/src/hermes/lib/VM/JSLib/GlobalObject.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 | | //===----------------------------------------------------------------------===// |
9 | | /// \file |
10 | | /// Initialize the global object ES5.1 15.1 |
11 | | //===----------------------------------------------------------------------===// |
12 | | #include "hermes/Platform/Intl/PlatformIntl.h" |
13 | | #include "hermes/VM/JSArrayBuffer.h" |
14 | | #include "hermes/VM/JSDataView.h" |
15 | | #include "hermes/VM/JSLib.h" |
16 | | #include "hermes/VM/JSTypedArray.h" |
17 | | #include "hermes/VM/Operations.h" |
18 | | #include "hermes/VM/PrimitiveBox.h" |
19 | | #include "hermes/VM/PropertyAccessor.h" |
20 | | #include "hermes/VM/StringView.h" |
21 | | |
22 | | #include "dtoa/dtoa.h" |
23 | | |
24 | | #include "JSLibInternal.h" |
25 | | |
26 | | namespace hermes { |
27 | | namespace vm { |
28 | | |
29 | | /// ES5.1 15.1.2.4 |
30 | 0 | CallResult<HermesValue> isNaN(void *, Runtime &runtime, NativeArgs args) { |
31 | 0 | auto res = toNumber_RJS(runtime, args.getArgHandle(0)); |
32 | 0 | if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) { |
33 | 0 | return ExecutionStatus::EXCEPTION; |
34 | 0 | } |
35 | 0 | return HermesValue::encodeBoolValue(std::isnan(res->getNumber())); |
36 | 0 | } |
37 | | |
38 | | /// ES5.1 15.1.2.5 |
39 | 0 | CallResult<HermesValue> isFinite(void *, Runtime &runtime, NativeArgs args) { |
40 | 0 | auto res = toNumber_RJS(runtime, args.getArgHandle(0)); |
41 | 0 | if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) { |
42 | 0 | return ExecutionStatus::EXCEPTION; |
43 | 0 | } |
44 | 0 | auto value = res->getDouble(); |
45 | 0 | return HermesValue::encodeBoolValue(std::isfinite(value)); |
46 | 0 | } |
47 | | |
48 | | /// Needed to construct Function.prototype. |
49 | 0 | CallResult<HermesValue> emptyFunction(void *, Runtime &, NativeArgs) { |
50 | 0 | return HermesValue::encodeUndefinedValue(); |
51 | 0 | } |
52 | | |
53 | | /// Given a character \p c in radix \p radix, checks if it's valid. |
54 | 0 | static bool isValidRadixChar(char16_t c, int radix) { |
55 | | // c is 0..9. |
56 | 0 | if (c >= '0' && c <= '9') { |
57 | 0 | return (radix >= 10 || c < '0' + radix); |
58 | 0 | } |
59 | 0 | c = letterToLower(c); |
60 | 0 | return (radix > 10 && c >= 'a' && c < 'a' + radix - 10); |
61 | 0 | } |
62 | | |
63 | | /// ES5.1 15.1.2.2 parseInt(string, radix) |
64 | 0 | CallResult<HermesValue> parseInt(void *, Runtime &runtime, NativeArgs args) { |
65 | | // toString(arg0). |
66 | 0 | auto strRes = toString_RJS(runtime, args.getArgHandle(0)); |
67 | 0 | if (LLVM_UNLIKELY(strRes == ExecutionStatus::EXCEPTION)) { |
68 | 0 | return ExecutionStatus::EXCEPTION; |
69 | 0 | } |
70 | 0 | auto str = runtime.makeHandle(std::move(*strRes)); |
71 | |
|
72 | 0 | int radix = 10; |
73 | 0 | bool stripPrefix = true; |
74 | | // If radix (arg1) is present and not undefined, toInt32_RJS(arg1). |
75 | 0 | if (args.getArgCount() > 1 && !args.getArg(1).isUndefined()) { |
76 | 0 | auto intRes = toInt32_RJS(runtime, args.getArgHandle(1)); |
77 | 0 | if (LLVM_UNLIKELY(intRes == ExecutionStatus::EXCEPTION)) { |
78 | 0 | return ExecutionStatus::EXCEPTION; |
79 | 0 | } |
80 | 0 | radix = static_cast<int>(intRes->getNumber()); |
81 | 0 | if (radix == 0) { |
82 | 0 | radix = 10; |
83 | 0 | } else if (radix < 2 || radix > 36) { |
84 | 0 | return HermesValue::encodeNaNValue(); |
85 | 0 | } else if (radix != 16) { |
86 | 0 | stripPrefix = false; |
87 | 0 | } |
88 | 0 | } |
89 | | |
90 | 0 | auto strView = StringPrimitive::createStringView(runtime, str); |
91 | 0 | auto begin = strView.begin(); |
92 | 0 | auto end = strView.end(); |
93 | | |
94 | | // Remove leading whitespaces. |
95 | 0 | while (begin != end && |
96 | 0 | (isWhiteSpaceChar(*begin) || isLineTerminatorChar(*begin))) { |
97 | 0 | ++begin; |
98 | 0 | } |
99 | | |
100 | | // Process sign. |
101 | 0 | int sign = 1; |
102 | 0 | if (begin != end && (*begin == u'+' || *begin == u'-')) { |
103 | 0 | if (*begin == u'-') { |
104 | 0 | sign = -1; |
105 | 0 | } |
106 | 0 | ++begin; |
107 | 0 | } |
108 | | |
109 | | // Strip 0x or 0X for 16-radix number. |
110 | 0 | if (stripPrefix && begin != end) { |
111 | 0 | if (*begin == u'0') { |
112 | 0 | ++begin; |
113 | 0 | if (begin != end && letterToLower(*begin) == u'x') { |
114 | 0 | ++begin; |
115 | 0 | radix = 16; |
116 | 0 | } else { |
117 | 0 | --begin; |
118 | 0 | } |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | | // Find the longest prefix that's still a valid int. |
123 | 0 | auto realEnd = begin; |
124 | 0 | for (; realEnd != end && isValidRadixChar(*realEnd, radix); ++realEnd) { |
125 | 0 | } |
126 | 0 | if (realEnd == begin) { |
127 | | // Return NaN if string has no digits. |
128 | 0 | return HermesValue::encodeNaNValue(); |
129 | 0 | } |
130 | | |
131 | 0 | return HermesValue::encodeUntrustedNumberValue( |
132 | 0 | sign * parseIntWithRadix(strView.slice(begin, realEnd), radix)); |
133 | 0 | } |
134 | | |
135 | | // Check if str1 is a prefix of str2. |
136 | 0 | static bool isPrefix(StringView str1, StringView str2) { |
137 | 0 | if (str1.length() > str2.length()) { |
138 | 0 | return false; |
139 | 0 | } |
140 | 0 | for (auto first1 = str1.begin(), last1 = str1.end(), first2 = str2.begin(); |
141 | 0 | first1 != last1; |
142 | 0 | ++first1, ++first2) { |
143 | 0 | if (*first1 != *first2) { |
144 | 0 | return false; |
145 | 0 | } |
146 | 0 | } |
147 | 0 | return true; |
148 | 0 | } |
149 | | |
150 | | /// ES5.1 15.1.2.3 parseFloat(string) |
151 | 0 | CallResult<HermesValue> parseFloat(void *, Runtime &runtime, NativeArgs args) { |
152 | | // toString(arg0). |
153 | 0 | auto res = toString_RJS(runtime, args.getArgHandle(0)); |
154 | 0 | if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) { |
155 | 0 | return ExecutionStatus::EXCEPTION; |
156 | 0 | } |
157 | | |
158 | 0 | auto strHandle = runtime.makeHandle(std::move(*res)); |
159 | 0 | auto origStr = StringPrimitive::createStringView(runtime, strHandle); |
160 | |
|
161 | 0 | auto &idTable = runtime.getIdentifierTable(); |
162 | | |
163 | | // Trim leading whitespaces. |
164 | 0 | auto begin = origStr.begin(); |
165 | 0 | auto end = origStr.end(); |
166 | |
|
167 | 0 | while (begin != end && |
168 | 0 | (isWhiteSpaceChar(*begin) || isLineTerminatorChar(*begin))) { |
169 | 0 | ++begin; |
170 | 0 | } |
171 | 0 | StringView str16 = origStr.slice(begin, end); |
172 | | |
173 | | // Check for special values. |
174 | | // parseFloat allows for partial match, hence we have to check for |
175 | | // substring. |
176 | 0 | if (LLVM_UNLIKELY(isPrefix( |
177 | 0 | idTable.getStringView( |
178 | 0 | runtime, Predefined::getSymbolID(Predefined::Infinity)), |
179 | 0 | str16))) { |
180 | 0 | return HermesValue::encodeUntrustedNumberValue( |
181 | 0 | std::numeric_limits<double>::infinity()); |
182 | 0 | } |
183 | 0 | if (LLVM_UNLIKELY(isPrefix( |
184 | 0 | idTable.getStringView( |
185 | 0 | runtime, Predefined::getSymbolID(Predefined::PositiveInfinity)), |
186 | 0 | str16))) { |
187 | 0 | return HermesValue::encodeUntrustedNumberValue( |
188 | 0 | std::numeric_limits<double>::infinity()); |
189 | 0 | } |
190 | 0 | if (LLVM_UNLIKELY(isPrefix( |
191 | 0 | idTable.getStringView( |
192 | 0 | runtime, Predefined::getSymbolID(Predefined::NegativeInfinity)), |
193 | 0 | str16))) { |
194 | 0 | return HermesValue::encodeUntrustedNumberValue( |
195 | 0 | -std::numeric_limits<double>::infinity()); |
196 | 0 | } |
197 | 0 | if (LLVM_UNLIKELY(isPrefix( |
198 | 0 | idTable.getStringView( |
199 | 0 | runtime, Predefined::getSymbolID(Predefined::NaN)), |
200 | 0 | str16))) { |
201 | 0 | return HermesValue::encodeNaNValue(); |
202 | 0 | } |
203 | | |
204 | | // Copy 16 bit chars into 8 bit chars as long as the character is |
205 | | // still a valid decimal number character. |
206 | 0 | auto len = str16.length(); |
207 | 0 | llvh::SmallVector<char, 32> str8(len + 1); |
208 | 0 | uint32_t i = 0; |
209 | 0 | for (auto c : str16) { |
210 | 0 | if ((c >= u'0' && c <= u'9') || c == '.' || letterToLower(c) == 'e' || |
211 | 0 | c == '+' || c == '-') { |
212 | 0 | str8[i] = static_cast<char>(c); |
213 | 0 | } else { |
214 | 0 | break; |
215 | 0 | } |
216 | 0 | ++i; |
217 | 0 | } |
218 | 0 | if (i == 0) { |
219 | | // Empty string. |
220 | 0 | return HermesValue::encodeNaNValue(); |
221 | 0 | } |
222 | | // Use hermes_g_strtod to figure out the longest prefix that's still valid. |
223 | | // hermes_g_strtod will try to convert the string to int for as long as it |
224 | | // can, and set endPtr to the last location where the prefix so far is still |
225 | | // a valid integer. |
226 | 0 | len = i; |
227 | 0 | str8[len] = '\0'; |
228 | 0 | char *endPtr; |
229 | 0 | ::hermes_g_strtod(str8.data(), &endPtr); |
230 | 0 | if (endPtr == str8.data()) { |
231 | | // Empty string. |
232 | 0 | return HermesValue::encodeNaNValue(); |
233 | 0 | } |
234 | | // Now we know the prefix untill endPtr is a valid int. |
235 | 0 | *endPtr = '\0'; |
236 | 0 | return HermesValue::encodeUntrustedNumberValue( |
237 | 0 | ::hermes_g_strtod(str8.data(), &endPtr)); |
238 | 0 | } |
239 | | |
240 | | /// Customized global function. gc() forces a GC collect. |
241 | 205 | CallResult<HermesValue> gc(void *, Runtime &runtime, NativeArgs) { |
242 | 205 | runtime.collect("forced"); |
243 | 205 | return HermesValue::encodeUndefinedValue(); |
244 | 205 | } |
245 | | |
246 | | CallResult<HermesValue> |
247 | 0 | throwTypeError(void *ctx, Runtime &runtime, NativeArgs) { |
248 | 0 | static const char *TypeErrorMessage[] = { |
249 | 0 | "Restricted in strict mode", |
250 | 0 | "Dynamic requires are not allowed after static resolution", |
251 | 0 | }; |
252 | |
|
253 | 0 | uint64_t kind = (uint64_t)ctx; |
254 | 0 | assert( |
255 | 0 | kind < (uint64_t)TypeErrorKind::NumKinds && |
256 | 0 | "[[ThrowTypeError]] wrong error kind passed as context"); |
257 | 0 | return runtime.raiseTypeError(TypeErrorMessage[kind]); |
258 | 0 | } |
259 | | |
260 | | // NOTE: when declaring more global symbols, don't forget to update |
261 | | // "Libhermes.h". |
262 | 105 | void initGlobalObject(Runtime &runtime, const JSLibFlags &jsLibFlags) { |
263 | 105 | GCScope gcScope{runtime, "initGlobalObject", 330}; |
264 | | |
265 | | // Not enumerable, not writable, not configurable. |
266 | 105 | DefinePropertyFlags constantDPF = |
267 | 105 | DefinePropertyFlags::getDefaultNewPropertyFlags(); |
268 | 105 | constantDPF.enumerable = 0; |
269 | 105 | constantDPF.writable = 0; |
270 | 105 | constantDPF.configurable = 0; |
271 | | |
272 | | // Not enumerable, but writable and configurable. |
273 | 105 | DefinePropertyFlags normalDPF = |
274 | 105 | DefinePropertyFlags::getNewNonEnumerableFlags(); |
275 | | |
276 | | // Not enumerable, not writable but configurable. |
277 | 105 | DefinePropertyFlags configurableOnlyPDF = |
278 | 105 | DefinePropertyFlags::getDefaultNewPropertyFlags(); |
279 | 105 | configurableOnlyPDF.enumerable = 0; |
280 | 105 | configurableOnlyPDF.writable = 0; |
281 | | |
282 | | /// Clear the configurable flag. |
283 | 105 | DefinePropertyFlags clearConfigurableDPF{}; |
284 | 105 | clearConfigurableDPF.setConfigurable = 1; |
285 | 105 | clearConfigurableDPF.configurable = 0; |
286 | | |
287 | | // Define a function on the global object with name \p name. |
288 | | // Allocates a NativeObject and puts it in the global object. |
289 | 105 | auto defineGlobalFunc = |
290 | 1.36k | [&](SymbolID name, NativeFunctionPtr functionPtr, unsigned paramCount) { |
291 | 1.36k | gcScope.clearAllHandles(); |
292 | | |
293 | 1.36k | auto func = NativeFunction::createWithoutPrototype( |
294 | 1.36k | runtime, nullptr, functionPtr, name, paramCount); |
295 | 1.36k | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
296 | 1.36k | runtime.getGlobal(), runtime, name, normalDPF, func)); |
297 | 1.36k | return func; |
298 | 1.36k | }; |
299 | | |
300 | | // 15.1.1.1 NaN. |
301 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
302 | 105 | runtime.getGlobal(), |
303 | 105 | runtime, |
304 | 105 | Predefined::getSymbolID(Predefined::NaN), |
305 | 105 | constantDPF, |
306 | 105 | runtime.makeHandle(HermesValue::encodeNaNValue()))); |
307 | | |
308 | | // 15.1.1.2 Infinity. |
309 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
310 | 105 | runtime.getGlobal(), |
311 | 105 | runtime, |
312 | 105 | Predefined::getSymbolID(Predefined::Infinity), |
313 | 105 | constantDPF, |
314 | 105 | runtime.makeHandle(HermesValue::encodeUntrustedNumberValue( |
315 | 105 | std::numeric_limits<double>::infinity())))); |
316 | | |
317 | | // 15.1.1.2 undefined. |
318 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
319 | 105 | runtime.getGlobal(), |
320 | 105 | runtime, |
321 | 105 | Predefined::getSymbolID(Predefined::undefined), |
322 | 105 | constantDPF, |
323 | 105 | runtime.makeHandle(HermesValue::encodeUndefinedValue()))); |
324 | | |
325 | | // "Forward declaration" of Object.prototype. Its properties will be populated |
326 | | // later. |
327 | | |
328 | 105 | runtime.objectPrototype = |
329 | 105 | JSObject::create(runtime, Runtime::makeNullHandle<JSObject>()) |
330 | 105 | .getHermesValue(); |
331 | 105 | runtime.objectPrototypeRawPtr = vmcast<JSObject>(runtime.objectPrototype); |
332 | | |
333 | | // "Forward declaration" of Error.prototype. Its properties will be populated |
334 | | // later. |
335 | 105 | runtime.ErrorPrototype = JSObject::create(runtime).getHermesValue(); |
336 | | |
337 | | // "Forward declaration" of the prototype for native error types. Their |
338 | | // properties will be populated later. |
339 | 105 | #define NATIVE_ERROR_TYPE(name) \ |
340 | 945 | runtime.name##Prototype = \ |
341 | 945 | JSObject::create( \ |
342 | 945 | runtime, Handle<JSObject>::vmcast(&runtime.ErrorPrototype)) \ |
343 | 945 | .getHermesValue(); |
344 | 105 | #define AGGREGATE_ERROR_TYPE(name) NATIVE_ERROR_TYPE(name) |
345 | 105 | #include "hermes/FrontEndDefs/NativeErrorTypes.def" |
346 | | |
347 | | // "Forward declaration" of the internal CallSite prototype. Its properties |
348 | | // will be populated later. |
349 | 105 | runtime.callSitePrototype = |
350 | 105 | JSObject::create( |
351 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.objectPrototype)) |
352 | 105 | .getHermesValue(); |
353 | | |
354 | | // "Forward declaration" of Function.prototype. Its properties will be |
355 | | // populated later. |
356 | 105 | Handle<NativeFunction> funcRes = NativeFunction::create( |
357 | 105 | runtime, |
358 | 105 | Handle<JSObject>::vmcast(&runtime.objectPrototype), |
359 | 105 | nullptr, |
360 | 105 | emptyFunction, |
361 | 105 | Predefined::getSymbolID(Predefined::emptyString), |
362 | 105 | 0, |
363 | 105 | Runtime::makeNullHandle<JSObject>()); |
364 | 105 | runtime.functionPrototype = funcRes.getHermesValue(); |
365 | 105 | runtime.functionPrototypeRawPtr = funcRes.get(); |
366 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
367 | 105 | Handle<JSObject>::vmcast(&runtime.functionPrototype), |
368 | 105 | runtime, |
369 | 105 | Predefined::getSymbolID(Predefined::length), |
370 | 105 | configurableOnlyPDF, |
371 | 105 | Runtime::getZeroValue())); |
372 | | |
373 | | // [[ThrowTypeError]]. |
374 | 105 | auto throwTypeErrorFunction = NativeFunction::create( |
375 | 105 | runtime, |
376 | 105 | Handle<JSObject>::vmcast(&runtime.functionPrototype), |
377 | 105 | (void *)TypeErrorKind::NonStrictOnly, |
378 | 105 | throwTypeError, |
379 | 105 | Predefined::getSymbolID(Predefined::emptyString), |
380 | 105 | 0, |
381 | 105 | Runtime::makeNullHandle<JSObject>()); |
382 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
383 | 105 | throwTypeErrorFunction, |
384 | 105 | runtime, |
385 | 105 | Predefined::getSymbolID(Predefined::length), |
386 | 105 | clearConfigurableDPF, |
387 | 105 | Runtime::getUndefinedValue())); |
388 | 105 | runtime.throwTypeErrorAccessor = PropertyAccessor::create( |
389 | 105 | runtime, throwTypeErrorFunction, throwTypeErrorFunction); |
390 | | |
391 | | // Define the 'parseInt' function. |
392 | 105 | runtime.parseIntFunction = |
393 | 105 | defineGlobalFunc( |
394 | 105 | Predefined::getSymbolID(Predefined::parseInt), parseInt, 2) |
395 | 105 | .getHermesValue(); |
396 | | |
397 | | // Define the 'parseFloat' function. |
398 | 105 | runtime.parseFloatFunction = |
399 | 105 | defineGlobalFunc( |
400 | 105 | Predefined::getSymbolID(Predefined::parseFloat), parseFloat, 1) |
401 | 105 | .getHermesValue(); |
402 | | |
403 | | // "Forward declaration" of String.prototype. Its properties will be |
404 | | // populated later. |
405 | 105 | runtime.stringPrototype = |
406 | 105 | runtime |
407 | 105 | .ignoreAllocationFailure(JSString::create( |
408 | 105 | runtime, |
409 | 105 | runtime.getPredefinedStringHandle(Predefined::emptyString), |
410 | 105 | Handle<JSObject>::vmcast(&runtime.objectPrototype))) |
411 | 105 | .getHermesValue(); |
412 | | |
413 | | // "Forward declaration" of BigInt.prototype. Its properties will be |
414 | | // populated later. |
415 | 105 | runtime.bigintPrototype = JSObject::create(runtime).getHermesValue(); |
416 | | |
417 | | // "Forward declaration" of Number.prototype. Its properties will be |
418 | | // populated later. |
419 | 105 | runtime.numberPrototype = |
420 | 105 | JSNumber::create( |
421 | 105 | runtime, +0.0, Handle<JSObject>::vmcast(&runtime.objectPrototype)) |
422 | 105 | .getHermesValue(); |
423 | | |
424 | | // "Forward declaration" of Boolean.prototype. Its properties will be |
425 | | // populated later. |
426 | 105 | runtime.booleanPrototype = |
427 | 105 | JSBoolean::create( |
428 | 105 | runtime, false, Handle<JSObject>::vmcast(&runtime.objectPrototype)) |
429 | 105 | .getHermesValue(); |
430 | | |
431 | | // "Forward declaration" of Symbol.prototype. Its properties will be |
432 | | // populated later. |
433 | 105 | runtime.symbolPrototype = JSObject::create(runtime).getHermesValue(); |
434 | | |
435 | | // "Forward declaration" of Date.prototype. Its properties will be |
436 | | // populated later. |
437 | 105 | runtime.datePrototype = |
438 | 105 | JSObject::create( |
439 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.objectPrototype)) |
440 | 105 | .getHermesValue(); |
441 | | |
442 | | // "Forward declaration" of %IteratorPrototype%. |
443 | 105 | runtime.iteratorPrototype = JSObject::create(runtime).getHermesValue(); |
444 | | |
445 | | // "Forward declaration" of Array.prototype. Its properties will be |
446 | | // populated later. |
447 | 105 | runtime.arrayPrototype = |
448 | 105 | runtime |
449 | 105 | .ignoreAllocationFailure(JSArray::createNoAllocPropStorage( |
450 | 105 | runtime, |
451 | 105 | Handle<JSObject>::vmcast(&runtime.objectPrototype), |
452 | 105 | JSArray::createClass( |
453 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.objectPrototype)), |
454 | 105 | 0, |
455 | 105 | 0)) |
456 | 105 | .getHermesValue(); |
457 | | |
458 | | // Declare the array class. |
459 | 105 | runtime.arrayClass = |
460 | 105 | JSArray::createClass( |
461 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.arrayPrototype)) |
462 | 105 | .getHermesValue(); |
463 | | |
464 | | // Declare the regexp match object class. |
465 | 105 | runtime.regExpMatchClass = |
466 | 105 | JSRegExp::createMatchClass( |
467 | 105 | runtime, Handle<HiddenClass>::vmcast(&runtime.arrayClass)) |
468 | 105 | .getHermesValue(); |
469 | | |
470 | | // "Forward declaration" of ArrayBuffer.prototype. Its properties will be |
471 | | // populated later. |
472 | 105 | runtime.arrayBufferPrototype = |
473 | 105 | JSObject::create( |
474 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.objectPrototype)) |
475 | 105 | .getHermesValue(); |
476 | | |
477 | | // "Forward declaration" of DataView.prototype. Its properties will be |
478 | | // populated later. |
479 | 105 | runtime.dataViewPrototype = |
480 | 105 | JSObject::create( |
481 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.objectPrototype)) |
482 | 105 | .getHermesValue(); |
483 | | |
484 | | // "Forward declaration" of TypedArrayBase.prototype. Its properties will be |
485 | | // populated later. |
486 | 105 | runtime.typedArrayBasePrototype = JSObject::create(runtime).getHermesValue(); |
487 | | |
488 | | // Typed arrays |
489 | | // NOTE: a TypedArray's prototype is a normal object, not a TypedArray. |
490 | 105 | #define TYPED_ARRAY(name, type) \ |
491 | 1.15k | runtime.name##ArrayPrototype = \ |
492 | 1.15k | JSObject::create( \ |
493 | 1.15k | runtime, Handle<JSObject>::vmcast(&runtime.typedArrayBasePrototype)) \ |
494 | 1.15k | .getHermesValue(); |
495 | 105 | #include "hermes/VM/TypedArrays.def" |
496 | | |
497 | | // "Forward declaration" of Set.prototype. Its properties will be |
498 | | // populated later. |
499 | 105 | runtime.setPrototype = JSObject::create(runtime).getHermesValue(); |
500 | | |
501 | 105 | runtime.setIteratorPrototype = |
502 | 105 | createSetIteratorPrototype(runtime).getHermesValue(); |
503 | | |
504 | | // "Forward declaration" of Map.prototype. Its properties will be |
505 | | // populated later. |
506 | 105 | runtime.mapPrototype = JSObject::create(runtime).getHermesValue(); |
507 | | |
508 | 105 | runtime.mapIteratorPrototype = |
509 | 105 | createMapIteratorPrototype(runtime).getHermesValue(); |
510 | | |
511 | | // "Forward declaration" of RegExp.prototype. |
512 | | // ES6: 21.2.5 "The RegExp prototype object is an ordinary object. It is not a |
513 | | // RegExp instance..." |
514 | 105 | runtime.regExpPrototype = |
515 | 105 | JSObject::create( |
516 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.objectPrototype)) |
517 | 105 | .getHermesValue(); |
518 | | |
519 | | // "Forward declaration" of WeakMap.prototype. |
520 | 105 | runtime.weakMapPrototype = JSObject::create(runtime).getHermesValue(); |
521 | | |
522 | | // "Forward declaration" of WeakSet.prototype. |
523 | 105 | runtime.weakSetPrototype = JSObject::create(runtime).getHermesValue(); |
524 | | |
525 | | // Only define WeakRef if microtasks are being used. |
526 | 105 | if (LLVM_UNLIKELY(runtime.hasMicrotaskQueue())) { |
527 | | // "Forward declaration" of WeakRef.prototype. |
528 | 0 | runtime.weakRefPrototype = JSObject::create(runtime).getHermesValue(); |
529 | 0 | } |
530 | | |
531 | | // "Forward declaration" of %ArrayIteratorPrototype%. |
532 | 105 | runtime.arrayIteratorPrototype = |
533 | 105 | JSObject::create( |
534 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.iteratorPrototype)) |
535 | 105 | .getHermesValue(); |
536 | | |
537 | | // "Forward declaration" of %StringIteratorPrototype%. |
538 | 105 | runtime.stringIteratorPrototype = |
539 | 105 | JSObject::create( |
540 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.iteratorPrototype)) |
541 | 105 | .getHermesValue(); |
542 | | |
543 | | // "Forward declaration" of %RegExpStringIteratorPrototype%. |
544 | 105 | runtime.regExpStringIteratorPrototype = |
545 | 105 | JSObject::create( |
546 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.iteratorPrototype)) |
547 | 105 | .getHermesValue(); |
548 | | |
549 | | // "Forward declaration" of "Generator prototype object" |
550 | 105 | runtime.generatorPrototype = |
551 | 105 | JSObject::create( |
552 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.iteratorPrototype)) |
553 | 105 | .getHermesValue(); |
554 | | |
555 | | // "Forward declaration" of %GeneratorFunction.prototype% |
556 | 105 | runtime.generatorFunctionPrototype = |
557 | 105 | JSObject::create( |
558 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.functionPrototype)) |
559 | 105 | .getHermesValue(); |
560 | | |
561 | | // "Forward declaration" of %AsyncFunction.prototype% |
562 | 105 | runtime.asyncFunctionPrototype = |
563 | 105 | JSObject::create( |
564 | 105 | runtime, Handle<JSObject>::vmcast(&runtime.functionPrototype)) |
565 | 105 | .getHermesValue(); |
566 | | |
567 | | // Object constructor. |
568 | 105 | createObjectConstructor(runtime); |
569 | | |
570 | | // JSError constructor. |
571 | 105 | runtime.errorConstructor = createErrorConstructor(runtime).getHermesValue(); |
572 | | |
573 | | // All Native Error constructors. |
574 | 105 | #define NATIVE_ERROR_TYPE(name) \ |
575 | 945 | runtime.name##Constructor = \ |
576 | 945 | create##name##Constructor(runtime).getHermesValue(); \ |
577 | 945 | gcScope.clearAllHandles(); |
578 | 105 | #define AGGREGATE_ERROR_TYPE(name) NATIVE_ERROR_TYPE(name) |
579 | 105 | #include "hermes/FrontEndDefs/NativeErrorTypes.def" |
580 | | |
581 | | // Populate the internal CallSite prototype. |
582 | 105 | populateCallSitePrototype(runtime); |
583 | | |
584 | | // String constructor. |
585 | 105 | createStringConstructor(runtime); |
586 | | |
587 | | // BigInt constructor. |
588 | 105 | createBigIntConstructor(runtime); |
589 | | |
590 | | // Function constructor. |
591 | 105 | runtime.functionConstructor = |
592 | 105 | createFunctionConstructor(runtime).getHermesValue(); |
593 | | |
594 | | // Number constructor. |
595 | 105 | createNumberConstructor(runtime); |
596 | | |
597 | | // Boolean constructor. |
598 | 105 | createBooleanConstructor(runtime); |
599 | | |
600 | | // Date constructor. |
601 | 105 | createDateConstructor(runtime); |
602 | | |
603 | | // RegExp constructor |
604 | 105 | createRegExpConstructor(runtime); |
605 | 105 | runtime.regExpLastInput = HermesValue::encodeUndefinedValue(); |
606 | 105 | runtime.regExpLastRegExp = HermesValue::encodeUndefinedValue(); |
607 | | |
608 | | // Array constructor. |
609 | 105 | createArrayConstructor(runtime); |
610 | | |
611 | 105 | if (runtime.hasArrayBuffer()) { |
612 | | // ArrayBuffer constructor. |
613 | 105 | createArrayBufferConstructor(runtime); |
614 | | |
615 | | // DataView constructor. |
616 | 105 | createDataViewConstructor(runtime); |
617 | | |
618 | | // TypedArrayBase constructor. |
619 | 105 | runtime.typedArrayBaseConstructor = |
620 | 105 | createTypedArrayBaseConstructor(runtime).getHermesValue(); |
621 | | |
622 | 105 | #define TYPED_ARRAY(name, type) \ |
623 | 1.15k | runtime.name##ArrayConstructor = \ |
624 | 1.15k | create##name##ArrayConstructor(runtime).getHermesValue(); \ |
625 | 1.15k | gcScope.clearAllHandles(); |
626 | 105 | #include "hermes/VM/TypedArrays.def" |
627 | 105 | } else { |
628 | 0 | gcScope.clearAllHandles(); |
629 | 0 | } // hasArrayBuffer |
630 | | |
631 | | // Set constructor. |
632 | 105 | createSetConstructor(runtime); |
633 | | |
634 | | // Map constructor. |
635 | 105 | createMapConstructor(runtime); |
636 | | |
637 | | // WeakMap constructor. |
638 | 105 | createWeakMapConstructor(runtime); |
639 | | |
640 | | // WeakSet constructor. |
641 | 105 | createWeakSetConstructor(runtime); |
642 | | |
643 | | // Only define WeakRef constructor if microtasks are being used. |
644 | 105 | if (LLVM_UNLIKELY(runtime.hasMicrotaskQueue())) { |
645 | | // WeakRef constructor. |
646 | 0 | createWeakRefConstructor(runtime); |
647 | 0 | } |
648 | | |
649 | | // Symbol constructor. |
650 | 105 | createSymbolConstructor(runtime); |
651 | | |
652 | | /// %IteratorPrototype%. |
653 | 105 | populateIteratorPrototype(runtime); |
654 | | |
655 | | /// Array Iterator. |
656 | 105 | populateArrayIteratorPrototype(runtime); |
657 | | |
658 | | /// String Iterator. |
659 | 105 | populateStringIteratorPrototype(runtime); |
660 | | |
661 | | /// RegExp String Iterator. |
662 | 105 | populateRegExpStringIteratorPrototype(runtime); |
663 | | |
664 | | // GeneratorFunction constructor (not directly exposed in the global object). |
665 | 105 | createGeneratorFunctionConstructor(runtime); |
666 | | |
667 | | // AsyncFunction constructor (not directly exposed in the global object). |
668 | 105 | createAsyncFunctionConstructor(runtime); |
669 | | |
670 | | // %GeneratorPrototype%. |
671 | 105 | populateGeneratorPrototype(runtime); |
672 | | |
673 | | // Proxy constructor. |
674 | 105 | if (LLVM_UNLIKELY(runtime.hasES6Proxy())) { |
675 | 105 | createProxyConstructor(runtime); |
676 | 105 | } |
677 | | |
678 | | // Define the global Math object |
679 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
680 | 105 | runtime.getGlobal(), |
681 | 105 | runtime, |
682 | 105 | Predefined::getSymbolID(Predefined::Math), |
683 | 105 | normalDPF, |
684 | 105 | createMathObject(runtime))); |
685 | | |
686 | | // Define the global JSON object |
687 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
688 | 105 | runtime.getGlobal(), |
689 | 105 | runtime, |
690 | 105 | Predefined::getSymbolID(Predefined::JSON), |
691 | 105 | normalDPF, |
692 | 105 | createJSONObject(runtime))); |
693 | | |
694 | 105 | if (LLVM_UNLIKELY(runtime.hasES6Proxy())) { |
695 | | // Define the global Reflect object |
696 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
697 | 105 | runtime.getGlobal(), |
698 | 105 | runtime, |
699 | 105 | Predefined::getSymbolID(Predefined::Reflect), |
700 | 105 | normalDPF, |
701 | 105 | createReflectObject(runtime))); |
702 | 105 | } |
703 | | |
704 | | // Define the global %HermesInternal object. |
705 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
706 | 105 | runtime.getGlobal(), |
707 | 105 | runtime, |
708 | 105 | Predefined::getSymbolID(Predefined::HermesInternal), |
709 | 105 | constantDPF, |
710 | 105 | createHermesInternalObject(runtime, jsLibFlags))); |
711 | | |
712 | 105 | #ifdef HERMES_ENABLE_DEBUGGER |
713 | | |
714 | | // Define the global %DebuggerInternal object. |
715 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
716 | 105 | runtime.getGlobal(), |
717 | 105 | runtime, |
718 | 105 | runtime.getIdentifierTable().registerLazyIdentifier( |
719 | 105 | createASCIIRef("DebuggerInternal")), |
720 | 105 | constantDPF, |
721 | 105 | createDebuggerInternalObject(runtime))); |
722 | | |
723 | 105 | #endif // HERMES_ENABLE_DEBUGGER |
724 | | |
725 | | // Define the 'print' function. |
726 | 105 | defineGlobalFunc(Predefined::getSymbolID(Predefined::print), print, 1); |
727 | | |
728 | | // Define the 'eval' function. |
729 | 105 | defineGlobalFunc(Predefined::getSymbolID(Predefined::eval), eval, 1); |
730 | | |
731 | | // Define the 'isNaN' function. |
732 | 105 | defineGlobalFunc(Predefined::getSymbolID(Predefined::isNaN), isNaN, 1); |
733 | | |
734 | | // Define the 'isFinite' function. |
735 | 105 | defineGlobalFunc(Predefined::getSymbolID(Predefined::isFinite), isFinite, 1); |
736 | | |
737 | | // Define the 'escape' function. |
738 | 105 | defineGlobalFunc(Predefined::getSymbolID(Predefined::escape), escape, 1); |
739 | | |
740 | | // Define the 'unescape' function. |
741 | 105 | defineGlobalFunc(Predefined::getSymbolID(Predefined::unescape), unescape, 1); |
742 | | |
743 | | // Define the 'decodeURI' function. |
744 | 105 | defineGlobalFunc( |
745 | 105 | Predefined::getSymbolID(Predefined::decodeURI), decodeURI, 1); |
746 | | |
747 | | // Define the 'decodeURIComponent' function. |
748 | 105 | defineGlobalFunc( |
749 | 105 | Predefined::getSymbolID(Predefined::decodeURIComponent), |
750 | 105 | decodeURIComponent, |
751 | 105 | 1); |
752 | | |
753 | | // Define the 'encodeURI' function. |
754 | 105 | defineGlobalFunc( |
755 | 105 | Predefined::getSymbolID(Predefined::encodeURI), encodeURI, 1); |
756 | | |
757 | | // Define the 'encodeURIComponent' function. |
758 | 105 | defineGlobalFunc( |
759 | 105 | Predefined::getSymbolID(Predefined::encodeURIComponent), |
760 | 105 | encodeURIComponent, |
761 | 105 | 1); |
762 | | |
763 | | // Define the 'globalThis' property. |
764 | 105 | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
765 | 105 | runtime.getGlobal(), |
766 | 105 | runtime, |
767 | 105 | Predefined::getSymbolID(Predefined::globalThis), |
768 | 105 | normalDPF, |
769 | 105 | runtime.getGlobal())); |
770 | | |
771 | | // Define the 'require' function. |
772 | 105 | runtime.requireFunction = |
773 | 105 | NativeFunction::create( |
774 | 105 | runtime, |
775 | 105 | Handle<JSObject>::vmcast(&runtime.functionPrototype), |
776 | 105 | nullptr, |
777 | 105 | require, |
778 | 105 | Predefined::getSymbolID(Predefined::require), |
779 | 105 | 1, |
780 | 105 | Runtime::makeNullHandle<JSObject>()) |
781 | 105 | .getHermesValue(); |
782 | | |
783 | 105 | if (jsLibFlags.enableHermesInternal) { |
784 | | // Define the 'gc' function. |
785 | 105 | defineGlobalFunc(Predefined::getSymbolID(Predefined::gc), gc, 0); |
786 | 105 | } |
787 | | |
788 | | #ifdef HERMES_ENABLE_IR_INSTRUMENTATION |
789 | | // Define the global __instrument object |
790 | | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
791 | | runtime.getGlobal(), |
792 | | runtime, |
793 | | runtime.getIdentifierTable().registerLazyIdentifier( |
794 | | createASCIIRef("__instrument")), |
795 | | normalDPF, |
796 | | createInstrumentObject(runtime))); |
797 | | #endif |
798 | | |
799 | | #ifdef HERMES_ENABLE_INTL |
800 | | // Define the global Intl object |
801 | | // TODO T65916424: Consider how we can move this somewhere more modular. |
802 | | if (runtime.hasIntl()) { |
803 | | runtime.ignoreAllocationFailure(JSObject::defineOwnProperty( |
804 | | runtime.getGlobal(), |
805 | | runtime, |
806 | | Predefined::getSymbolID(Predefined::Intl), |
807 | | normalDPF, |
808 | | intl::createIntlObject(runtime))); |
809 | | } |
810 | | #endif |
811 | 105 | } |
812 | | |
813 | | } // namespace vm |
814 | | } // namespace hermes |