/src/hermes/lib/VM/JSLib/JSLibInternal.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright (c) Meta Platforms, Inc. and affiliates.  | 
3  |  |  *  | 
4  |  |  * This source code is licensed under the MIT license found in the  | 
5  |  |  * LICENSE file in the root directory of this source tree.  | 
6  |  |  */  | 
7  |  |  | 
8  |  | #include "JSLibInternal.h"  | 
9  |  |  | 
10  |  | #include "hermes/Regex/Executor.h"  | 
11  |  | #include "hermes/Regex/Regex.h"  | 
12  |  | #include "hermes/Regex/RegexTraits.h"  | 
13  |  | #include "hermes/VM/PropertyAccessor.h"  | 
14  |  | #include "hermes/VM/Runtime.h"  | 
15  |  | #include "hermes/VM/StringBuilder.h"  | 
16  |  | #include "hermes/VM/StringPrimitive.h"  | 
17  |  | #include "hermes/VM/StringView.h"  | 
18  |  | #pragma GCC diagnostic push  | 
19  |  |  | 
20  |  | #ifdef HERMES_COMPILER_SUPPORTS_WSHORTEN_64_TO_32  | 
21  |  | #pragma GCC diagnostic ignored "-Wshorten-64-to-32"  | 
22  |  | #endif  | 
23  |  | namespace hermes { | 
24  |  | namespace vm { | 
25  |  |  | 
26  |  | Handle<NativeConstructor> defineSystemConstructor(  | 
27  |  |     Runtime &runtime,  | 
28  |  |     SymbolID name,  | 
29  |  |     NativeFunctionPtr nativeFunctionPtr,  | 
30  |  |     Handle<JSObject> prototypeObjectHandle,  | 
31  |  |     Handle<JSObject> constructorProtoObjectHandle,  | 
32  |  |     unsigned paramCount,  | 
33  |  |     NativeConstructor::CreatorFunction *creator,  | 
34  | 6.24k  |     CellKind targetKind) { | 
35  | 6.24k  |   auto constructor = runtime.makeHandle(NativeConstructor::create(  | 
36  | 6.24k  |       runtime,  | 
37  | 6.24k  |       constructorProtoObjectHandle,  | 
38  | 6.24k  |       nullptr,  | 
39  | 6.24k  |       nativeFunctionPtr,  | 
40  | 6.24k  |       paramCount,  | 
41  | 6.24k  |       creator,  | 
42  | 6.24k  |       targetKind));  | 
43  |  |  | 
44  | 6.24k  |   auto st = Callable::defineNameLengthAndPrototype(  | 
45  | 6.24k  |       constructor,  | 
46  | 6.24k  |       runtime,  | 
47  | 6.24k  |       name,  | 
48  | 6.24k  |       paramCount,  | 
49  | 6.24k  |       prototypeObjectHandle,  | 
50  | 6.24k  |       Callable::WritablePrototype::No,  | 
51  | 6.24k  |       false);  | 
52  | 6.24k  |   (void)st;  | 
53  | 6.24k  |   assert(  | 
54  | 6.24k  |       st != ExecutionStatus::EXCEPTION && "defineLengthAndPrototype() failed");  | 
55  |  |  | 
56  |  |   // Define the global.  | 
57  | 6.24k  |   DefinePropertyFlags dpf = DefinePropertyFlags::getNewNonEnumerableFlags();  | 
58  |  |  | 
59  | 6.24k  |   auto res = JSObject::defineOwnProperty(  | 
60  | 6.24k  |       runtime.getGlobal(), runtime, name, dpf, constructor);  | 
61  | 6.24k  |   assert(  | 
62  | 6.24k  |       res != ExecutionStatus::EXCEPTION && *res &&  | 
63  | 6.24k  |       "defineOwnProperty() failed");  | 
64  | 6.24k  |   (void)res;  | 
65  |  |  | 
66  | 6.24k  |   return constructor;  | 
67  | 6.24k  | }  | 
68  |  |  | 
69  |  | CallResult<HermesValue> defineMethod(  | 
70  |  |     Runtime &runtime,  | 
71  |  |     Handle<JSObject> objectHandle,  | 
72  |  |     SymbolID propertyName,  | 
73  |  |     SymbolID methodName,  | 
74  |  |     void *context,  | 
75  |  |     NativeFunctionPtr nativeFunctionPtr,  | 
76  |  |     unsigned paramCount,  | 
77  | 57.6k  |     DefinePropertyFlags dpf) { | 
78  | 57.6k  |   GCScope gcScope{runtime}; | 
79  |  |  | 
80  | 57.6k  |   auto method = NativeFunction::create(  | 
81  | 57.6k  |       runtime,  | 
82  | 57.6k  |       Handle<JSObject>::vmcast(&runtime.functionPrototype),  | 
83  | 57.6k  |       context,  | 
84  | 57.6k  |       nativeFunctionPtr,  | 
85  | 57.6k  |       methodName,  | 
86  | 57.6k  |       paramCount,  | 
87  | 57.6k  |       Runtime::makeNullHandle<JSObject>());  | 
88  |  |  | 
89  | 57.6k  |   auto res = JSObject::defineOwnProperty(  | 
90  | 57.6k  |       objectHandle, runtime, propertyName, dpf, method);  | 
91  | 57.6k  |   (void)res;  | 
92  | 57.6k  |   assert(  | 
93  | 57.6k  |       res != ExecutionStatus::EXCEPTION && *res &&  | 
94  | 57.6k  |       "defineOwnProperty() failed");  | 
95  |  |  | 
96  | 57.6k  |   return method.getHermesValue();  | 
97  | 57.6k  | }  | 
98  |  |  | 
99  |  | Handle<NativeConstructor> defineSystemConstructor(  | 
100  |  |     Runtime &runtime,  | 
101  |  |     SymbolID name,  | 
102  |  |     NativeFunctionPtr nativeFunctionPtr,  | 
103  |  |     Handle<JSObject> prototypeObjectHandle,  | 
104  |  |     unsigned paramCount,  | 
105  |  |     NativeConstructor::CreatorFunction *creator,  | 
106  | 3.04k  |     CellKind targetKind) { | 
107  | 3.04k  |   return defineSystemConstructor(  | 
108  | 3.04k  |       runtime,  | 
109  | 3.04k  |       name,  | 
110  | 3.04k  |       nativeFunctionPtr,  | 
111  | 3.04k  |       prototypeObjectHandle,  | 
112  | 3.04k  |       Handle<JSObject>::vmcast(&runtime.functionPrototype),  | 
113  | 3.04k  |       paramCount,  | 
114  | 3.04k  |       creator,  | 
115  | 3.04k  |       targetKind);  | 
116  | 3.04k  | }  | 
117  |  |  | 
118  |  | void defineMethod(  | 
119  |  |     Runtime &runtime,  | 
120  |  |     Handle<JSObject> objectHandle,  | 
121  |  |     SymbolID name,  | 
122  |  |     void *context,  | 
123  |  |     NativeFunctionPtr nativeFunctionPtr,  | 
124  | 53.9k  |     unsigned paramCount) { | 
125  | 53.9k  |   DefinePropertyFlags dpf = DefinePropertyFlags::getNewNonEnumerableFlags();  | 
126  | 53.9k  |   (void)defineMethod(  | 
127  | 53.9k  |       runtime, objectHandle, name, context, nativeFunctionPtr, paramCount, dpf);  | 
128  | 53.9k  | }  | 
129  |  |  | 
130  |  | void defineAccessor(  | 
131  |  |     Runtime &runtime,  | 
132  |  |     Handle<JSObject> objectHandle,  | 
133  |  |     SymbolID propertyName,  | 
134  |  |     SymbolID methodName,  | 
135  |  |     void *context,  | 
136  |  |     NativeFunctionPtr getterFunc,  | 
137  |  |     NativeFunctionPtr setterFunc,  | 
138  |  |     bool enumerable,  | 
139  | 7.04k  |     bool configurable) { | 
140  | 7.04k  |   assert(  | 
141  | 7.04k  |       (getterFunc || setterFunc) &&  | 
142  | 7.04k  |       "at least a getter or a setter must be specified");  | 
143  | 7.04k  |   ExecutionStatus status{}; | 
144  | 7.04k  |   (void)status;  | 
145  |  |  | 
146  | 7.04k  |   GCScope gcScope{runtime}; | 
147  |  |  | 
148  | 7.04k  |   StringView nameView =  | 
149  | 7.04k  |       runtime.getIdentifierTable().getStringView(runtime, methodName);  | 
150  | 7.04k  |   assert(nameView.isASCII() && "Only ASCII accessors are supported");  | 
151  |  |  | 
152  | 7.04k  |   MutableHandle<NativeFunction> getter{runtime}; | 
153  | 7.04k  |   if (getterFunc) { | 
154  |  |     // Set the name by prepending "get ".  | 
155  | 7.04k  |     llvh::SmallString<32> getterName{"get "}; | 
156  | 7.04k  |     llvh::raw_svector_ostream os{getterName}; | 
157  | 7.04k  |     os << nameView;  | 
158  |  |  | 
159  | 7.04k  |     auto strRes = runtime.ignoreAllocationFailure(  | 
160  | 7.04k  |         StringPrimitive::create(runtime, getterName));  | 
161  | 7.04k  |     SymbolID getterFuncName =  | 
162  | 7.04k  |         runtime  | 
163  | 7.04k  |             .ignoreAllocationFailure(  | 
164  | 7.04k  |                 runtime.getIdentifierTable().getSymbolHandleFromPrimitive(  | 
165  | 7.04k  |                     runtime,  | 
166  | 7.04k  |                     createPseudoHandle(vmcast<StringPrimitive>(strRes))))  | 
167  | 7.04k  |             .get();  | 
168  |  |  | 
169  | 7.04k  |     auto funcRes = NativeFunction::create(  | 
170  | 7.04k  |         runtime,  | 
171  | 7.04k  |         Handle<JSObject>::vmcast(&runtime.functionPrototype),  | 
172  | 7.04k  |         context,  | 
173  | 7.04k  |         getterFunc,  | 
174  | 7.04k  |         getterFuncName,  | 
175  | 7.04k  |         0,  | 
176  | 7.04k  |         Runtime::makeNullHandle<JSObject>());  | 
177  | 7.04k  |     getter = funcRes.get();  | 
178  | 7.04k  |   }  | 
179  |  |  | 
180  | 7.04k  |   MutableHandle<NativeFunction> setter{runtime}; | 
181  | 7.04k  |   if (setterFunc) { | 
182  |  |     // Set the name by prepending "set ".  | 
183  | 160  |     llvh::SmallString<32> setterName{"set "}; | 
184  | 160  |     llvh::raw_svector_ostream os{setterName}; | 
185  | 160  |     os << nameView;  | 
186  |  |  | 
187  | 160  |     auto strRes = runtime.ignoreAllocationFailure(  | 
188  | 160  |         StringPrimitive::create(runtime, setterName));  | 
189  | 160  |     SymbolID setterFuncName =  | 
190  | 160  |         runtime  | 
191  | 160  |             .ignoreAllocationFailure(  | 
192  | 160  |                 runtime.getIdentifierTable().getSymbolHandleFromPrimitive(  | 
193  | 160  |                     runtime,  | 
194  | 160  |                     createPseudoHandle(vmcast<StringPrimitive>(strRes))))  | 
195  | 160  |             .get();  | 
196  |  |  | 
197  | 160  |     auto funcRes = NativeFunction::create(  | 
198  | 160  |         runtime,  | 
199  | 160  |         Handle<JSObject>::vmcast(&runtime.functionPrototype),  | 
200  | 160  |         context,  | 
201  | 160  |         setterFunc,  | 
202  | 160  |         setterFuncName,  | 
203  | 160  |         1,  | 
204  | 160  |         Runtime::makeNullHandle<JSObject>());  | 
205  | 160  |     setter = funcRes.get();  | 
206  | 160  |   }  | 
207  |  |  | 
208  | 7.04k  |   auto accessor = runtime.makeHandle<PropertyAccessor>(  | 
209  | 7.04k  |       PropertyAccessor::create(runtime, getter, setter));  | 
210  |  |  | 
211  | 7.04k  |   DefinePropertyFlags dpf{}; | 
212  | 7.04k  |   dpf.setEnumerable = 1;  | 
213  | 7.04k  |   dpf.setConfigurable = 1;  | 
214  | 7.04k  |   dpf.setGetter = 1;  | 
215  | 7.04k  |   dpf.setSetter = 1;  | 
216  | 7.04k  |   dpf.enumerable = enumerable;  | 
217  | 7.04k  |   dpf.configurable = configurable;  | 
218  |  |  | 
219  | 7.04k  |   auto res = JSObject::defineOwnProperty(  | 
220  | 7.04k  |       objectHandle, runtime, propertyName, dpf, accessor);  | 
221  | 7.04k  |   (void)res;  | 
222  | 7.04k  |   assert(  | 
223  | 7.04k  |       res != ExecutionStatus::EXCEPTION && *res &&  | 
224  | 7.04k  |       "defineOwnProperty() failed");  | 
225  | 7.04k  | }  | 
226  |  |  | 
227  |  | void defineProperty(  | 
228  |  |     Runtime &runtime,  | 
229  |  |     Handle<JSObject> objectHandle,  | 
230  |  |     SymbolID name,  | 
231  |  |     Handle<> value,  | 
232  | 13.6k  |     DefinePropertyFlags dpf) { | 
233  | 13.6k  |   auto res = JSObject::defineOwnProperty(  | 
234  | 13.6k  |       objectHandle, runtime, name, dpf, value, PropOpFlags());  | 
235  | 13.6k  |   (void)res;  | 
236  | 13.6k  |   assert(  | 
237  | 13.6k  |       res != ExecutionStatus::EXCEPTION && *res &&  | 
238  | 13.6k  |       "defineOwnProperty() failed");  | 
239  | 13.6k  | }  | 
240  |  |  | 
241  |  | void defineProperty(  | 
242  |  |     Runtime &runtime,  | 
243  |  |     Handle<JSObject> objectHandle,  | 
244  |  |     SymbolID name,  | 
245  | 4.48k  |     Handle<> value) { | 
246  | 4.48k  |   DefinePropertyFlags dpf = DefinePropertyFlags::getNewNonEnumerableFlags();  | 
247  |  |  | 
248  | 4.48k  |   return defineProperty(runtime, objectHandle, name, value, dpf);  | 
249  | 4.48k  | }  | 
250  |  |  | 
251  |  | ExecutionStatus iteratorCloseAndRethrow(  | 
252  |  |     Runtime &runtime,  | 
253  | 0  |     Handle<JSObject> iterator) { | 
254  | 0  |   auto completion = runtime.makeHandle(runtime.getThrownValue());  | 
255  | 0  |   if (isUncatchableError(completion.getHermesValue())) { | 
256  |  |     // If an uncatchable exception was raised, do not swallow it, but instead  | 
257  |  |     // propagate it.  | 
258  | 0  |     return ExecutionStatus::EXCEPTION;  | 
259  | 0  |   }  | 
260  | 0  |   runtime.clearThrownValue();  | 
261  | 0  |   auto status = iteratorClose(runtime, iterator, completion);  | 
262  | 0  |   (void)status;  | 
263  | 0  |   assert(  | 
264  | 0  |       status == ExecutionStatus::EXCEPTION && "exception swallowed mistakenly");  | 
265  | 0  |   return ExecutionStatus::EXCEPTION;  | 
266  | 0  | }  | 
267  |  |  | 
268  | 1  | static std::vector<uint8_t> getReturnThisRegexBytecode() { | 
269  | 1  |   const char16_t *returnThisRE = uR"X(^\s*return[ \t]+this\s*;?\s*$)X";  | 
270  | 1  |   return regex::Regex<regex::UTF16RegexTraits>(returnThisRE).compile();  | 
271  | 1  | }  | 
272  |  |  | 
273  | 86  | static bool isReturnThis(Handle<StringPrimitive> str, Runtime &runtime) { | 
274  |  |   // Fast check for minimal version.  | 
275  | 86  |   { | 
276  | 86  |     auto minimal = runtime.getPredefinedString(Predefined::returnThis);  | 
277  | 86  |     if (str->equals(minimal)) { | 
278  | 0  |       return true;  | 
279  | 0  |     }  | 
280  | 86  |   }  | 
281  |  |   // Regex match for variants.  | 
282  | 86  |   auto input = StringPrimitive::createStringView(runtime, str);  | 
283  | 86  |   static auto bytecode = getReturnThisRegexBytecode();  | 
284  | 86  |   auto result = regex::MatchRuntimeResult::NoMatch;  | 
285  | 86  |   if (input.isASCII()) { | 
286  | 0  |     const char *begin = input.castToCharPtr();  | 
287  | 0  |     result = regex::searchWithBytecode(  | 
288  | 0  |         bytecode,  | 
289  | 0  |         begin,  | 
290  | 0  |         0,  | 
291  | 0  |         input.length(),  | 
292  | 0  |         nullptr,  | 
293  | 0  |         regex::constants::matchDefault | regex::constants::matchInputAllAscii,  | 
294  | 0  |         runtime.getOverflowGuardForRegex());  | 
295  | 86  |   } else { | 
296  | 86  |     const char16_t *begin = input.castToChar16Ptr();  | 
297  | 86  |     result = regex::searchWithBytecode(  | 
298  | 86  |         bytecode,  | 
299  | 86  |         begin,  | 
300  | 86  |         0,  | 
301  | 86  |         input.length(),  | 
302  | 86  |         nullptr,  | 
303  | 86  |         regex::constants::matchDefault,  | 
304  | 86  |         runtime.getOverflowGuardForRegex());  | 
305  | 86  |   }  | 
306  | 86  |   return result == regex::MatchRuntimeResult::Match;  | 
307  | 86  | }  | 
308  |  |  | 
309  |  | CallResult<HermesValue> createDynamicFunction(  | 
310  |  |     Runtime &runtime,  | 
311  |  |     NativeArgs args,  | 
312  | 87  |     DynamicFunctionKind kind) { | 
313  | 87  |   GCScope gcScope(runtime);  | 
314  |  |  | 
315  |  |   // Number of arguments supplied to Function().  | 
316  | 87  |   uint32_t argCount = args.getArgCount();  | 
317  |  |  | 
318  |  |   // Number of parameters in the resultant function.  | 
319  | 87  |   uint32_t paramCount = argCount > 0 ? argCount - 1 : 0;  | 
320  |  |  | 
321  |  |   // List of the parameter strings for the resultant function..  | 
322  | 87  |   auto arrRes = JSArray::create(runtime, paramCount, paramCount);  | 
323  | 87  |   if (LLVM_UNLIKELY(arrRes == ExecutionStatus::EXCEPTION)) { | 
324  | 0  |     return ExecutionStatus::EXCEPTION;  | 
325  | 0  |   }  | 
326  | 87  |   auto params = *arrRes;  | 
327  |  |  | 
328  |  |   // Body of the resultant function.  | 
329  | 87  |   MutableHandle<StringPrimitive> body{runtime}; | 
330  |  |  | 
331  |  |   // String length of the function in its entirety.  | 
332  |  |   // Account for commas in the argument list initially.  | 
333  |  |   // If at least two arguments to the function (3 in total), there's a comma.  | 
334  | 87  |   SafeUInt32 size{paramCount > 0 ? paramCount - 1 : 0}; | 
335  |  |  | 
336  |  |   // es2020 19.2.1.1.1 Runtime Semantics: CreateDynamicFunction: If  | 
337  |  |   // NewTarget is given, such as with Reflect.construct, use  | 
338  |  |   // NewParent.prototype as the parent.  The prototype on NewParent  | 
339  |  |   // has already been looked up to use as the parent of 'this', so  | 
340  |  |   // instead of looking it up again, just use this's parent.  If  | 
341  |  |   // NewTarget isn't given, fall back to a default.  | 
342  | 87  |   MutableHandle<JSObject> fallbackProto{runtime}; | 
343  | 87  |   switch (kind) { | 
344  | 87  |     case DynamicFunctionKind::Normal:  | 
345  | 87  |       fallbackProto = Handle<JSObject>::vmcast(&runtime.functionPrototype);  | 
346  | 87  |       break;  | 
347  | 0  |     case DynamicFunctionKind::Generator:  | 
348  | 0  |       fallbackProto =  | 
349  | 0  |           Handle<JSObject>::vmcast(&runtime.generatorFunctionPrototype);  | 
350  | 0  |       break;  | 
351  | 0  |     case DynamicFunctionKind::Async:  | 
352  | 0  |       fallbackProto = Handle<JSObject>::vmcast(&runtime.asyncFunctionPrototype);  | 
353  | 0  |       break;  | 
354  | 0  |     default:  | 
355  | 0  |       llvm_unreachable("unknown kind for CreateDynamicFunction."); | 
356  | 87  |   }  | 
357  |  |  | 
358  | 87  |   Handle<JSObject> parent = !args.getNewTarget().isUndefined()  | 
359  | 87  |       ? runtime.makeHandle(  | 
360  | 0  |             vmcast<JSObject>(args.getThisArg())->getParent(runtime))  | 
361  | 87  |       : fallbackProto;  | 
362  |  |  | 
363  | 87  |   if (argCount == 0) { | 
364  |  |     // No arguments, just set body to be the empty string.  | 
365  | 0  |     body = runtime.getPredefinedString(Predefined::emptyString);  | 
366  | 87  |   } else { | 
367  |  |     // If there's arguments, store the parameters and the provided body.  | 
368  | 87  |     auto marker = gcScope.createMarker();  | 
369  | 13.3k  |     for (uint32_t i = 0; i < paramCount; ++i) { | 
370  | 13.2k  |       gcScope.flushToMarker(marker);  | 
371  | 13.2k  |       auto strRes = toString_RJS(runtime, args.getArgHandle(i));  | 
372  | 13.2k  |       if (LLVM_UNLIKELY(strRes == ExecutionStatus::EXCEPTION)) { | 
373  | 0  |         return ExecutionStatus::EXCEPTION;  | 
374  | 0  |       }  | 
375  | 13.2k  |       auto param = runtime.makeHandle(std::move(*strRes));  | 
376  | 13.2k  |       JSArray::setElementAt(params, runtime, i, param);  | 
377  | 13.2k  |       size.add(param->getStringLength());  | 
378  | 13.2k  |     }  | 
379  |  |  | 
380  |  |     // Last parameter is the body.  | 
381  | 87  |     auto strRes = toString_RJS(runtime, args.getArgHandle(paramCount));  | 
382  | 87  |     if (strRes == ExecutionStatus::EXCEPTION) { | 
383  | 0  |       return ExecutionStatus::EXCEPTION;  | 
384  | 0  |     }  | 
385  | 87  |     body = strRes->get();  | 
386  | 87  |     size.add(body->getStringLength());  | 
387  |  |  | 
388  | 87  |     if (kind == DynamicFunctionKind::Normal && argCount == 1 &&  | 
389  | 87  |         isReturnThis(body, runtime)) { | 
390  |  |       // If this raises an exception, we still return immediately.  | 
391  | 0  |       return JSFunction::create(  | 
392  | 0  |                  runtime,  | 
393  | 0  |                  runtime.makeHandle(Domain::create(runtime)),  | 
394  | 0  |                  parent,  | 
395  | 0  |                  Handle<Environment>(runtime, nullptr),  | 
396  | 0  |                  runtime.getReturnThisCodeBlock())  | 
397  | 0  |           .getHermesValue();  | 
398  | 0  |     }  | 
399  | 87  |   }  | 
400  |  |  | 
401  |  |   // Constant parts of the function.  | 
402  | 87  |   ASCIIRef functionHeader;  | 
403  | 87  |   switch (kind) { | 
404  | 87  |     case DynamicFunctionKind::Normal:  | 
405  | 87  |       functionHeader = createASCIIRef("(function ("); | 
406  | 87  |       break;  | 
407  | 0  |     case DynamicFunctionKind::Generator:  | 
408  | 0  |       functionHeader = createASCIIRef("(function*("); | 
409  | 0  |       break;  | 
410  | 0  |     case DynamicFunctionKind::Async:  | 
411  | 0  |       functionHeader = createASCIIRef("(async function ("); | 
412  | 0  |       break;  | 
413  | 0  |     default:  | 
414  | 0  |       llvm_unreachable("unknown kind for CreateDynamicFunction."); | 
415  | 87  |   };  | 
416  | 87  |   size.add(functionHeader.size());  | 
417  |  |  | 
418  | 87  |   auto bodyHeader = createASCIIRef("){"); | 
419  | 87  |   size.add(bodyHeader.size());  | 
420  |  |  | 
421  |  |   // Note: add a \n before the closing '}' in case the  | 
422  |  |   // function body ends with a line comment.  | 
423  | 87  |   auto functionFooter = createASCIIRef("\n})"); | 
424  | 87  |   size.add(functionFooter.size());  | 
425  |  |  | 
426  | 87  |   auto separator = createASCIIRef(","); | 
427  |  |  | 
428  | 87  |   auto builder = StringBuilder::createStringBuilder(runtime, size);  | 
429  | 87  |   if (builder == ExecutionStatus::EXCEPTION) { | 
430  | 0  |     return ExecutionStatus::EXCEPTION;  | 
431  | 0  |   }  | 
432  | 87  |   builder->appendASCIIRef(functionHeader);  | 
433  | 87  |   MutableHandle<StringPrimitive> element{runtime}; | 
434  | 13.3k  |   for (uint32_t i = 0; i < paramCount; ++i) { | 
435  |  |     // Copy params into str.  | 
436  | 13.2k  |     element = params->at(runtime, i).getString(runtime);  | 
437  | 13.2k  |     builder->appendStringPrim(element);  | 
438  | 13.2k  |     if (i < paramCount - 1) { | 
439  |  |       // If there's more params left to put, need to add a comma.  | 
440  |  |       // We wouldn't have entered the loop if paramCount == 0,  | 
441  |  |       // so there's no overflow here.  | 
442  | 13.2k  |       builder->appendASCIIRef(separator);  | 
443  | 13.2k  |     }  | 
444  | 13.2k  |   }  | 
445  | 87  |   builder->appendASCIIRef(bodyHeader);  | 
446  | 87  |   builder->appendStringPrim(body);  | 
447  | 87  |   builder->appendASCIIRef(functionFooter);  | 
448  |  |  | 
449  | 87  |   auto evalRes =  | 
450  | 87  |       directEval(runtime, builder->getStringPrimitive(), {}, false, true); | 
451  | 87  |   if (evalRes == ExecutionStatus::EXCEPTION) { | 
452  | 5  |     return ExecutionStatus::EXCEPTION;  | 
453  | 5  |   }  | 
454  |  |  | 
455  | 82  |   Handle<JSFunction> function =  | 
456  | 82  |       runtime.makeHandle(vmcast<JSFunction>(evalRes.getValue()));  | 
457  |  |  | 
458  | 82  |   DefinePropertyFlags dpf = DefinePropertyFlags::getDefaultNewPropertyFlags();  | 
459  | 82  |   dpf.enumerable = 0;  | 
460  | 82  |   dpf.writable = 0;  | 
461  |  |  | 
462  |  |   // Define the `name` correctly.  | 
463  | 82  |   if (JSObject::defineOwnProperty(  | 
464  | 82  |           function,  | 
465  | 82  |           runtime,  | 
466  | 82  |           Predefined::getSymbolID(Predefined::name),  | 
467  | 82  |           dpf,  | 
468  | 82  |           runtime.makeHandle(runtime.getStringPrimFromSymbolID(  | 
469  | 82  |               Predefined::getSymbolID(Predefined::anonymous)))) ==  | 
470  | 82  |       ExecutionStatus::EXCEPTION) { | 
471  | 0  |     return ExecutionStatus::EXCEPTION;  | 
472  | 0  |   }  | 
473  |  |  | 
474  |  |   // Set the parent.  This could be done by threading the argument  | 
475  |  |   // through to Runtime::runBytecode where the object is actually  | 
476  |  |   // created, but this is the only place we need to do this so it  | 
477  |  |   // keeps the code simpler.  | 
478  | 82  |   CallResult<bool> parentRes = JSObject::setParent(*function, runtime, *parent);  | 
479  | 82  |   if (LLVM_UNLIKELY(parentRes == ExecutionStatus::EXCEPTION)) { | 
480  | 0  |     return ExecutionStatus::EXCEPTION;  | 
481  | 0  |   }  | 
482  | 82  |   assert(  | 
483  | 82  |       *parentRes && "Setting prototype on new dynamic function returned false");  | 
484  |  |  | 
485  | 82  |   return function.getHermesValue();  | 
486  | 82  | }  | 
487  |  |  | 
488  |  | } // namespace vm  | 
489  |  | } // namespace hermes  |