1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "vm/SelfHosting.h"
8
9 #include "mozilla/Casting.h"
10 #include "mozilla/DebugOnly.h"
11 #include "mozilla/Maybe.h"
12 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
13
14 #include <algorithm>
15 #include <iterator>
16
17 #include "jsdate.h"
18 #include "jsfriendapi.h"
19 #include "jsmath.h"
20 #include "jsnum.h"
21 #include "selfhosted.out.h"
22
23 #include "builtin/Array.h"
24 #include "builtin/BigInt.h"
25 #ifdef JS_HAS_INTL_API
26 # include "builtin/intl/Collator.h"
27 # include "builtin/intl/DateTimeFormat.h"
28 # include "builtin/intl/DisplayNames.h"
29 # include "builtin/intl/IntlObject.h"
30 # include "builtin/intl/ListFormat.h"
31 # include "builtin/intl/Locale.h"
32 # include "builtin/intl/NumberFormat.h"
33 # include "builtin/intl/PluralRules.h"
34 # include "builtin/intl/RelativeTimeFormat.h"
35 #endif
36 #include "builtin/MapObject.h"
37 #include "builtin/ModuleObject.h"
38 #include "builtin/Object.h"
39 #include "builtin/Promise.h"
40 #include "builtin/Reflect.h"
41 #include "builtin/RegExp.h"
42 #include "builtin/SelfHostingDefines.h"
43 #include "builtin/String.h"
44 #include "builtin/WeakMapObject.h"
45 #include "frontend/BytecodeCompilation.h" // CompileGlobalScriptToStencil
46 #include "frontend/CompilationStencil.h" // js::frontend::CompilationStencil
47 #include "gc/Marking.h"
48 #include "gc/Policy.h"
49 #include "jit/AtomicOperations.h"
50 #include "jit/InlinableNatives.h"
51 #include "js/CharacterEncoding.h"
52 #include "js/CompilationAndEvaluation.h"
53 #include "js/Conversions.h"
54 #include "js/Date.h"
55 #include "js/ErrorReport.h" // JS::PrintError
56 #include "js/Exception.h"
57 #include "js/experimental/TypedData.h" // JS_GetArrayBufferViewType
58 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
59 #include "js/Modules.h" // JS::GetModulePrivate
60 #include "js/PropertySpec.h"
61 #include "js/ScalarType.h" // js::Scalar::Type
62 #include "js/SourceText.h" // JS::SourceText
63 #include "js/StableStringChars.h"
64 #include "js/Transcoding.h"
65 #include "js/Warnings.h" // JS::{,Set}WarningReporter
66 #include "js/Wrapper.h"
67 #include "util/StringBuffer.h"
68 #include "vm/ArgumentsObject.h"
69 #include "vm/AsyncFunction.h"
70 #include "vm/AsyncIteration.h"
71 #include "vm/BigIntType.h"
72 #include "vm/BytecodeIterator.h"
73 #include "vm/BytecodeLocation.h"
74 #include "vm/Compression.h"
75 #include "vm/DateObject.h"
76 #include "vm/ErrorReporting.h" // js::MaybePrintAndClearPendingException
77 #include "vm/FrameIter.h" // js::ScriptFrameIter
78 #include "vm/FunctionFlags.h" // js::FunctionFlags
79 #include "vm/GeneratorObject.h"
80 #include "vm/Interpreter.h"
81 #include "vm/Iteration.h"
82 #include "vm/JSContext.h"
83 #include "vm/JSFunction.h"
84 #include "vm/JSObject.h"
85 #include "vm/PIC.h"
86 #include "vm/PlainObject.h" // js::PlainObject
87 #include "vm/Printer.h"
88 #include "vm/Realm.h"
89 #include "vm/RegExpObject.h"
90 #include "vm/StringType.h"
91 #include "vm/ToSource.h" // js::ValueToSource
92 #include "vm/TypedArrayObject.h"
93 #include "vm/Uint8Clamped.h"
94 #include "vm/WrapperObject.h"
95
96 #include "gc/GC-inl.h"
97 #include "vm/BooleanObject-inl.h"
98 #include "vm/BytecodeIterator-inl.h"
99 #include "vm/BytecodeLocation-inl.h"
100 #include "vm/Compartment-inl.h"
101 #include "vm/JSAtom-inl.h"
102 #include "vm/JSFunction-inl.h"
103 #include "vm/JSObject-inl.h"
104 #include "vm/JSScript-inl.h"
105 #include "vm/NativeObject-inl.h"
106 #include "vm/NumberObject-inl.h"
107 #include "vm/StringObject-inl.h"
108 #include "vm/TypedArrayObject-inl.h"
109
110 using namespace js;
111 using namespace js::selfhosted;
112
113 using JS::AutoCheckCannotGC;
114 using JS::AutoStableStringChars;
115 using JS::CompileOptions;
116 using mozilla::Maybe;
117
selfHosting_WarningReporter(JSContext * cx,JSErrorReport * report)118 static void selfHosting_WarningReporter(JSContext* cx, JSErrorReport* report) {
119 MOZ_ASSERT(report->isWarning());
120
121 JS::PrintError(stderr, report, true);
122 }
123
intrinsic_ToObject(JSContext * cx,unsigned argc,Value * vp)124 static bool intrinsic_ToObject(JSContext* cx, unsigned argc, Value* vp) {
125 CallArgs args = CallArgsFromVp(argc, vp);
126 JSObject* obj = ToObject(cx, args[0]);
127 if (!obj) {
128 return false;
129 }
130 args.rval().setObject(*obj);
131 return true;
132 }
133
intrinsic_IsObject(JSContext * cx,unsigned argc,Value * vp)134 static bool intrinsic_IsObject(JSContext* cx, unsigned argc, Value* vp) {
135 CallArgs args = CallArgsFromVp(argc, vp);
136 Value val = args[0];
137 bool isObject = val.isObject();
138 args.rval().setBoolean(isObject);
139 return true;
140 }
141
intrinsic_IsArray(JSContext * cx,unsigned argc,Value * vp)142 static bool intrinsic_IsArray(JSContext* cx, unsigned argc, Value* vp) {
143 CallArgs args = CallArgsFromVp(argc, vp);
144 MOZ_ASSERT(args.length() == 1);
145 RootedValue val(cx, args[0]);
146 if (val.isObject()) {
147 RootedObject obj(cx, &val.toObject());
148 bool isArray = false;
149 if (!IsArray(cx, obj, &isArray)) {
150 return false;
151 }
152 args.rval().setBoolean(isArray);
153 } else {
154 args.rval().setBoolean(false);
155 }
156 return true;
157 }
158
intrinsic_IsCrossRealmArrayConstructor(JSContext * cx,unsigned argc,Value * vp)159 static bool intrinsic_IsCrossRealmArrayConstructor(JSContext* cx, unsigned argc,
160 Value* vp) {
161 CallArgs args = CallArgsFromVp(argc, vp);
162 MOZ_ASSERT(args.length() == 1);
163 MOZ_ASSERT(args[0].isObject());
164
165 bool result = false;
166 if (!IsCrossRealmArrayConstructor(cx, &args[0].toObject(), &result)) {
167 return false;
168 }
169 args.rval().setBoolean(result);
170 return true;
171 }
172
intrinsic_ToLength(JSContext * cx,unsigned argc,Value * vp)173 static bool intrinsic_ToLength(JSContext* cx, unsigned argc, Value* vp) {
174 CallArgs args = CallArgsFromVp(argc, vp);
175 MOZ_ASSERT(args.length() == 1);
176
177 // Inline fast path for the common case.
178 if (args[0].isInt32()) {
179 int32_t i = args[0].toInt32();
180 args.rval().setInt32(i < 0 ? 0 : i);
181 return true;
182 }
183
184 uint64_t length = 0;
185 if (!ToLength(cx, args[0], &length)) {
186 return false;
187 }
188
189 args.rval().setNumber(double(length));
190 return true;
191 }
192
intrinsic_ToInteger(JSContext * cx,unsigned argc,Value * vp)193 static bool intrinsic_ToInteger(JSContext* cx, unsigned argc, Value* vp) {
194 CallArgs args = CallArgsFromVp(argc, vp);
195 double result;
196 if (!ToInteger(cx, args[0], &result)) {
197 return false;
198 }
199 args.rval().setNumber(result);
200 return true;
201 }
202
intrinsic_ToSource(JSContext * cx,unsigned argc,Value * vp)203 static bool intrinsic_ToSource(JSContext* cx, unsigned argc, Value* vp) {
204 CallArgs args = CallArgsFromVp(argc, vp);
205 JSString* str = ValueToSource(cx, args[0]);
206 if (!str) {
207 return false;
208 }
209 args.rval().setString(str);
210 return true;
211 }
212
intrinsic_ToPropertyKey(JSContext * cx,unsigned argc,Value * vp)213 static bool intrinsic_ToPropertyKey(JSContext* cx, unsigned argc, Value* vp) {
214 CallArgs args = CallArgsFromVp(argc, vp);
215 RootedId id(cx);
216 if (!ToPropertyKey(cx, args[0], &id)) {
217 return false;
218 }
219
220 args.rval().set(IdToValue(id));
221 return true;
222 }
223
intrinsic_IsCallable(JSContext * cx,unsigned argc,Value * vp)224 static bool intrinsic_IsCallable(JSContext* cx, unsigned argc, Value* vp) {
225 CallArgs args = CallArgsFromVp(argc, vp);
226 args.rval().setBoolean(IsCallable(args[0]));
227 return true;
228 }
229
intrinsic_IsConstructor(JSContext * cx,unsigned argc,Value * vp)230 static bool intrinsic_IsConstructor(JSContext* cx, unsigned argc, Value* vp) {
231 CallArgs args = CallArgsFromVp(argc, vp);
232 MOZ_ASSERT(args.length() == 1);
233 args.rval().setBoolean(IsConstructor(args[0]));
234 return true;
235 }
236
237 template <typename T>
intrinsic_IsInstanceOfBuiltin(JSContext * cx,unsigned argc,Value * vp)238 static bool intrinsic_IsInstanceOfBuiltin(JSContext* cx, unsigned argc,
239 Value* vp) {
240 CallArgs args = CallArgsFromVp(argc, vp);
241 MOZ_ASSERT(args.length() == 1);
242 MOZ_ASSERT(args[0].isObject());
243
244 args.rval().setBoolean(args[0].toObject().is<T>());
245 return true;
246 }
247
248 template <typename T>
intrinsic_GuardToBuiltin(JSContext * cx,unsigned argc,Value * vp)249 static bool intrinsic_GuardToBuiltin(JSContext* cx, unsigned argc, Value* vp) {
250 CallArgs args = CallArgsFromVp(argc, vp);
251 MOZ_ASSERT(args.length() == 1);
252 MOZ_ASSERT(args[0].isObject());
253
254 if (args[0].toObject().is<T>()) {
255 args.rval().setObject(args[0].toObject());
256 return true;
257 }
258 args.rval().setNull();
259 return true;
260 }
261
262 template <typename T>
intrinsic_IsWrappedInstanceOfBuiltin(JSContext * cx,unsigned argc,Value * vp)263 static bool intrinsic_IsWrappedInstanceOfBuiltin(JSContext* cx, unsigned argc,
264 Value* vp) {
265 CallArgs args = CallArgsFromVp(argc, vp);
266 MOZ_ASSERT(args.length() == 1);
267 MOZ_ASSERT(args[0].isObject());
268
269 JSObject* obj = &args[0].toObject();
270 if (!obj->is<WrapperObject>()) {
271 args.rval().setBoolean(false);
272 return true;
273 }
274
275 JSObject* unwrapped = CheckedUnwrapDynamic(obj, cx);
276 if (!unwrapped) {
277 ReportAccessDenied(cx);
278 return false;
279 }
280
281 args.rval().setBoolean(unwrapped->is<T>());
282 return true;
283 }
284
285 template <typename T>
intrinsic_IsPossiblyWrappedInstanceOfBuiltin(JSContext * cx,unsigned argc,Value * vp)286 static bool intrinsic_IsPossiblyWrappedInstanceOfBuiltin(JSContext* cx,
287 unsigned argc,
288 Value* vp) {
289 CallArgs args = CallArgsFromVp(argc, vp);
290 MOZ_ASSERT(args.length() == 1);
291 MOZ_ASSERT(args[0].isObject());
292
293 JSObject* obj = CheckedUnwrapDynamic(&args[0].toObject(), cx);
294 if (!obj) {
295 ReportAccessDenied(cx);
296 return false;
297 }
298
299 args.rval().setBoolean(obj->is<T>());
300 return true;
301 }
302
intrinsic_SubstringKernel(JSContext * cx,unsigned argc,Value * vp)303 static bool intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp) {
304 CallArgs args = CallArgsFromVp(argc, vp);
305 MOZ_ASSERT(args[0].isString());
306 MOZ_RELEASE_ASSERT(args[1].isInt32());
307 MOZ_RELEASE_ASSERT(args[2].isInt32());
308
309 RootedString str(cx, args[0].toString());
310 int32_t begin = args[1].toInt32();
311 int32_t length = args[2].toInt32();
312
313 JSString* substr = SubstringKernel(cx, str, begin, length);
314 if (!substr) {
315 return false;
316 }
317
318 args.rval().setString(substr);
319 return true;
320 }
321
ThrowErrorWithType(JSContext * cx,JSExnType type,const CallArgs & args)322 static void ThrowErrorWithType(JSContext* cx, JSExnType type,
323 const CallArgs& args) {
324 MOZ_RELEASE_ASSERT(args[0].isInt32());
325 uint32_t errorNumber = args[0].toInt32();
326
327 #ifdef DEBUG
328 const JSErrorFormatString* efs = GetErrorMessage(nullptr, errorNumber);
329 MOZ_ASSERT(efs->argCount == args.length() - 1);
330 MOZ_ASSERT(efs->exnType == type,
331 "error-throwing intrinsic and error number are inconsistent");
332 #endif
333
334 UniqueChars errorArgs[3];
335 for (unsigned i = 1; i < 4 && i < args.length(); i++) {
336 HandleValue val = args[i];
337 if (val.isInt32() || val.isString()) {
338 JSString* str = ToString<CanGC>(cx, val);
339 if (!str) {
340 return;
341 }
342 errorArgs[i - 1] = QuoteString(cx, str);
343 } else {
344 errorArgs[i - 1] =
345 DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, nullptr);
346 }
347 if (!errorArgs[i - 1]) {
348 return;
349 }
350 }
351
352 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber,
353 errorArgs[0].get(), errorArgs[1].get(),
354 errorArgs[2].get());
355 }
356
intrinsic_ThrowRangeError(JSContext * cx,unsigned argc,Value * vp)357 static bool intrinsic_ThrowRangeError(JSContext* cx, unsigned argc, Value* vp) {
358 CallArgs args = CallArgsFromVp(argc, vp);
359 MOZ_ASSERT(args.length() >= 1);
360
361 ThrowErrorWithType(cx, JSEXN_RANGEERR, args);
362 return false;
363 }
364
intrinsic_ThrowTypeError(JSContext * cx,unsigned argc,Value * vp)365 static bool intrinsic_ThrowTypeError(JSContext* cx, unsigned argc, Value* vp) {
366 CallArgs args = CallArgsFromVp(argc, vp);
367 MOZ_ASSERT(args.length() >= 1);
368
369 ThrowErrorWithType(cx, JSEXN_TYPEERR, args);
370 return false;
371 }
372
intrinsic_ThrowSyntaxError(JSContext * cx,unsigned argc,Value * vp)373 static bool intrinsic_ThrowSyntaxError(JSContext* cx, unsigned argc,
374 Value* vp) {
375 CallArgs args = CallArgsFromVp(argc, vp);
376 MOZ_ASSERT(args.length() >= 1);
377
378 ThrowErrorWithType(cx, JSEXN_SYNTAXERR, args);
379 return false;
380 }
381
intrinsic_ThrowAggregateError(JSContext * cx,unsigned argc,Value * vp)382 static bool intrinsic_ThrowAggregateError(JSContext* cx, unsigned argc,
383 Value* vp) {
384 CallArgs args = CallArgsFromVp(argc, vp);
385 MOZ_ASSERT(args.length() >= 1);
386
387 ThrowErrorWithType(cx, JSEXN_AGGREGATEERR, args);
388 return false;
389 }
390
intrinsic_ThrowInternalError(JSContext * cx,unsigned argc,Value * vp)391 static bool intrinsic_ThrowInternalError(JSContext* cx, unsigned argc,
392 Value* vp) {
393 CallArgs args = CallArgsFromVp(argc, vp);
394 MOZ_ASSERT(args.length() >= 1);
395
396 ThrowErrorWithType(cx, JSEXN_INTERNALERR, args);
397 return false;
398 }
399
intrinsic_GetErrorMessage(JSContext * cx,unsigned argc,Value * vp)400 static bool intrinsic_GetErrorMessage(JSContext* cx, unsigned argc, Value* vp) {
401 CallArgs args = CallArgsFromVp(argc, vp);
402 MOZ_ASSERT(args.length() == 1);
403 MOZ_RELEASE_ASSERT(args[0].isInt32());
404
405 const JSErrorFormatString* errorString =
406 GetErrorMessage(nullptr, args[0].toInt32());
407 MOZ_ASSERT(errorString);
408
409 MOZ_ASSERT(errorString->argCount == 0);
410 RootedString message(cx, JS_NewStringCopyZ(cx, errorString->format));
411 if (!message) {
412 return false;
413 }
414
415 args.rval().setString(message);
416 return true;
417 }
418
intrinsic_CreateModuleSyntaxError(JSContext * cx,unsigned argc,Value * vp)419 static bool intrinsic_CreateModuleSyntaxError(JSContext* cx, unsigned argc,
420 Value* vp) {
421 CallArgs args = CallArgsFromVp(argc, vp);
422 MOZ_ASSERT(args.length() == 4);
423 MOZ_ASSERT(args[0].isObject());
424 MOZ_RELEASE_ASSERT(args[1].isInt32());
425 MOZ_RELEASE_ASSERT(args[2].isInt32());
426 MOZ_ASSERT(args[3].isString());
427
428 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
429 RootedString filename(cx,
430 JS_NewStringCopyZ(cx, module->script()->filename()));
431 if (!filename) {
432 return false;
433 }
434
435 RootedString message(cx, args[3].toString());
436
437 RootedValue error(cx);
438 if (!JS::CreateError(cx, JSEXN_SYNTAXERR, nullptr, filename,
439 args[1].toInt32(), args[2].toInt32(), nullptr, message,
440 &error)) {
441 return false;
442 }
443
444 args.rval().set(error);
445 return true;
446 }
447
448 /**
449 * Handles an assertion failure in self-hosted code just like an assertion
450 * failure in C++ code. Information about the failure can be provided in
451 * args[0].
452 */
intrinsic_AssertionFailed(JSContext * cx,unsigned argc,Value * vp)453 static bool intrinsic_AssertionFailed(JSContext* cx, unsigned argc, Value* vp) {
454 #ifdef DEBUG
455 CallArgs args = CallArgsFromVp(argc, vp);
456 if (args.length() > 0) {
457 // try to dump the informative string
458 JSString* str = ToString<CanGC>(cx, args[0]);
459 if (str) {
460 js::Fprinter out(stderr);
461 out.put("Self-hosted JavaScript assertion info: ");
462 str->dumpCharsNoNewline(out);
463 out.putChar('\n');
464 }
465 }
466 #endif
467 MOZ_ASSERT(false);
468 return false;
469 }
470
471 /**
472 * Dumps a message to stderr, after stringifying it. Doesn't append a newline.
473 */
intrinsic_DumpMessage(JSContext * cx,unsigned argc,Value * vp)474 static bool intrinsic_DumpMessage(JSContext* cx, unsigned argc, Value* vp) {
475 CallArgs args = CallArgsFromVp(argc, vp);
476 #ifdef DEBUG
477 if (args.length() > 0) {
478 // try to dump the informative string
479 js::Fprinter out(stderr);
480 JSString* str = ToString<CanGC>(cx, args[0]);
481 if (str) {
482 str->dumpCharsNoNewline(out);
483 out.putChar('\n');
484 } else {
485 cx->recoverFromOutOfMemory();
486 }
487 }
488 #endif
489 args.rval().setUndefined();
490 return true;
491 }
492
intrinsic_FinishBoundFunctionInit(JSContext * cx,unsigned argc,Value * vp)493 static bool intrinsic_FinishBoundFunctionInit(JSContext* cx, unsigned argc,
494 Value* vp) {
495 CallArgs args = CallArgsFromVp(argc, vp);
496 MOZ_ASSERT(args.length() == 3);
497 MOZ_ASSERT(IsCallable(args[1]));
498 MOZ_RELEASE_ASSERT(args[2].isInt32());
499
500 RootedFunction bound(cx, &args[0].toObject().as<JSFunction>());
501 RootedObject targetObj(cx, &args[1].toObject());
502 int32_t argCount = args[2].toInt32();
503
504 args.rval().setUndefined();
505 return JSFunction::finishBoundFunctionInit(cx, bound, targetObj, argCount);
506 }
507
508 /*
509 * Used to decompile values in the nearest non-builtin stack frame, falling
510 * back to decompiling in the current frame. Helpful for printing higher-order
511 * function arguments.
512 *
513 * The user must supply the argument number of the value in question; it
514 * _cannot_ be automatically determined.
515 */
intrinsic_DecompileArg(JSContext * cx,unsigned argc,Value * vp)516 static bool intrinsic_DecompileArg(JSContext* cx, unsigned argc, Value* vp) {
517 CallArgs args = CallArgsFromVp(argc, vp);
518 MOZ_ASSERT(args.length() == 2);
519 MOZ_RELEASE_ASSERT(args[0].isInt32());
520
521 HandleValue value = args[1];
522 JSString* str = DecompileArgument(cx, args[0].toInt32(), value);
523 if (!str) {
524 return false;
525 }
526 args.rval().setString(str);
527 return true;
528 }
529
intrinsic_DefineDataProperty(JSContext * cx,unsigned argc,Value * vp)530 static bool intrinsic_DefineDataProperty(JSContext* cx, unsigned argc,
531 Value* vp) {
532 CallArgs args = CallArgsFromVp(argc, vp);
533
534 // When DefineDataProperty is called with 3 arguments, it's compiled to
535 // JSOp::InitElem in the bytecode emitter so we shouldn't get here.
536 MOZ_ASSERT(args.length() == 4);
537 MOZ_ASSERT(args[0].isObject());
538 MOZ_RELEASE_ASSERT(args[3].isInt32());
539
540 RootedObject obj(cx, &args[0].toObject());
541 RootedId id(cx);
542 if (!ToPropertyKey(cx, args[1], &id)) {
543 return false;
544 }
545 RootedValue value(cx, args[2]);
546
547 JS::PropertyAttributes attrs;
548 unsigned attributes = args[3].toInt32();
549
550 MOZ_ASSERT(bool(attributes & ATTR_ENUMERABLE) !=
551 bool(attributes & ATTR_NONENUMERABLE),
552 "DefineDataProperty must receive either ATTR_ENUMERABLE xor "
553 "ATTR_NONENUMERABLE");
554 if (attributes & ATTR_ENUMERABLE) {
555 attrs += JS::PropertyAttribute::Enumerable;
556 }
557
558 MOZ_ASSERT(bool(attributes & ATTR_CONFIGURABLE) !=
559 bool(attributes & ATTR_NONCONFIGURABLE),
560 "DefineDataProperty must receive either ATTR_CONFIGURABLE xor "
561 "ATTR_NONCONFIGURABLE");
562 if (attributes & ATTR_CONFIGURABLE) {
563 attrs += JS::PropertyAttribute::Configurable;
564 }
565
566 MOZ_ASSERT(
567 bool(attributes & ATTR_WRITABLE) != bool(attributes & ATTR_NONWRITABLE),
568 "DefineDataProperty must receive either ATTR_WRITABLE xor "
569 "ATTR_NONWRITABLE");
570 if (attributes & ATTR_WRITABLE) {
571 attrs += JS::PropertyAttribute::Writable;
572 }
573
574 Rooted<PropertyDescriptor> desc(cx, PropertyDescriptor::Data(value, attrs));
575 if (!DefineProperty(cx, obj, id, desc)) {
576 return false;
577 }
578
579 args.rval().setUndefined();
580 return true;
581 }
582
intrinsic_DefineProperty(JSContext * cx,unsigned argc,Value * vp)583 static bool intrinsic_DefineProperty(JSContext* cx, unsigned argc, Value* vp) {
584 // _DefineProperty(object, propertyKey, attributes,
585 // valueOrGetter, setter, strict)
586 CallArgs args = CallArgsFromVp(argc, vp);
587 MOZ_ASSERT(args.length() == 6);
588 MOZ_ASSERT(args[0].isObject());
589 MOZ_ASSERT(args[1].isString() || args[1].isNumber() || args[1].isSymbol());
590 MOZ_RELEASE_ASSERT(args[2].isInt32());
591 MOZ_ASSERT(args[5].isBoolean());
592
593 RootedObject obj(cx, &args[0].toObject());
594 RootedId id(cx);
595 if (!PrimitiveValueToId<CanGC>(cx, args[1], &id)) {
596 return false;
597 }
598
599 Rooted<PropertyDescriptor> desc(cx, PropertyDescriptor::Empty());
600
601 unsigned attributes = args[2].toInt32();
602 if (attributes & (ATTR_ENUMERABLE | ATTR_NONENUMERABLE)) {
603 desc.setEnumerable(attributes & ATTR_ENUMERABLE);
604 }
605
606 if (attributes & (ATTR_CONFIGURABLE | ATTR_NONCONFIGURABLE)) {
607 desc.setConfigurable(attributes & ATTR_CONFIGURABLE);
608 }
609
610 if (attributes & (ATTR_WRITABLE | ATTR_NONWRITABLE)) {
611 desc.setWritable(attributes & ATTR_WRITABLE);
612 }
613
614 // When args[4] is |null|, the data descriptor has a value component.
615 if ((attributes & DATA_DESCRIPTOR_KIND) && args[4].isNull()) {
616 desc.setValue(args[3]);
617 }
618
619 if (attributes & ACCESSOR_DESCRIPTOR_KIND) {
620 Value getter = args[3];
621 if (getter.isObject()) {
622 desc.setGetter(&getter.toObject());
623 } else if (getter.isUndefined()) {
624 desc.setGetter(nullptr);
625 } else {
626 MOZ_ASSERT(getter.isNull());
627 }
628
629 Value setter = args[4];
630 if (setter.isObject()) {
631 desc.setSetter(&setter.toObject());
632 } else if (setter.isUndefined()) {
633 desc.setSetter(nullptr);
634 } else {
635 MOZ_ASSERT(setter.isNull());
636 }
637 }
638
639 desc.assertValid();
640
641 ObjectOpResult result;
642 if (!DefineProperty(cx, obj, id, desc, result)) {
643 return false;
644 }
645
646 bool strict = args[5].toBoolean();
647 if (strict && !result.ok()) {
648 // We need to tell our caller Object.defineProperty,
649 // that this operation failed, without actually throwing
650 // for web-compatibility reasons.
651 if (result.failureCode() == JSMSG_CANT_DEFINE_WINDOW_NC) {
652 args.rval().setBoolean(false);
653 return true;
654 }
655
656 return result.reportError(cx, obj, id);
657 }
658
659 args.rval().setBoolean(result.ok());
660 return true;
661 }
662
intrinsic_ObjectHasPrototype(JSContext * cx,unsigned argc,Value * vp)663 static bool intrinsic_ObjectHasPrototype(JSContext* cx, unsigned argc,
664 Value* vp) {
665 CallArgs args = CallArgsFromVp(argc, vp);
666 MOZ_ASSERT(args.length() == 2);
667
668 // Self-hosted code calls this intrinsic with builtin prototypes. These are
669 // always native objects.
670 auto* obj = &args[0].toObject().as<NativeObject>();
671 auto* proto = &args[1].toObject().as<NativeObject>();
672
673 JSObject* actualProto = obj->staticPrototype();
674 args.rval().setBoolean(actualProto == proto);
675 return true;
676 }
677
intrinsic_UnsafeSetReservedSlot(JSContext * cx,unsigned argc,Value * vp)678 static bool intrinsic_UnsafeSetReservedSlot(JSContext* cx, unsigned argc,
679 Value* vp) {
680 CallArgs args = CallArgsFromVp(argc, vp);
681 MOZ_ASSERT(args.length() == 3);
682 MOZ_ASSERT(args[0].isObject());
683 MOZ_RELEASE_ASSERT(args[1].isInt32());
684 MOZ_ASSERT(args[1].toInt32() >= 0);
685
686 uint32_t slot = uint32_t(args[1].toInt32());
687 args[0].toObject().as<NativeObject>().setReservedSlot(slot, args[2]);
688 args.rval().setUndefined();
689 return true;
690 }
691
intrinsic_UnsafeGetReservedSlot(JSContext * cx,unsigned argc,Value * vp)692 static bool intrinsic_UnsafeGetReservedSlot(JSContext* cx, unsigned argc,
693 Value* vp) {
694 CallArgs args = CallArgsFromVp(argc, vp);
695 MOZ_ASSERT(args.length() == 2);
696 MOZ_ASSERT(args[0].isObject());
697 MOZ_RELEASE_ASSERT(args[1].isInt32());
698 MOZ_ASSERT(args[1].toInt32() >= 0);
699
700 uint32_t slot = uint32_t(args[1].toInt32());
701 args.rval().set(args[0].toObject().as<NativeObject>().getReservedSlot(slot));
702 return true;
703 }
704
intrinsic_UnsafeGetObjectFromReservedSlot(JSContext * cx,unsigned argc,Value * vp)705 static bool intrinsic_UnsafeGetObjectFromReservedSlot(JSContext* cx,
706 unsigned argc,
707 Value* vp) {
708 if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp)) {
709 return false;
710 }
711 MOZ_ASSERT(vp->isObject());
712 return true;
713 }
714
intrinsic_UnsafeGetInt32FromReservedSlot(JSContext * cx,unsigned argc,Value * vp)715 static bool intrinsic_UnsafeGetInt32FromReservedSlot(JSContext* cx,
716 unsigned argc, Value* vp) {
717 if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp)) {
718 return false;
719 }
720 MOZ_ASSERT(vp->isInt32());
721 return true;
722 }
723
intrinsic_UnsafeGetStringFromReservedSlot(JSContext * cx,unsigned argc,Value * vp)724 static bool intrinsic_UnsafeGetStringFromReservedSlot(JSContext* cx,
725 unsigned argc,
726 Value* vp) {
727 if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp)) {
728 return false;
729 }
730 MOZ_ASSERT(vp->isString());
731 return true;
732 }
733
intrinsic_UnsafeGetBooleanFromReservedSlot(JSContext * cx,unsigned argc,Value * vp)734 static bool intrinsic_UnsafeGetBooleanFromReservedSlot(JSContext* cx,
735 unsigned argc,
736 Value* vp) {
737 if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp)) {
738 return false;
739 }
740 MOZ_ASSERT(vp->isBoolean());
741 return true;
742 }
743
intrinsic_ThisTimeValue(JSContext * cx,unsigned argc,Value * vp)744 static bool intrinsic_ThisTimeValue(JSContext* cx, unsigned argc, Value* vp) {
745 CallArgs args = CallArgsFromVp(argc, vp);
746 MOZ_ASSERT(args.length() == 1);
747 MOZ_ASSERT(args[0].isInt32());
748
749 const char* name = nullptr;
750
751 int32_t method = args[0].toInt32();
752 if (method == DATE_METHOD_LOCALE_TIME_STRING) {
753 name = "toLocaleTimeString";
754 } else if (method == DATE_METHOD_LOCALE_DATE_STRING) {
755 name = "toLocaleDateString";
756 } else {
757 MOZ_ASSERT(method == DATE_METHOD_LOCALE_STRING);
758 name = "toLocaleString";
759 }
760
761 auto* unwrapped = UnwrapAndTypeCheckThis<DateObject>(cx, args, name);
762 if (!unwrapped) {
763 return false;
764 }
765
766 args.rval().set(unwrapped->UTCTime());
767 return true;
768 }
769
intrinsic_IsPackedArray(JSContext * cx,unsigned argc,Value * vp)770 static bool intrinsic_IsPackedArray(JSContext* cx, unsigned argc, Value* vp) {
771 CallArgs args = CallArgsFromVp(argc, vp);
772 MOZ_ASSERT(args.length() == 1);
773 MOZ_ASSERT(args[0].isObject());
774 args.rval().setBoolean(IsPackedArray(&args[0].toObject()));
775 return true;
776 }
777
intrinsic_NewArrayIterator(JSContext * cx,unsigned argc,Value * vp)778 bool js::intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, Value* vp) {
779 CallArgs args = CallArgsFromVp(argc, vp);
780 MOZ_ASSERT(args.length() == 0);
781
782 JSObject* obj = NewArrayIterator(cx);
783 if (!obj) {
784 return false;
785 }
786
787 args.rval().setObject(*obj);
788 return true;
789 }
790
intrinsic_ArrayIteratorPrototypeOptimizable(JSContext * cx,unsigned argc,Value * vp)791 static bool intrinsic_ArrayIteratorPrototypeOptimizable(JSContext* cx,
792 unsigned argc,
793 Value* vp) {
794 CallArgs args = CallArgsFromVp(argc, vp);
795 MOZ_ASSERT(args.length() == 0);
796
797 ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
798 if (!stubChain) {
799 return false;
800 }
801
802 bool optimized;
803 if (!stubChain->tryOptimizeArrayIteratorNext(cx, &optimized)) {
804 return false;
805 }
806 args.rval().setBoolean(optimized);
807 return true;
808 }
809
intrinsic_GetNextMapEntryForIterator(JSContext * cx,unsigned argc,Value * vp)810 static bool intrinsic_GetNextMapEntryForIterator(JSContext* cx, unsigned argc,
811 Value* vp) {
812 CallArgs args = CallArgsFromVp(argc, vp);
813 MOZ_ASSERT(args.length() == 2);
814 MOZ_ASSERT(args[0].toObject().is<MapIteratorObject>());
815 MOZ_ASSERT(args[1].isObject());
816
817 MapIteratorObject* mapIterator = &args[0].toObject().as<MapIteratorObject>();
818 ArrayObject* result = &args[1].toObject().as<ArrayObject>();
819
820 args.rval().setBoolean(MapIteratorObject::next(mapIterator, result));
821 return true;
822 }
823
intrinsic_CreateMapIterationResultPair(JSContext * cx,unsigned argc,Value * vp)824 static bool intrinsic_CreateMapIterationResultPair(JSContext* cx, unsigned argc,
825 Value* vp) {
826 CallArgs args = CallArgsFromVp(argc, vp);
827 MOZ_ASSERT(args.length() == 0);
828
829 JSObject* result = MapIteratorObject::createResultPair(cx);
830 if (!result) {
831 return false;
832 }
833
834 args.rval().setObject(*result);
835 return true;
836 }
837
intrinsic_GetNextSetEntryForIterator(JSContext * cx,unsigned argc,Value * vp)838 static bool intrinsic_GetNextSetEntryForIterator(JSContext* cx, unsigned argc,
839 Value* vp) {
840 CallArgs args = CallArgsFromVp(argc, vp);
841 MOZ_ASSERT(args.length() == 2);
842 MOZ_ASSERT(args[0].toObject().is<SetIteratorObject>());
843 MOZ_ASSERT(args[1].isObject());
844
845 SetIteratorObject* setIterator = &args[0].toObject().as<SetIteratorObject>();
846 ArrayObject* result = &args[1].toObject().as<ArrayObject>();
847
848 args.rval().setBoolean(SetIteratorObject::next(setIterator, result));
849 return true;
850 }
851
intrinsic_CreateSetIterationResult(JSContext * cx,unsigned argc,Value * vp)852 static bool intrinsic_CreateSetIterationResult(JSContext* cx, unsigned argc,
853 Value* vp) {
854 CallArgs args = CallArgsFromVp(argc, vp);
855 MOZ_ASSERT(args.length() == 0);
856
857 JSObject* result = SetIteratorObject::createResult(cx);
858 if (!result) {
859 return false;
860 }
861
862 args.rval().setObject(*result);
863 return true;
864 }
865
intrinsic_NewStringIterator(JSContext * cx,unsigned argc,Value * vp)866 bool js::intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp) {
867 CallArgs args = CallArgsFromVp(argc, vp);
868 MOZ_ASSERT(args.length() == 0);
869
870 JSObject* obj = NewStringIterator(cx);
871 if (!obj) {
872 return false;
873 }
874
875 args.rval().setObject(*obj);
876 return true;
877 }
878
intrinsic_NewRegExpStringIterator(JSContext * cx,unsigned argc,Value * vp)879 bool js::intrinsic_NewRegExpStringIterator(JSContext* cx, unsigned argc,
880 Value* vp) {
881 CallArgs args = CallArgsFromVp(argc, vp);
882 MOZ_ASSERT(args.length() == 0);
883
884 JSObject* obj = NewRegExpStringIterator(cx);
885 if (!obj) {
886 return false;
887 }
888
889 args.rval().setObject(*obj);
890 return true;
891 }
892
GetUnclonedSelfHostedCanonicalName(JSFunction * fun)893 static js::PropertyName* GetUnclonedSelfHostedCanonicalName(JSFunction* fun) {
894 if (!fun->isExtended()) {
895 return nullptr;
896 }
897 Value name = fun->getExtendedSlot(CANONICAL_FUNCTION_NAME_SLOT);
898 if (!name.isString()) {
899 return nullptr;
900 }
901 return name.toString()->asAtom().asPropertyName();
902 }
903
GetClonedSelfHostedFunctionName(const JSFunction * fun)904 js::PropertyName* js::GetClonedSelfHostedFunctionName(const JSFunction* fun) {
905 if (!fun->isExtended()) {
906 return nullptr;
907 }
908 Value name = fun->getExtendedSlot(LAZY_FUNCTION_NAME_SLOT);
909 if (!name.isString()) {
910 return nullptr;
911 }
912 return name.toString()->asAtom().asPropertyName();
913 }
914
GetClonedSelfHostedFunctionNameOffMainThread(JSFunction * fun)915 js::PropertyName* js::GetClonedSelfHostedFunctionNameOffMainThread(
916 JSFunction* fun) {
917 Value name = fun->getExtendedSlotOffMainThread(LAZY_FUNCTION_NAME_SLOT);
918 if (!name.isString()) {
919 return nullptr;
920 }
921 return name.toString()->asAtom().asPropertyName();
922 }
923
IsExtendedUnclonedSelfHostedFunctionName(JSAtom * name)924 bool js::IsExtendedUnclonedSelfHostedFunctionName(JSAtom* name) {
925 if (name->length() < 2) {
926 return false;
927 }
928 return name->latin1OrTwoByteChar(0) ==
929 ExtendedUnclonedSelfHostedFunctionNamePrefix;
930 }
931
SetUnclonedSelfHostedCanonicalName(JSFunction * fun,JSAtom * name)932 void js::SetUnclonedSelfHostedCanonicalName(JSFunction* fun, JSAtom* name) {
933 fun->setExtendedSlot(CANONICAL_FUNCTION_NAME_SLOT, StringValue(name));
934 }
935
SetClonedSelfHostedFunctionName(JSFunction * fun,JSAtom * name)936 static void SetClonedSelfHostedFunctionName(JSFunction* fun, JSAtom* name) {
937 fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(name));
938 }
939
intrinsic_GeneratorObjectIsClosed(JSContext * cx,unsigned argc,Value * vp)940 static bool intrinsic_GeneratorObjectIsClosed(JSContext* cx, unsigned argc,
941 Value* vp) {
942 CallArgs args = CallArgsFromVp(argc, vp);
943 MOZ_ASSERT(args.length() == 1);
944 MOZ_ASSERT(args[0].isObject());
945
946 GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>();
947 args.rval().setBoolean(genObj->isClosed());
948 return true;
949 }
950
intrinsic_IsSuspendedGenerator(JSContext * cx,unsigned argc,Value * vp)951 static bool intrinsic_IsSuspendedGenerator(JSContext* cx, unsigned argc,
952 Value* vp) {
953 CallArgs args = CallArgsFromVp(argc, vp);
954 MOZ_ASSERT(args.length() == 1);
955
956 if (!args[0].isObject() || !args[0].toObject().is<GeneratorObject>()) {
957 args.rval().setBoolean(false);
958 return true;
959 }
960
961 GeneratorObject& genObj = args[0].toObject().as<GeneratorObject>();
962 args.rval().setBoolean(!genObj.isClosed() && genObj.isSuspended());
963 return true;
964 }
965
intrinsic_GeneratorIsRunning(JSContext * cx,unsigned argc,Value * vp)966 static bool intrinsic_GeneratorIsRunning(JSContext* cx, unsigned argc,
967 Value* vp) {
968 CallArgs args = CallArgsFromVp(argc, vp);
969 MOZ_ASSERT(args.length() == 1);
970 MOZ_ASSERT(args[0].isObject());
971
972 GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>();
973 args.rval().setBoolean(genObj->isRunning());
974 return true;
975 }
976
intrinsic_GeneratorSetClosed(JSContext * cx,unsigned argc,Value * vp)977 static bool intrinsic_GeneratorSetClosed(JSContext* cx, unsigned argc,
978 Value* vp) {
979 CallArgs args = CallArgsFromVp(argc, vp);
980 MOZ_ASSERT(args.length() == 1);
981 MOZ_ASSERT(args[0].isObject());
982
983 GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>();
984 genObj->setClosed();
985 return true;
986 }
987
988 template <typename T>
intrinsic_ArrayBufferByteLength(JSContext * cx,unsigned argc,Value * vp)989 static bool intrinsic_ArrayBufferByteLength(JSContext* cx, unsigned argc,
990 Value* vp) {
991 CallArgs args = CallArgsFromVp(argc, vp);
992 MOZ_ASSERT(args.length() == 1);
993 MOZ_ASSERT(args[0].isObject());
994 MOZ_ASSERT(args[0].toObject().is<T>());
995
996 size_t byteLength = args[0].toObject().as<T>().byteLength();
997 args.rval().setNumber(byteLength);
998 return true;
999 }
1000
1001 template <typename T>
intrinsic_PossiblyWrappedArrayBufferByteLength(JSContext * cx,unsigned argc,Value * vp)1002 static bool intrinsic_PossiblyWrappedArrayBufferByteLength(JSContext* cx,
1003 unsigned argc,
1004 Value* vp) {
1005 CallArgs args = CallArgsFromVp(argc, vp);
1006 MOZ_ASSERT(args.length() == 1);
1007
1008 T* obj = args[0].toObject().maybeUnwrapAs<T>();
1009 if (!obj) {
1010 ReportAccessDenied(cx);
1011 return false;
1012 }
1013
1014 size_t byteLength = obj->byteLength();
1015 args.rval().setNumber(byteLength);
1016 return true;
1017 }
1018
AssertNonNegativeInteger(const Value & v)1019 static void AssertNonNegativeInteger(const Value& v) {
1020 MOZ_ASSERT(v.isNumber());
1021 MOZ_ASSERT(v.toNumber() >= 0);
1022 MOZ_ASSERT(v.toNumber() < DOUBLE_INTEGRAL_PRECISION_LIMIT);
1023 MOZ_ASSERT(JS::ToInteger(v.toNumber()) == v.toNumber());
1024 }
1025
1026 template <typename T>
intrinsic_ArrayBufferCopyData(JSContext * cx,unsigned argc,Value * vp)1027 static bool intrinsic_ArrayBufferCopyData(JSContext* cx, unsigned argc,
1028 Value* vp) {
1029 CallArgs args = CallArgsFromVp(argc, vp);
1030 MOZ_ASSERT(args.length() == 6);
1031 AssertNonNegativeInteger(args[1]);
1032 AssertNonNegativeInteger(args[3]);
1033 AssertNonNegativeInteger(args[4]);
1034
1035 bool isWrapped = args[5].toBoolean();
1036 Rooted<T*> toBuffer(cx);
1037 if (!isWrapped) {
1038 toBuffer = &args[0].toObject().as<T>();
1039 } else {
1040 JSObject* wrapped = &args[0].toObject();
1041 MOZ_ASSERT(wrapped->is<WrapperObject>());
1042 toBuffer = wrapped->maybeUnwrapAs<T>();
1043 if (!toBuffer) {
1044 ReportAccessDenied(cx);
1045 return false;
1046 }
1047 }
1048 size_t toIndex = size_t(args[1].toNumber());
1049 Rooted<T*> fromBuffer(cx, &args[2].toObject().as<T>());
1050 size_t fromIndex = size_t(args[3].toNumber());
1051 size_t count = size_t(args[4].toNumber());
1052
1053 T::copyData(toBuffer, toIndex, fromBuffer, fromIndex, count);
1054
1055 args.rval().setUndefined();
1056 return true;
1057 }
1058
1059 // Arguments must both be SharedArrayBuffer or wrapped SharedArrayBuffer.
intrinsic_SharedArrayBuffersMemorySame(JSContext * cx,unsigned argc,Value * vp)1060 static bool intrinsic_SharedArrayBuffersMemorySame(JSContext* cx, unsigned argc,
1061 Value* vp) {
1062 CallArgs args = CallArgsFromVp(argc, vp);
1063 MOZ_ASSERT(args.length() == 2);
1064
1065 auto* lhs = args[0].toObject().maybeUnwrapAs<SharedArrayBufferObject>();
1066 if (!lhs) {
1067 ReportAccessDenied(cx);
1068 return false;
1069 }
1070 auto* rhs = args[1].toObject().maybeUnwrapAs<SharedArrayBufferObject>();
1071 if (!rhs) {
1072 ReportAccessDenied(cx);
1073 return false;
1074 }
1075
1076 args.rval().setBoolean(lhs->rawBufferObject() == rhs->rawBufferObject());
1077 return true;
1078 }
1079
intrinsic_GetTypedArrayKind(JSContext * cx,unsigned argc,Value * vp)1080 static bool intrinsic_GetTypedArrayKind(JSContext* cx, unsigned argc,
1081 Value* vp) {
1082 CallArgs args = CallArgsFromVp(argc, vp);
1083 MOZ_ASSERT(args.length() == 1);
1084 MOZ_ASSERT(args[0].isObject());
1085
1086 static_assert(TYPEDARRAY_KIND_INT8 == Scalar::Type::Int8,
1087 "TYPEDARRAY_KIND_INT8 doesn't match the scalar type");
1088 static_assert(TYPEDARRAY_KIND_UINT8 == Scalar::Type::Uint8,
1089 "TYPEDARRAY_KIND_UINT8 doesn't match the scalar type");
1090 static_assert(TYPEDARRAY_KIND_INT16 == Scalar::Type::Int16,
1091 "TYPEDARRAY_KIND_INT16 doesn't match the scalar type");
1092 static_assert(TYPEDARRAY_KIND_UINT16 == Scalar::Type::Uint16,
1093 "TYPEDARRAY_KIND_UINT16 doesn't match the scalar type");
1094 static_assert(TYPEDARRAY_KIND_INT32 == Scalar::Type::Int32,
1095 "TYPEDARRAY_KIND_INT32 doesn't match the scalar type");
1096 static_assert(TYPEDARRAY_KIND_UINT32 == Scalar::Type::Uint32,
1097 "TYPEDARRAY_KIND_UINT32 doesn't match the scalar type");
1098 static_assert(TYPEDARRAY_KIND_FLOAT32 == Scalar::Type::Float32,
1099 "TYPEDARRAY_KIND_FLOAT32 doesn't match the scalar type");
1100 static_assert(TYPEDARRAY_KIND_FLOAT64 == Scalar::Type::Float64,
1101 "TYPEDARRAY_KIND_FLOAT64 doesn't match the scalar type");
1102 static_assert(TYPEDARRAY_KIND_UINT8CLAMPED == Scalar::Type::Uint8Clamped,
1103 "TYPEDARRAY_KIND_UINT8CLAMPED doesn't match the scalar type");
1104 static_assert(TYPEDARRAY_KIND_BIGINT64 == Scalar::Type::BigInt64,
1105 "TYPEDARRAY_KIND_BIGINT64 doesn't match the scalar type");
1106 static_assert(TYPEDARRAY_KIND_BIGUINT64 == Scalar::Type::BigUint64,
1107 "TYPEDARRAY_KIND_BIGUINT64 doesn't match the scalar type");
1108
1109 JSObject* obj = &args[0].toObject();
1110 Scalar::Type type = JS_GetArrayBufferViewType(obj);
1111
1112 args.rval().setInt32(static_cast<int32_t>(type));
1113 return true;
1114 }
1115
intrinsic_IsTypedArrayConstructor(JSContext * cx,unsigned argc,Value * vp)1116 static bool intrinsic_IsTypedArrayConstructor(JSContext* cx, unsigned argc,
1117 Value* vp) {
1118 CallArgs args = CallArgsFromVp(argc, vp);
1119 MOZ_ASSERT(args.length() == 1);
1120 MOZ_ASSERT(args[0].isObject());
1121
1122 args.rval().setBoolean(js::IsTypedArrayConstructor(&args[0].toObject()));
1123 return true;
1124 }
1125
intrinsic_TypedArrayBuffer(JSContext * cx,unsigned argc,Value * vp)1126 static bool intrinsic_TypedArrayBuffer(JSContext* cx, unsigned argc,
1127 Value* vp) {
1128 CallArgs args = CallArgsFromVp(argc, vp);
1129 MOZ_ASSERT(args.length() == 1);
1130 MOZ_ASSERT(TypedArrayObject::is(args[0]));
1131
1132 Rooted<TypedArrayObject*> tarray(cx,
1133 &args[0].toObject().as<TypedArrayObject>());
1134 if (!TypedArrayObject::ensureHasBuffer(cx, tarray)) {
1135 return false;
1136 }
1137
1138 args.rval().set(tarray->bufferValue());
1139 return true;
1140 }
1141
intrinsic_TypedArrayByteOffset(JSContext * cx,unsigned argc,Value * vp)1142 static bool intrinsic_TypedArrayByteOffset(JSContext* cx, unsigned argc,
1143 Value* vp) {
1144 CallArgs args = CallArgsFromVp(argc, vp);
1145 MOZ_ASSERT(args.length() == 1);
1146 MOZ_ASSERT(TypedArrayObject::is(args[0]));
1147
1148 auto* tarr = &args[0].toObject().as<TypedArrayObject>();
1149 args.rval().set(tarr->byteOffsetValue());
1150 return true;
1151 }
1152
intrinsic_TypedArrayElementSize(JSContext * cx,unsigned argc,Value * vp)1153 static bool intrinsic_TypedArrayElementSize(JSContext* cx, unsigned argc,
1154 Value* vp) {
1155 CallArgs args = CallArgsFromVp(argc, vp);
1156 MOZ_ASSERT(args.length() == 1);
1157 MOZ_ASSERT(TypedArrayObject::is(args[0]));
1158
1159 unsigned size =
1160 TypedArrayElemSize(args[0].toObject().as<TypedArrayObject>().type());
1161 MOZ_ASSERT(size == 1 || size == 2 || size == 4 || size == 8);
1162
1163 args.rval().setInt32(mozilla::AssertedCast<int32_t>(size));
1164 return true;
1165 }
1166
1167 // Return the value of [[ArrayLength]] internal slot of the TypedArray
intrinsic_TypedArrayLength(JSContext * cx,unsigned argc,Value * vp)1168 static bool intrinsic_TypedArrayLength(JSContext* cx, unsigned argc,
1169 Value* vp) {
1170 CallArgs args = CallArgsFromVp(argc, vp);
1171 MOZ_ASSERT(args.length() == 1);
1172 MOZ_ASSERT(TypedArrayObject::is(args[0]));
1173
1174 auto* tarr = &args[0].toObject().as<TypedArrayObject>();
1175 args.rval().set(tarr->lengthValue());
1176 return true;
1177 }
1178
intrinsic_PossiblyWrappedTypedArrayLength(JSContext * cx,unsigned argc,Value * vp)1179 static bool intrinsic_PossiblyWrappedTypedArrayLength(JSContext* cx,
1180 unsigned argc,
1181 Value* vp) {
1182 CallArgs args = CallArgsFromVp(argc, vp);
1183 MOZ_ASSERT(args.length() == 1);
1184 MOZ_ASSERT(args[0].isObject());
1185
1186 TypedArrayObject* obj = args[0].toObject().maybeUnwrapAs<TypedArrayObject>();
1187 if (!obj) {
1188 ReportAccessDenied(cx);
1189 return false;
1190 }
1191
1192 args.rval().set(obj->lengthValue());
1193 return true;
1194 }
1195
intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer(JSContext * cx,unsigned argc,Value * vp)1196 static bool intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer(JSContext* cx,
1197 unsigned argc,
1198 Value* vp) {
1199 CallArgs args = CallArgsFromVp(argc, vp);
1200 MOZ_ASSERT(args.length() == 1);
1201 MOZ_ASSERT(args[0].isObject());
1202
1203 TypedArrayObject* obj = args[0].toObject().maybeUnwrapAs<TypedArrayObject>();
1204 if (!obj) {
1205 ReportAccessDenied(cx);
1206 return false;
1207 }
1208
1209 bool detached = obj->hasDetachedBuffer();
1210 args.rval().setBoolean(detached);
1211 return true;
1212 }
1213
1214 // Extract the TypedArrayObject* underlying |obj| and return it. This method,
1215 // in a TOTALLY UNSAFE manner, completely violates the normal compartment
1216 // boundaries, returning an object not necessarily in the current compartment
1217 // or in |obj|'s compartment.
1218 //
1219 // All callers of this method are expected to sigil this TypedArrayObject*, and
1220 // all values and information derived from it, with an "unsafe" prefix, to
1221 // indicate the extreme caution required when dealing with such values.
1222 //
1223 // If calling code discipline ever fails to be maintained, it's gonna have a
1224 // bad time.
DangerouslyUnwrapTypedArray(JSContext * cx,JSObject * obj)1225 static TypedArrayObject* DangerouslyUnwrapTypedArray(JSContext* cx,
1226 JSObject* obj) {
1227 // An unwrapped pointer to an object potentially on the other side of a
1228 // compartment boundary! Isn't this such fun?
1229 TypedArrayObject* unwrapped = obj->maybeUnwrapAs<TypedArrayObject>();
1230 if (!unwrapped) {
1231 ReportAccessDenied(cx);
1232 return nullptr;
1233 }
1234
1235 // Be super-duper careful using this, as we've just punched through
1236 // the compartment boundary, and things like buffer() on this aren't
1237 // same-compartment with anything else in the calling method.
1238 return unwrapped;
1239 }
1240
1241 // The specification requires us to perform bitwise copying when |sourceType|
1242 // and |targetType| are the same (ES2017, §22.2.3.24, step 15). Additionally,
1243 // as an optimization, we can also perform bitwise copying when |sourceType|
1244 // and |targetType| have compatible bit-level representations.
IsTypedArrayBitwiseSlice(Scalar::Type sourceType,Scalar::Type targetType)1245 static bool IsTypedArrayBitwiseSlice(Scalar::Type sourceType,
1246 Scalar::Type targetType) {
1247 switch (sourceType) {
1248 case Scalar::Int8:
1249 return targetType == Scalar::Int8 || targetType == Scalar::Uint8;
1250
1251 case Scalar::Uint8:
1252 case Scalar::Uint8Clamped:
1253 return targetType == Scalar::Int8 || targetType == Scalar::Uint8 ||
1254 targetType == Scalar::Uint8Clamped;
1255
1256 case Scalar::Int16:
1257 case Scalar::Uint16:
1258 return targetType == Scalar::Int16 || targetType == Scalar::Uint16;
1259
1260 case Scalar::Int32:
1261 case Scalar::Uint32:
1262 return targetType == Scalar::Int32 || targetType == Scalar::Uint32;
1263
1264 case Scalar::Float32:
1265 return targetType == Scalar::Float32;
1266
1267 case Scalar::Float64:
1268 return targetType == Scalar::Float64;
1269
1270 case Scalar::BigInt64:
1271 case Scalar::BigUint64:
1272 return targetType == Scalar::BigInt64 || targetType == Scalar::BigUint64;
1273
1274 default:
1275 MOZ_CRASH("IsTypedArrayBitwiseSlice with a bogus typed array type");
1276 }
1277 }
1278
intrinsic_TypedArrayBitwiseSlice(JSContext * cx,unsigned argc,Value * vp)1279 static bool intrinsic_TypedArrayBitwiseSlice(JSContext* cx, unsigned argc,
1280 Value* vp) {
1281 CallArgs args = CallArgsFromVp(argc, vp);
1282 MOZ_ASSERT(args.length() == 4);
1283 MOZ_ASSERT(args[0].isObject());
1284 MOZ_ASSERT(args[1].isObject());
1285 AssertNonNegativeInteger(args[2]);
1286 AssertNonNegativeInteger(args[3]);
1287
1288 Rooted<TypedArrayObject*> source(cx,
1289 &args[0].toObject().as<TypedArrayObject>());
1290 MOZ_ASSERT(!source->hasDetachedBuffer());
1291
1292 // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all
1293 // variables derived from it to counsel extreme caution here.
1294 Rooted<TypedArrayObject*> unsafeTypedArrayCrossCompartment(cx);
1295 unsafeTypedArrayCrossCompartment =
1296 DangerouslyUnwrapTypedArray(cx, &args[1].toObject());
1297 if (!unsafeTypedArrayCrossCompartment) {
1298 return false;
1299 }
1300 MOZ_ASSERT(!unsafeTypedArrayCrossCompartment->hasDetachedBuffer());
1301
1302 Scalar::Type sourceType = source->type();
1303 if (!IsTypedArrayBitwiseSlice(sourceType,
1304 unsafeTypedArrayCrossCompartment->type())) {
1305 args.rval().setBoolean(false);
1306 return true;
1307 }
1308
1309 size_t sourceOffset = size_t(args[2].toNumber());
1310 size_t count = size_t(args[3].toNumber());
1311
1312 MOZ_ASSERT(count > 0 && count <= source->length());
1313 MOZ_ASSERT(sourceOffset <= source->length() - count);
1314 MOZ_ASSERT(count <= unsafeTypedArrayCrossCompartment->length());
1315
1316 size_t elementSize = TypedArrayElemSize(sourceType);
1317 MOZ_ASSERT(elementSize ==
1318 TypedArrayElemSize(unsafeTypedArrayCrossCompartment->type()));
1319
1320 SharedMem<uint8_t*> sourceData =
1321 source->dataPointerEither().cast<uint8_t*>() + sourceOffset * elementSize;
1322
1323 SharedMem<uint8_t*> unsafeTargetDataCrossCompartment =
1324 unsafeTypedArrayCrossCompartment->dataPointerEither().cast<uint8_t*>();
1325
1326 size_t byteLength = count * elementSize;
1327
1328 // The same-type case requires exact copying preserving the bit-level
1329 // encoding of the source data, so use memcpy if possible. If source and
1330 // target are the same buffer, we can't use memcpy (or memmove), because
1331 // the specification requires sequential copying of the values. This case
1332 // is only possible if a @@species constructor created a specifically
1333 // crafted typed array. It won't happen in normal code and hence doesn't
1334 // need to be optimized.
1335 if (!TypedArrayObject::sameBuffer(source, unsafeTypedArrayCrossCompartment)) {
1336 if (source->isSharedMemory() ||
1337 unsafeTypedArrayCrossCompartment->isSharedMemory()) {
1338 jit::AtomicOperations::memcpySafeWhenRacy(
1339 unsafeTargetDataCrossCompartment, sourceData, byteLength);
1340 } else {
1341 memcpy(unsafeTargetDataCrossCompartment.unwrapUnshared(),
1342 sourceData.unwrapUnshared(), byteLength);
1343 }
1344 } else {
1345 using namespace jit;
1346
1347 for (; byteLength > 0; byteLength--) {
1348 AtomicOperations::storeSafeWhenRacy(
1349 unsafeTargetDataCrossCompartment++,
1350 AtomicOperations::loadSafeWhenRacy(sourceData++));
1351 }
1352 }
1353
1354 args.rval().setBoolean(true);
1355 return true;
1356 }
1357
intrinsic_TypedArrayInitFromPackedArray(JSContext * cx,unsigned argc,Value * vp)1358 static bool intrinsic_TypedArrayInitFromPackedArray(JSContext* cx,
1359 unsigned argc, Value* vp) {
1360 CallArgs args = CallArgsFromVp(argc, vp);
1361 MOZ_ASSERT(args.length() == 2);
1362 MOZ_ASSERT(args[0].isObject());
1363 MOZ_ASSERT(args[1].isObject());
1364
1365 Rooted<TypedArrayObject*> target(cx,
1366 &args[0].toObject().as<TypedArrayObject>());
1367 MOZ_ASSERT(!target->hasDetachedBuffer());
1368 MOZ_ASSERT(!target->isSharedMemory());
1369
1370 RootedArrayObject source(cx, &args[1].toObject().as<ArrayObject>());
1371 MOZ_ASSERT(IsPackedArray(source));
1372 MOZ_ASSERT(source->length() == target->length());
1373
1374 switch (target->type()) {
1375 #define INIT_TYPED_ARRAY(T, N) \
1376 case Scalar::N: { \
1377 if (!ElementSpecific<T, UnsharedOps>::initFromIterablePackedArray( \
1378 cx, target, source)) { \
1379 return false; \
1380 } \
1381 break; \
1382 }
1383 JS_FOR_EACH_TYPED_ARRAY(INIT_TYPED_ARRAY)
1384 #undef INIT_TYPED_ARRAY
1385
1386 default:
1387 MOZ_CRASH(
1388 "TypedArrayInitFromPackedArray with a typed array with bogus type");
1389 }
1390
1391 args.rval().setUndefined();
1392 return true;
1393 }
1394
intrinsic_RegExpCreate(JSContext * cx,unsigned argc,Value * vp)1395 static bool intrinsic_RegExpCreate(JSContext* cx, unsigned argc, Value* vp) {
1396 CallArgs args = CallArgsFromVp(argc, vp);
1397
1398 MOZ_ASSERT(args.length() == 1 || args.length() == 2);
1399 MOZ_ASSERT_IF(args.length() == 2,
1400 args[1].isString() || args[1].isUndefined());
1401 MOZ_ASSERT(!args.isConstructing());
1402
1403 return RegExpCreate(cx, args[0], args.get(1), args.rval());
1404 }
1405
intrinsic_RegExpGetSubstitution(JSContext * cx,unsigned argc,Value * vp)1406 static bool intrinsic_RegExpGetSubstitution(JSContext* cx, unsigned argc,
1407 Value* vp) {
1408 CallArgs args = CallArgsFromVp(argc, vp);
1409 MOZ_ASSERT(args.length() == 6);
1410
1411 RootedArrayObject matchResult(cx, &args[0].toObject().as<ArrayObject>());
1412
1413 RootedLinearString string(cx, args[1].toString()->ensureLinear(cx));
1414 if (!string) {
1415 return false;
1416 }
1417
1418 int32_t position = int32_t(args[2].toNumber());
1419 MOZ_ASSERT(position >= 0);
1420
1421 RootedLinearString replacement(cx, args[3].toString()->ensureLinear(cx));
1422 if (!replacement) {
1423 return false;
1424 }
1425
1426 int32_t firstDollarIndex = int32_t(args[4].toNumber());
1427 MOZ_ASSERT(firstDollarIndex >= 0);
1428
1429 RootedValue namedCaptures(cx, args[5]);
1430 MOZ_ASSERT(namedCaptures.isUndefined() || namedCaptures.isObject());
1431
1432 return RegExpGetSubstitution(cx, matchResult, string, size_t(position),
1433 replacement, size_t(firstDollarIndex),
1434 namedCaptures, args.rval());
1435 }
1436
intrinsic_StringReplaceString(JSContext * cx,unsigned argc,Value * vp)1437 static bool intrinsic_StringReplaceString(JSContext* cx, unsigned argc,
1438 Value* vp) {
1439 CallArgs args = CallArgsFromVp(argc, vp);
1440 MOZ_ASSERT(args.length() == 3);
1441
1442 RootedString string(cx, args[0].toString());
1443 RootedString pattern(cx, args[1].toString());
1444 RootedString replacement(cx, args[2].toString());
1445 JSString* result = str_replace_string_raw(cx, string, pattern, replacement);
1446 if (!result) {
1447 return false;
1448 }
1449
1450 args.rval().setString(result);
1451 return true;
1452 }
1453
intrinsic_StringReplaceAllString(JSContext * cx,unsigned argc,Value * vp)1454 static bool intrinsic_StringReplaceAllString(JSContext* cx, unsigned argc,
1455 Value* vp) {
1456 CallArgs args = CallArgsFromVp(argc, vp);
1457 MOZ_ASSERT(args.length() == 3);
1458
1459 RootedString string(cx, args[0].toString());
1460 RootedString pattern(cx, args[1].toString());
1461 RootedString replacement(cx, args[2].toString());
1462 JSString* result =
1463 str_replaceAll_string_raw(cx, string, pattern, replacement);
1464 if (!result) {
1465 return false;
1466 }
1467
1468 args.rval().setString(result);
1469 return true;
1470 }
1471
intrinsic_StringSplitString(JSContext * cx,unsigned argc,Value * vp)1472 static bool intrinsic_StringSplitString(JSContext* cx, unsigned argc,
1473 Value* vp) {
1474 CallArgs args = CallArgsFromVp(argc, vp);
1475 MOZ_ASSERT(args.length() == 2);
1476
1477 RootedString string(cx, args[0].toString());
1478 RootedString sep(cx, args[1].toString());
1479
1480 JSObject* aobj = StringSplitString(cx, string, sep, INT32_MAX);
1481 if (!aobj) {
1482 return false;
1483 }
1484
1485 args.rval().setObject(*aobj);
1486 return true;
1487 }
1488
intrinsic_StringSplitStringLimit(JSContext * cx,unsigned argc,Value * vp)1489 static bool intrinsic_StringSplitStringLimit(JSContext* cx, unsigned argc,
1490 Value* vp) {
1491 CallArgs args = CallArgsFromVp(argc, vp);
1492 MOZ_ASSERT(args.length() == 3);
1493
1494 RootedString string(cx, args[0].toString());
1495 RootedString sep(cx, args[1].toString());
1496
1497 // args[2] should be already in UInt32 range, but it could be double typed,
1498 // because of Ion optimization.
1499 uint32_t limit = uint32_t(args[2].toNumber());
1500 MOZ_ASSERT(limit > 0,
1501 "Zero limit case is already handled in self-hosted code.");
1502
1503 JSObject* aobj = StringSplitString(cx, string, sep, limit);
1504 if (!aobj) {
1505 return false;
1506 }
1507
1508 args.rval().setObject(*aobj);
1509 return true;
1510 }
1511
CallSelfHostedNonGenericMethod(JSContext * cx,const CallArgs & args)1512 bool CallSelfHostedNonGenericMethod(JSContext* cx, const CallArgs& args) {
1513 // This function is called when a self-hosted method is invoked on a
1514 // wrapper object, like a CrossCompartmentWrapper. The last argument is
1515 // the name of the self-hosted function. The other arguments are the
1516 // arguments to pass to this function.
1517
1518 MOZ_ASSERT(args.length() > 0);
1519 RootedPropertyName name(
1520 cx, args[args.length() - 1].toString()->asAtom().asPropertyName());
1521
1522 InvokeArgs args2(cx);
1523 if (!args2.init(cx, args.length() - 1)) {
1524 return false;
1525 }
1526
1527 for (size_t i = 0; i < args.length() - 1; i++) {
1528 args2[i].set(args[i]);
1529 }
1530
1531 return CallSelfHostedFunction(cx, name, args.thisv(), args2, args.rval());
1532 }
1533
1534 #ifdef DEBUG
CallSelfHostedFunction(JSContext * cx,const char * name,HandleValue thisv,const AnyInvokeArgs & args,MutableHandleValue rval)1535 bool js::CallSelfHostedFunction(JSContext* cx, const char* name,
1536 HandleValue thisv, const AnyInvokeArgs& args,
1537 MutableHandleValue rval) {
1538 JSAtom* funAtom = Atomize(cx, name, strlen(name));
1539 if (!funAtom) {
1540 return false;
1541 }
1542 RootedPropertyName funName(cx, funAtom->asPropertyName());
1543 return CallSelfHostedFunction(cx, funName, thisv, args, rval);
1544 }
1545 #endif
1546
CallSelfHostedFunction(JSContext * cx,HandlePropertyName name,HandleValue thisv,const AnyInvokeArgs & args,MutableHandleValue rval)1547 bool js::CallSelfHostedFunction(JSContext* cx, HandlePropertyName name,
1548 HandleValue thisv, const AnyInvokeArgs& args,
1549 MutableHandleValue rval) {
1550 RootedValue fun(cx);
1551 if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &fun)) {
1552 return false;
1553 }
1554 MOZ_ASSERT(fun.toObject().is<JSFunction>());
1555
1556 return Call(cx, fun, thisv, args, rval);
1557 }
1558
1559 template <typename T>
Is(HandleValue v)1560 bool Is(HandleValue v) {
1561 return v.isObject() && v.toObject().is<T>();
1562 }
1563
1564 template <IsAcceptableThis Test>
CallNonGenericSelfhostedMethod(JSContext * cx,unsigned argc,Value * vp)1565 static bool CallNonGenericSelfhostedMethod(JSContext* cx, unsigned argc,
1566 Value* vp) {
1567 CallArgs args = CallArgsFromVp(argc, vp);
1568 return CallNonGenericMethod<Test, CallSelfHostedNonGenericMethod>(cx, args);
1569 }
1570
IsCallSelfHostedNonGenericMethod(NativeImpl impl)1571 bool js::IsCallSelfHostedNonGenericMethod(NativeImpl impl) {
1572 return impl == CallSelfHostedNonGenericMethod;
1573 }
1574
ReportIncompatibleSelfHostedMethod(JSContext * cx,const CallArgs & args)1575 bool js::ReportIncompatibleSelfHostedMethod(JSContext* cx,
1576 const CallArgs& args) {
1577 // The contract for this function is the same as
1578 // CallSelfHostedNonGenericMethod. The normal ReportIncompatible function
1579 // doesn't work for selfhosted functions, because they always call the
1580 // different CallXXXMethodIfWrapped methods, which would be reported as the
1581 // called function instead.
1582
1583 // Lookup the selfhosted method that was invoked. But skip over
1584 // internal self-hosted function frames, because those are never the
1585 // actual self-hosted callee from external code. We can't just skip
1586 // self-hosted things until we find a non-self-hosted one because of cases
1587 // like array.sort(somethingSelfHosted), where we want to report the error
1588 // in the somethingSelfHosted, not in the sort() call.
1589
1590 static const char* const internalNames[] = {
1591 "IsTypedArrayEnsuringArrayBuffer",
1592 "UnwrapAndCallRegExpBuiltinExec",
1593 "RegExpBuiltinExec",
1594 "RegExpExec",
1595 "RegExpSearchSlowPath",
1596 "RegExpReplaceSlowPath",
1597 "RegExpMatchSlowPath",
1598 };
1599
1600 ScriptFrameIter iter(cx);
1601 MOZ_ASSERT(iter.isFunctionFrame());
1602
1603 while (!iter.done()) {
1604 MOZ_ASSERT(iter.callee(cx)->isSelfHostedOrIntrinsic() &&
1605 !iter.callee(cx)->isBoundFunction());
1606 UniqueChars funNameBytes;
1607 const char* funName =
1608 GetFunctionNameBytes(cx, iter.callee(cx), &funNameBytes);
1609 if (!funName) {
1610 return false;
1611 }
1612 if (std::all_of(
1613 std::begin(internalNames), std::end(internalNames),
1614 [funName](auto* name) { return strcmp(funName, name) != 0; })) {
1615 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
1616 JSMSG_INCOMPATIBLE_METHOD, funName, "method",
1617 InformalValueTypeName(args.thisv()));
1618 return false;
1619 }
1620 ++iter;
1621 }
1622
1623 MOZ_ASSERT_UNREACHABLE("How did we not find a useful self-hosted frame?");
1624 return false;
1625 }
1626
1627 #ifdef JS_HAS_INTL_API
1628 /**
1629 * Returns the default locale as a well-formed, but not necessarily
1630 * canonicalized, BCP-47 language tag.
1631 */
intrinsic_RuntimeDefaultLocale(JSContext * cx,unsigned argc,Value * vp)1632 static bool intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc,
1633 Value* vp) {
1634 CallArgs args = CallArgsFromVp(argc, vp);
1635 MOZ_ASSERT(args.length() == 0);
1636
1637 const char* locale = cx->runtime()->getDefaultLocale();
1638 if (!locale) {
1639 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1640 JSMSG_DEFAULT_LOCALE_ERROR);
1641 return false;
1642 }
1643
1644 JSString* jslocale = NewStringCopyZ<CanGC>(cx, locale);
1645 if (!jslocale) {
1646 return false;
1647 }
1648
1649 args.rval().setString(jslocale);
1650 return true;
1651 }
1652
intrinsic_IsRuntimeDefaultLocale(JSContext * cx,unsigned argc,Value * vp)1653 static bool intrinsic_IsRuntimeDefaultLocale(JSContext* cx, unsigned argc,
1654 Value* vp) {
1655 CallArgs args = CallArgsFromVp(argc, vp);
1656 MOZ_ASSERT(args.length() == 1);
1657 MOZ_ASSERT(args[0].isString() || args[0].isUndefined());
1658
1659 // |undefined| is the default value when the Intl runtime caches haven't
1660 // yet been initialized. Handle it the same way as a cache miss.
1661 if (args[0].isUndefined()) {
1662 args.rval().setBoolean(false);
1663 return true;
1664 }
1665
1666 const char* locale = cx->runtime()->getDefaultLocale();
1667 if (!locale) {
1668 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1669 JSMSG_DEFAULT_LOCALE_ERROR);
1670 return false;
1671 }
1672
1673 JSLinearString* str = args[0].toString()->ensureLinear(cx);
1674 if (!str) {
1675 return false;
1676 }
1677
1678 bool equals = StringEqualsAscii(str, locale);
1679 args.rval().setBoolean(equals);
1680 return true;
1681 }
1682 #endif // JS_HAS_INTL_API
1683
intrinsic_ThrowArgTypeNotObject(JSContext * cx,unsigned argc,Value * vp)1684 static bool intrinsic_ThrowArgTypeNotObject(JSContext* cx, unsigned argc,
1685 Value* vp) {
1686 CallArgs args = CallArgsFromVp(argc, vp);
1687 MOZ_ASSERT(args.length() == 2);
1688 MOZ_ASSERT(args[0].isNumber());
1689 MOZ_ASSERT(!args[1].isObject());
1690 if (args[0].toNumber() == NOT_OBJECT_KIND_DESCRIPTOR) {
1691 ReportNotObject(cx, JSMSG_OBJECT_REQUIRED_PROP_DESC, args[1]);
1692 } else {
1693 MOZ_CRASH("unexpected kind");
1694 }
1695
1696 return false;
1697 }
1698
intrinsic_ConstructFunction(JSContext * cx,unsigned argc,Value * vp)1699 static bool intrinsic_ConstructFunction(JSContext* cx, unsigned argc,
1700 Value* vp) {
1701 CallArgs args = CallArgsFromVp(argc, vp);
1702 MOZ_ASSERT(args.length() == 3);
1703 MOZ_ASSERT(IsConstructor(args[0]));
1704 MOZ_ASSERT(IsConstructor(args[1]));
1705 MOZ_ASSERT(args[2].toObject().is<ArrayObject>());
1706
1707 RootedArrayObject argsList(cx, &args[2].toObject().as<ArrayObject>());
1708 uint32_t len = argsList->length();
1709 ConstructArgs constructArgs(cx);
1710 if (!constructArgs.init(cx, len)) {
1711 return false;
1712 }
1713 for (uint32_t index = 0; index < len; index++) {
1714 constructArgs[index].set(argsList->getDenseElement(index));
1715 }
1716
1717 RootedObject res(cx);
1718 if (!Construct(cx, args[0], constructArgs, args[1], &res)) {
1719 return false;
1720 }
1721
1722 args.rval().setObject(*res);
1723 return true;
1724 }
1725
intrinsic_IsConstructing(JSContext * cx,unsigned argc,Value * vp)1726 static bool intrinsic_IsConstructing(JSContext* cx, unsigned argc, Value* vp) {
1727 CallArgs args = CallArgsFromVp(argc, vp);
1728 MOZ_ASSERT(args.length() == 0);
1729
1730 ScriptFrameIter iter(cx);
1731 bool isConstructing = iter.isConstructing();
1732 args.rval().setBoolean(isConstructing);
1733 return true;
1734 }
1735
intrinsic_ConstructorForTypedArray(JSContext * cx,unsigned argc,Value * vp)1736 static bool intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc,
1737 Value* vp) {
1738 CallArgs args = CallArgsFromVp(argc, vp);
1739 MOZ_ASSERT(args.length() == 1);
1740 MOZ_ASSERT(args[0].isObject());
1741
1742 auto* object = UnwrapAndDowncastValue<TypedArrayObject>(cx, args[0]);
1743 if (!object) {
1744 return false;
1745 }
1746
1747 JSProtoKey protoKey = StandardProtoKeyOrNull(object);
1748 MOZ_ASSERT(protoKey);
1749
1750 // While it may seem like an invariant that in any compartment,
1751 // seeing a typed array object implies that the TypedArray constructor
1752 // for that type is initialized on the compartment's global, this is not
1753 // the case. When we construct a typed array given a cross-compartment
1754 // ArrayBuffer, we put the constructed TypedArray in the same compartment
1755 // as the ArrayBuffer. Since we use the prototype from the initial
1756 // compartment, and never call the constructor in the ArrayBuffer's
1757 // compartment from script, we are not guaranteed to have initialized
1758 // the constructor.
1759 JSObject* ctor = GlobalObject::getOrCreateConstructor(cx, protoKey);
1760 if (!ctor) {
1761 return false;
1762 }
1763
1764 args.rval().setObject(*ctor);
1765 return true;
1766 }
1767
intrinsic_HostResolveImportedModule(JSContext * cx,unsigned argc,Value * vp)1768 static bool intrinsic_HostResolveImportedModule(JSContext* cx, unsigned argc,
1769 Value* vp) {
1770 CallArgs args = CallArgsFromVp(argc, vp);
1771 MOZ_ASSERT(args.length() == 2);
1772 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1773 RootedObject moduleRequest(cx, &args[1].toObject());
1774
1775 RootedValue referencingPrivate(cx, JS::GetModulePrivate(module));
1776 RootedObject result(
1777 cx, CallModuleResolveHook(cx, referencingPrivate, moduleRequest));
1778 if (!result) {
1779 return false;
1780 }
1781
1782 if (!result->is<ModuleObject>()) {
1783 JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
1784 return false;
1785 }
1786
1787 args.rval().setObject(*result);
1788 return true;
1789 }
1790
intrinsic_CreateImportBinding(JSContext * cx,unsigned argc,Value * vp)1791 static bool intrinsic_CreateImportBinding(JSContext* cx, unsigned argc,
1792 Value* vp) {
1793 CallArgs args = CallArgsFromVp(argc, vp);
1794 MOZ_ASSERT(args.length() == 4);
1795 RootedModuleEnvironmentObject environment(
1796 cx, &args[0].toObject().as<ModuleEnvironmentObject>());
1797 RootedAtom importedName(cx, &args[1].toString()->asAtom());
1798 RootedModuleObject module(cx, &args[2].toObject().as<ModuleObject>());
1799 RootedAtom localName(cx, &args[3].toString()->asAtom());
1800 if (!environment->createImportBinding(cx, importedName, module, localName)) {
1801 return false;
1802 }
1803
1804 args.rval().setUndefined();
1805 return true;
1806 }
1807
intrinsic_CreateNamespaceBinding(JSContext * cx,unsigned argc,Value * vp)1808 static bool intrinsic_CreateNamespaceBinding(JSContext* cx, unsigned argc,
1809 Value* vp) {
1810 CallArgs args = CallArgsFromVp(argc, vp);
1811 MOZ_ASSERT(args.length() == 3);
1812 RootedModuleEnvironmentObject environment(
1813 cx, &args[0].toObject().as<ModuleEnvironmentObject>());
1814 RootedId name(cx, AtomToId(&args[1].toString()->asAtom()));
1815 MOZ_ASSERT(args[2].toObject().is<ModuleNamespaceObject>());
1816 // The property already exists in the evironment but is not writable, so set
1817 // the slot directly.
1818 mozilla::Maybe<PropertyInfo> prop = environment->lookup(cx, name);
1819 MOZ_ASSERT(prop.isSome());
1820 environment->setSlot(prop->slot(), args[2]);
1821 args.rval().setUndefined();
1822 return true;
1823 }
1824
intrinsic_EnsureModuleEnvironmentNamespace(JSContext * cx,unsigned argc,Value * vp)1825 static bool intrinsic_EnsureModuleEnvironmentNamespace(JSContext* cx,
1826 unsigned argc,
1827 Value* vp) {
1828 CallArgs args = CallArgsFromVp(argc, vp);
1829 MOZ_ASSERT(args.length() == 2);
1830 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1831 MOZ_ASSERT(args[1].toObject().is<ModuleNamespaceObject>());
1832 RootedModuleEnvironmentObject environment(cx, &module->initialEnvironment());
1833 // The property already exists in the evironment but is not writable, so set
1834 // the slot directly.
1835 mozilla::Maybe<PropertyInfo> prop =
1836 environment->lookup(cx, cx->names().starNamespaceStar);
1837 MOZ_ASSERT(prop.isSome());
1838 environment->setSlot(prop->slot(), args[1]);
1839 args.rval().setUndefined();
1840 return true;
1841 }
1842
intrinsic_InstantiateModuleFunctionDeclarations(JSContext * cx,unsigned argc,Value * vp)1843 static bool intrinsic_InstantiateModuleFunctionDeclarations(JSContext* cx,
1844 unsigned argc,
1845 Value* vp) {
1846 CallArgs args = CallArgsFromVp(argc, vp);
1847 MOZ_ASSERT(args.length() == 1);
1848 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1849 args.rval().setUndefined();
1850 return ModuleObject::instantiateFunctionDeclarations(cx, module);
1851 }
1852
intrinsic_ExecuteModule(JSContext * cx,unsigned argc,Value * vp)1853 static bool intrinsic_ExecuteModule(JSContext* cx, unsigned argc, Value* vp) {
1854 CallArgs args = CallArgsFromVp(argc, vp);
1855 MOZ_ASSERT(args.length() == 1);
1856 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1857 return ModuleObject::execute(cx, module, args.rval());
1858 }
1859
intrinsic_IsTopLevelAwaitEnabled(JSContext * cx,unsigned argc,Value * vp)1860 static bool intrinsic_IsTopLevelAwaitEnabled(JSContext* cx, unsigned argc,
1861 Value* vp) {
1862 CallArgs args = CallArgsFromVp(argc, vp);
1863 MOZ_ASSERT(args.length() == 0);
1864 bool topLevelAwait = cx->options().topLevelAwait();
1865 args.rval().setBoolean(topLevelAwait);
1866 return true;
1867 }
1868
intrinsic_SetCycleRoot(JSContext * cx,unsigned argc,Value * vp)1869 static bool intrinsic_SetCycleRoot(JSContext* cx, unsigned argc, Value* vp) {
1870 CallArgs args = CallArgsFromVp(argc, vp);
1871 MOZ_ASSERT(args.length() == 2);
1872 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1873 RootedModuleObject cycleRoot(cx, &args[1].toObject().as<ModuleObject>());
1874 module->setCycleRoot(cycleRoot);
1875 args.rval().setUndefined();
1876 return true;
1877 }
1878
intrinsic_GetCycleRoot(JSContext * cx,unsigned argc,Value * vp)1879 static bool intrinsic_GetCycleRoot(JSContext* cx, unsigned argc, Value* vp) {
1880 CallArgs args = CallArgsFromVp(argc, vp);
1881 MOZ_ASSERT(args.length() == 1);
1882 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1883 JSObject* result = module->getCycleRoot();
1884 if (!result) {
1885 return false;
1886 }
1887 args.rval().setObject(*result);
1888 return true;
1889 }
1890
intrinsic_AppendAsyncParentModule(JSContext * cx,unsigned argc,Value * vp)1891 static bool intrinsic_AppendAsyncParentModule(JSContext* cx, unsigned argc,
1892 Value* vp) {
1893 CallArgs args = CallArgsFromVp(argc, vp);
1894 MOZ_ASSERT(args.length() == 2);
1895 RootedModuleObject self(cx, &args[0].toObject().as<ModuleObject>());
1896 RootedModuleObject parent(cx, &args[1].toObject().as<ModuleObject>());
1897 return ModuleObject::appendAsyncParentModule(cx, self, parent);
1898 }
1899
intrinsic_InitAsyncEvaluating(JSContext * cx,unsigned argc,Value * vp)1900 static bool intrinsic_InitAsyncEvaluating(JSContext* cx, unsigned argc,
1901 Value* vp) {
1902 CallArgs args = CallArgsFromVp(argc, vp);
1903 MOZ_ASSERT(args.length() == 1);
1904 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1905 if (!module->initAsyncEvaluatingSlot()) {
1906 return false;
1907 }
1908 args.rval().setUndefined();
1909 return true;
1910 }
1911
intrinsic_IsAsyncEvaluating(JSContext * cx,unsigned argc,Value * vp)1912 static bool intrinsic_IsAsyncEvaluating(JSContext* cx, unsigned argc,
1913 Value* vp) {
1914 CallArgs args = CallArgsFromVp(argc, vp);
1915 MOZ_ASSERT(args.length() == 1);
1916 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1917 bool isAsyncEvaluating = module->isAsyncEvaluating();
1918 args.rval().setBoolean(isAsyncEvaluating);
1919 return true;
1920 }
1921
intrinsic_CreateTopLevelCapability(JSContext * cx,unsigned argc,Value * vp)1922 static bool intrinsic_CreateTopLevelCapability(JSContext* cx, unsigned argc,
1923 Value* vp) {
1924 CallArgs args = CallArgsFromVp(argc, vp);
1925 MOZ_ASSERT(args.length() == 1);
1926 RootedModuleObject self(cx, &args[0].toObject().as<ModuleObject>());
1927 PromiseObject* result = ModuleObject::createTopLevelCapability(cx, self);
1928 if (!result) {
1929 return false;
1930 }
1931 args.rval().setObject(*result);
1932 return true;
1933 }
1934
intrinsic_ModuleTopLevelCapabilityResolve(JSContext * cx,unsigned argc,Value * vp)1935 static bool intrinsic_ModuleTopLevelCapabilityResolve(JSContext* cx,
1936 unsigned argc,
1937 Value* vp) {
1938 CallArgs args = CallArgsFromVp(argc, vp);
1939 MOZ_ASSERT(args.length() == 1);
1940 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1941 ModuleObject::topLevelCapabilityResolve(cx, module);
1942 args.rval().setUndefined();
1943 return true;
1944 }
1945
intrinsic_ModuleTopLevelCapabilityReject(JSContext * cx,unsigned argc,Value * vp)1946 static bool intrinsic_ModuleTopLevelCapabilityReject(JSContext* cx,
1947 unsigned argc, Value* vp) {
1948 CallArgs args = CallArgsFromVp(argc, vp);
1949 MOZ_ASSERT(args.length() == 2);
1950 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1951 HandleValue error = args[1];
1952 ModuleObject::topLevelCapabilityReject(cx, module, error);
1953 args.rval().setUndefined();
1954 return true;
1955 }
1956
intrinsic_NewModuleNamespace(JSContext * cx,unsigned argc,Value * vp)1957 static bool intrinsic_NewModuleNamespace(JSContext* cx, unsigned argc,
1958 Value* vp) {
1959 CallArgs args = CallArgsFromVp(argc, vp);
1960 MOZ_ASSERT(args.length() == 2);
1961 RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
1962 RootedObject exports(cx, &args[1].toObject());
1963 JSObject* namespace_ = ModuleObject::createNamespace(cx, module, exports);
1964 if (!namespace_) {
1965 return false;
1966 }
1967
1968 args.rval().setObject(*namespace_);
1969 return true;
1970 }
1971
intrinsic_AddModuleNamespaceBinding(JSContext * cx,unsigned argc,Value * vp)1972 static bool intrinsic_AddModuleNamespaceBinding(JSContext* cx, unsigned argc,
1973 Value* vp) {
1974 CallArgs args = CallArgsFromVp(argc, vp);
1975 MOZ_ASSERT(args.length() == 4);
1976 RootedModuleNamespaceObject namespace_(
1977 cx, &args[0].toObject().as<ModuleNamespaceObject>());
1978 RootedAtom exportedName(cx, &args[1].toString()->asAtom());
1979 RootedModuleObject targetModule(cx, &args[2].toObject().as<ModuleObject>());
1980 RootedAtom targetName(cx, &args[3].toString()->asAtom());
1981 if (!namespace_->addBinding(cx, exportedName, targetModule, targetName)) {
1982 return false;
1983 }
1984
1985 args.rval().setUndefined();
1986 return true;
1987 }
1988
intrinsic_PromiseResolve(JSContext * cx,unsigned argc,Value * vp)1989 static bool intrinsic_PromiseResolve(JSContext* cx, unsigned argc, Value* vp) {
1990 CallArgs args = CallArgsFromVp(argc, vp);
1991 MOZ_ASSERT(args.length() == 2);
1992
1993 RootedObject constructor(cx, &args[0].toObject());
1994 JSObject* promise = js::PromiseResolve(cx, constructor, args[1]);
1995 if (!promise) {
1996 return false;
1997 }
1998
1999 args.rval().setObject(*promise);
2000 return true;
2001 }
2002
intrinsic_CopyDataPropertiesOrGetOwnKeys(JSContext * cx,unsigned argc,Value * vp)2003 static bool intrinsic_CopyDataPropertiesOrGetOwnKeys(JSContext* cx,
2004 unsigned argc, Value* vp) {
2005 CallArgs args = CallArgsFromVp(argc, vp);
2006 MOZ_ASSERT(args.length() == 3);
2007 MOZ_ASSERT(args[0].isObject());
2008 MOZ_ASSERT(args[1].isObject());
2009 MOZ_ASSERT(args[2].isObjectOrNull());
2010
2011 RootedObject target(cx, &args[0].toObject());
2012 RootedObject from(cx, &args[1].toObject());
2013 RootedObject excludedItems(cx, args[2].toObjectOrNull());
2014
2015 if (from->is<NativeObject>() && target->is<PlainObject>() &&
2016 (!excludedItems || excludedItems->is<PlainObject>())) {
2017 bool optimized;
2018 if (!CopyDataPropertiesNative(
2019 cx, target.as<PlainObject>(), from.as<NativeObject>(),
2020 (excludedItems ? excludedItems.as<PlainObject>() : nullptr),
2021 &optimized)) {
2022 return false;
2023 }
2024
2025 if (optimized) {
2026 args.rval().setNull();
2027 return true;
2028 }
2029 }
2030
2031 return GetOwnPropertyKeys(
2032 cx, from, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, args.rval());
2033 }
2034
intrinsic_ToBigInt(JSContext * cx,unsigned argc,Value * vp)2035 static bool intrinsic_ToBigInt(JSContext* cx, unsigned argc, Value* vp) {
2036 CallArgs args = CallArgsFromVp(argc, vp);
2037 MOZ_ASSERT(args.length() == 1);
2038 BigInt* res = ToBigInt(cx, args[0]);
2039 if (!res) {
2040 return false;
2041 }
2042 args.rval().setBigInt(res);
2043 return true;
2044 }
2045
intrinsic_NewWrapForValidIterator(JSContext * cx,unsigned argc,Value * vp)2046 static bool intrinsic_NewWrapForValidIterator(JSContext* cx, unsigned argc,
2047 Value* vp) {
2048 CallArgs args = CallArgsFromVp(argc, vp);
2049 MOZ_ASSERT(args.length() == 0);
2050
2051 JSObject* obj = NewWrapForValidIterator(cx);
2052 if (!obj) {
2053 return false;
2054 }
2055
2056 args.rval().setObject(*obj);
2057 return true;
2058 }
2059
intrinsic_NewPrivateName(JSContext * cx,unsigned argc,Value * vp)2060 static bool intrinsic_NewPrivateName(JSContext* cx, unsigned argc, Value* vp) {
2061 CallArgs args = CallArgsFromVp(argc, vp);
2062 MOZ_ASSERT(args.length() == 1);
2063
2064 RootedString desc(cx, args[0].toString());
2065 auto* symbol = JS::Symbol::new_(cx, JS::SymbolCode::PrivateNameSymbol, desc);
2066 if (!symbol) {
2067 return false;
2068 }
2069 args.rval().setSymbol(symbol);
2070 return true;
2071 }
2072
intrinsic_NewIteratorHelper(JSContext * cx,unsigned argc,Value * vp)2073 static bool intrinsic_NewIteratorHelper(JSContext* cx, unsigned argc,
2074 Value* vp) {
2075 CallArgs args = CallArgsFromVp(argc, vp);
2076 MOZ_ASSERT(args.length() == 0);
2077
2078 JSObject* obj = NewIteratorHelper(cx);
2079 if (!obj) {
2080 return false;
2081 }
2082
2083 args.rval().setObject(*obj);
2084 return true;
2085 }
2086
intrinsic_NewAsyncIteratorHelper(JSContext * cx,unsigned argc,Value * vp)2087 static bool intrinsic_NewAsyncIteratorHelper(JSContext* cx, unsigned argc,
2088 Value* vp) {
2089 CallArgs args = CallArgsFromVp(argc, vp);
2090 MOZ_ASSERT(args.length() == 0);
2091
2092 JSObject* obj = NewAsyncIteratorHelper(cx);
2093 if (!obj) {
2094 return false;
2095 }
2096
2097 args.rval().setObject(*obj);
2098 return true;
2099 }
2100
intrinsic_NoPrivateGetter(JSContext * cx,unsigned argc,Value * vp)2101 static bool intrinsic_NoPrivateGetter(JSContext* cx, unsigned argc, Value* vp) {
2102 CallArgs args = CallArgsFromVp(argc, vp);
2103 MOZ_ASSERT(args.length() == 0);
2104
2105 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
2106 JSMSG_PRIVATE_SETTER_ONLY);
2107
2108 args.rval().setUndefined();
2109 return false;
2110 }
2111
2112 static const JSFunctionSpec intrinsic_functions[] = {
2113 // Intrinsic helper functions
2114 JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4,
2115 0),
2116 JS_FN("AppendAsyncParentModule", intrinsic_AppendAsyncParentModule, 2, 0),
2117 JS_INLINABLE_FN("ArrayBufferByteLength",
2118 intrinsic_ArrayBufferByteLength<ArrayBufferObject>, 1, 0,
2119 IntrinsicArrayBufferByteLength),
2120 JS_FN("ArrayBufferCopyData",
2121 intrinsic_ArrayBufferCopyData<ArrayBufferObject>, 6, 0),
2122 JS_INLINABLE_FN("ArrayIteratorPrototypeOptimizable",
2123 intrinsic_ArrayIteratorPrototypeOptimizable, 0, 0,
2124 IntrinsicArrayIteratorPrototypeOptimizable),
2125 JS_FN("ArrayNativeSort", intrinsic_ArrayNativeSort, 1, 0),
2126 JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1, 0),
2127 JS_FN("CallArrayBufferMethodIfWrapped",
2128 CallNonGenericSelfhostedMethod<Is<ArrayBufferObject>>, 2, 0),
2129 JS_FN("CallArrayIteratorMethodIfWrapped",
2130 CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2, 0),
2131 JS_FN("CallAsyncIteratorHelperMethodIfWrapped",
2132 CallNonGenericSelfhostedMethod<Is<AsyncIteratorHelperObject>>, 2, 0),
2133 JS_FN("CallGeneratorMethodIfWrapped",
2134 CallNonGenericSelfhostedMethod<Is<GeneratorObject>>, 2, 0),
2135 JS_FN("CallIteratorHelperMethodIfWrapped",
2136 CallNonGenericSelfhostedMethod<Is<IteratorHelperObject>>, 2, 0),
2137 JS_FN("CallMapIteratorMethodIfWrapped",
2138 CallNonGenericSelfhostedMethod<Is<MapIteratorObject>>, 2, 0),
2139 JS_FN("CallMapMethodIfWrapped",
2140 CallNonGenericSelfhostedMethod<Is<MapObject>>, 2, 0),
2141 JS_FN("CallModuleMethodIfWrapped",
2142 CallNonGenericSelfhostedMethod<Is<ModuleObject>>, 2, 0),
2143 JS_FN("CallRegExpMethodIfWrapped",
2144 CallNonGenericSelfhostedMethod<Is<RegExpObject>>, 2, 0),
2145 JS_FN("CallRegExpStringIteratorMethodIfWrapped",
2146 CallNonGenericSelfhostedMethod<Is<RegExpStringIteratorObject>>, 2, 0),
2147 JS_FN("CallSetIteratorMethodIfWrapped",
2148 CallNonGenericSelfhostedMethod<Is<SetIteratorObject>>, 2, 0),
2149 JS_FN("CallSetMethodIfWrapped",
2150 CallNonGenericSelfhostedMethod<Is<SetObject>>, 2, 0),
2151 JS_FN("CallSharedArrayBufferMethodIfWrapped",
2152 CallNonGenericSelfhostedMethod<Is<SharedArrayBufferObject>>, 2, 0),
2153 JS_FN("CallStringIteratorMethodIfWrapped",
2154 CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>, 2, 0),
2155 JS_FN("CallTypedArrayMethodIfWrapped",
2156 CallNonGenericSelfhostedMethod<Is<TypedArrayObject>>, 2, 0),
2157 JS_FN("CallWrapForValidIteratorMethodIfWrapped",
2158 CallNonGenericSelfhostedMethod<Is<WrapForValidIteratorObject>>, 2, 0),
2159 JS_FN("ConstructFunction", intrinsic_ConstructFunction, 2, 0),
2160 JS_FN("ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1, 0),
2161 JS_FN("CopyDataPropertiesOrGetOwnKeys",
2162 intrinsic_CopyDataPropertiesOrGetOwnKeys, 3, 0),
2163 JS_FN("CreateImportBinding", intrinsic_CreateImportBinding, 4, 0),
2164 JS_FN("CreateMapIterationResultPair",
2165 intrinsic_CreateMapIterationResultPair, 0, 0),
2166 JS_FN("CreateModuleSyntaxError", intrinsic_CreateModuleSyntaxError, 4, 0),
2167 JS_FN("CreateNamespaceBinding", intrinsic_CreateNamespaceBinding, 3, 0),
2168 JS_FN("CreateSetIterationResult", intrinsic_CreateSetIterationResult, 0, 0),
2169 JS_FN("CreateTopLevelCapability", intrinsic_CreateTopLevelCapability, 1, 0),
2170 JS_FN("DecompileArg", intrinsic_DecompileArg, 2, 0),
2171 JS_FN("DefineDataProperty", intrinsic_DefineDataProperty, 4, 0),
2172 JS_FN("DefineProperty", intrinsic_DefineProperty, 6, 0),
2173 JS_FN("DumpMessage", intrinsic_DumpMessage, 1, 0),
2174 JS_FN("EnsureModuleEnvironmentNamespace",
2175 intrinsic_EnsureModuleEnvironmentNamespace, 1, 0),
2176 JS_FN("ExecuteModule", intrinsic_ExecuteModule, 1, 0),
2177 JS_INLINABLE_FN("FinishBoundFunctionInit",
2178 intrinsic_FinishBoundFunctionInit, 3, 0,
2179 IntrinsicFinishBoundFunctionInit),
2180 JS_FN("FlatStringMatch", FlatStringMatch, 2, 0),
2181 JS_FN("FlatStringSearch", FlatStringSearch, 2, 0),
2182 JS_FN("GeneratorIsRunning", intrinsic_GeneratorIsRunning, 1, 0),
2183 JS_FN("GeneratorObjectIsClosed", intrinsic_GeneratorObjectIsClosed, 1, 0),
2184 JS_FN("GeneratorSetClosed", intrinsic_GeneratorSetClosed, 1, 0),
2185 JS_FN("GetCycleRoot", intrinsic_GetCycleRoot, 1, 0),
2186 JS_FN("GetElemBaseForLambda", intrinsic_GetElemBaseForLambda, 1, 0),
2187 JS_FN("GetErrorMessage", intrinsic_GetErrorMessage, 1, 0),
2188 JS_INLINABLE_FN("GetFirstDollarIndex", GetFirstDollarIndex, 1, 0,
2189 GetFirstDollarIndex),
2190 JS_INLINABLE_FN("GetNextMapEntryForIterator",
2191 intrinsic_GetNextMapEntryForIterator, 2, 0,
2192 IntrinsicGetNextMapEntryForIterator),
2193 JS_INLINABLE_FN("GetNextSetEntryForIterator",
2194 intrinsic_GetNextSetEntryForIterator, 2, 0,
2195 IntrinsicGetNextSetEntryForIterator),
2196 JS_FN("GetOwnPropertyDescriptorToArray", GetOwnPropertyDescriptorToArray, 2,
2197 0),
2198 JS_FN("GetStringDataProperty", intrinsic_GetStringDataProperty, 2, 0),
2199 JS_FN("GetTypedArrayKind", intrinsic_GetTypedArrayKind, 1, 0),
2200 JS_INLINABLE_FN("GuardToArrayBuffer",
2201 intrinsic_GuardToBuiltin<ArrayBufferObject>, 1, 0,
2202 IntrinsicGuardToArrayBuffer),
2203 JS_INLINABLE_FN("GuardToArrayIterator",
2204 intrinsic_GuardToBuiltin<ArrayIteratorObject>, 1, 0,
2205 IntrinsicGuardToArrayIterator),
2206 JS_INLINABLE_FN("GuardToAsyncIteratorHelper",
2207 intrinsic_GuardToBuiltin<AsyncIteratorHelperObject>, 1, 0,
2208 IntrinsicGuardToAsyncIteratorHelper),
2209 JS_INLINABLE_FN("GuardToIteratorHelper",
2210 intrinsic_GuardToBuiltin<IteratorHelperObject>, 1, 0,
2211 IntrinsicGuardToIteratorHelper),
2212 JS_INLINABLE_FN("GuardToMapIterator",
2213 intrinsic_GuardToBuiltin<MapIteratorObject>, 1, 0,
2214 IntrinsicGuardToMapIterator),
2215 JS_INLINABLE_FN("GuardToMapObject", intrinsic_GuardToBuiltin<MapObject>, 1,
2216 0, IntrinsicGuardToMapObject),
2217 JS_INLINABLE_FN("GuardToRegExpStringIterator",
2218 intrinsic_GuardToBuiltin<RegExpStringIteratorObject>, 1, 0,
2219 IntrinsicGuardToRegExpStringIterator),
2220 JS_INLINABLE_FN("GuardToSetIterator",
2221 intrinsic_GuardToBuiltin<SetIteratorObject>, 1, 0,
2222 IntrinsicGuardToSetIterator),
2223 JS_INLINABLE_FN("GuardToSetObject", intrinsic_GuardToBuiltin<SetObject>, 1,
2224 0, IntrinsicGuardToSetObject),
2225 JS_INLINABLE_FN("GuardToSharedArrayBuffer",
2226 intrinsic_GuardToBuiltin<SharedArrayBufferObject>, 1, 0,
2227 IntrinsicGuardToSharedArrayBuffer),
2228 JS_INLINABLE_FN("GuardToStringIterator",
2229 intrinsic_GuardToBuiltin<StringIteratorObject>, 1, 0,
2230 IntrinsicGuardToStringIterator),
2231 JS_INLINABLE_FN("GuardToWrapForValidIterator",
2232 intrinsic_GuardToBuiltin<WrapForValidIteratorObject>, 1, 0,
2233 IntrinsicGuardToWrapForValidIterator),
2234 JS_FN("HostResolveImportedModule", intrinsic_HostResolveImportedModule, 2,
2235 0),
2236 JS_FN("InitAsyncEvaluating", intrinsic_InitAsyncEvaluating, 1, 0),
2237 JS_FN("InstantiateModuleFunctionDeclarations",
2238 intrinsic_InstantiateModuleFunctionDeclarations, 1, 0),
2239 JS_FN("IntrinsicAsyncGeneratorNext", AsyncGeneratorNext, 1, 0),
2240 JS_FN("IntrinsicAsyncGeneratorReturn", AsyncGeneratorReturn, 1, 0),
2241 JS_FN("IntrinsicAsyncGeneratorThrow", AsyncGeneratorThrow, 1, 0),
2242 JS_INLINABLE_FN("IsArray", intrinsic_IsArray, 1, 0, ArrayIsArray),
2243 JS_FN("IsAsyncEvaluating", intrinsic_IsAsyncEvaluating, 1, 0),
2244 JS_FN("IsAsyncFunctionGeneratorObject",
2245 intrinsic_IsInstanceOfBuiltin<AsyncFunctionGeneratorObject>, 1, 0),
2246 JS_FN("IsAsyncGeneratorObject",
2247 intrinsic_IsInstanceOfBuiltin<AsyncGeneratorObject>, 1, 0),
2248 JS_INLINABLE_FN("IsCallable", intrinsic_IsCallable, 1, 0,
2249 IntrinsicIsCallable),
2250 JS_INLINABLE_FN("IsConstructing", intrinsic_IsConstructing, 0, 0,
2251 IntrinsicIsConstructing),
2252 JS_INLINABLE_FN("IsConstructor", intrinsic_IsConstructor, 1, 0,
2253 IntrinsicIsConstructor),
2254 JS_INLINABLE_FN("IsCrossRealmArrayConstructor",
2255 intrinsic_IsCrossRealmArrayConstructor, 1, 0,
2256 IntrinsicIsCrossRealmArrayConstructor),
2257 JS_FN("IsGeneratorObject", intrinsic_IsInstanceOfBuiltin<GeneratorObject>,
2258 1, 0),
2259 JS_FN("IsModule", intrinsic_IsInstanceOfBuiltin<ModuleObject>, 1, 0),
2260 JS_FN("IsModuleEnvironment",
2261 intrinsic_IsInstanceOfBuiltin<ModuleEnvironmentObject>, 1, 0),
2262 JS_INLINABLE_FN("IsObject", intrinsic_IsObject, 1, 0, IntrinsicIsObject),
2263 JS_INLINABLE_FN("IsPackedArray", intrinsic_IsPackedArray, 1, 0,
2264 IntrinsicIsPackedArray),
2265 JS_INLINABLE_FN("IsPossiblyWrappedRegExpObject",
2266 intrinsic_IsPossiblyWrappedInstanceOfBuiltin<RegExpObject>,
2267 1, 0, IsPossiblyWrappedRegExpObject),
2268 JS_INLINABLE_FN(
2269 "IsPossiblyWrappedTypedArray",
2270 intrinsic_IsPossiblyWrappedInstanceOfBuiltin<TypedArrayObject>, 1, 0,
2271 IntrinsicIsPossiblyWrappedTypedArray),
2272 JS_INLINABLE_FN("IsRegExpObject",
2273 intrinsic_IsInstanceOfBuiltin<RegExpObject>, 1, 0,
2274 IsRegExpObject),
2275 JS_INLINABLE_FN("IsSuspendedGenerator", intrinsic_IsSuspendedGenerator, 1,
2276 0, IntrinsicIsSuspendedGenerator),
2277 JS_FN("IsTopLevelAwaitEnabled", intrinsic_IsTopLevelAwaitEnabled, 0, 0),
2278 JS_INLINABLE_FN("IsTypedArray",
2279 intrinsic_IsInstanceOfBuiltin<TypedArrayObject>, 1, 0,
2280 IntrinsicIsTypedArray),
2281 JS_INLINABLE_FN("IsTypedArrayConstructor",
2282 intrinsic_IsTypedArrayConstructor, 1, 0,
2283 IntrinsicIsTypedArrayConstructor),
2284 JS_FN("IsWrappedArrayBuffer",
2285 intrinsic_IsWrappedInstanceOfBuiltin<ArrayBufferObject>, 1, 0),
2286 JS_FN("IsWrappedSharedArrayBuffer",
2287 intrinsic_IsWrappedInstanceOfBuiltin<SharedArrayBufferObject>, 1, 0),
2288 JS_FN("ModuleTopLevelCapabilityReject",
2289 intrinsic_ModuleTopLevelCapabilityReject, 2, 0),
2290 JS_FN("ModuleTopLevelCapabilityResolve",
2291 intrinsic_ModuleTopLevelCapabilityResolve, 1, 0),
2292 JS_INLINABLE_FN("NewArrayIterator", intrinsic_NewArrayIterator, 0, 0,
2293 IntrinsicNewArrayIterator),
2294 JS_FN("NewAsyncIteratorHelper", intrinsic_NewAsyncIteratorHelper, 0, 0),
2295 JS_FN("NewIteratorHelper", intrinsic_NewIteratorHelper, 0, 0),
2296 JS_FN("NewModuleNamespace", intrinsic_NewModuleNamespace, 2, 0),
2297 JS_FN("NewPrivateName", intrinsic_NewPrivateName, 1, 0),
2298 JS_INLINABLE_FN("NewRegExpStringIterator",
2299 intrinsic_NewRegExpStringIterator, 0, 0,
2300 IntrinsicNewRegExpStringIterator),
2301 JS_INLINABLE_FN("NewStringIterator", intrinsic_NewStringIterator, 0, 0,
2302 IntrinsicNewStringIterator),
2303 JS_FN("NewWrapForValidIterator", intrinsic_NewWrapForValidIterator, 0, 0),
2304 JS_FN("NoPrivateGetter", intrinsic_NoPrivateGetter, 1, 0),
2305 JS_INLINABLE_FN("ObjectHasPrototype", intrinsic_ObjectHasPrototype, 2, 0,
2306 IntrinsicObjectHasPrototype),
2307 JS_INLINABLE_FN(
2308 "PossiblyWrappedArrayBufferByteLength",
2309 intrinsic_PossiblyWrappedArrayBufferByteLength<ArrayBufferObject>, 1, 0,
2310 IntrinsicPossiblyWrappedArrayBufferByteLength),
2311 JS_FN(
2312 "PossiblyWrappedSharedArrayBufferByteLength",
2313 intrinsic_PossiblyWrappedArrayBufferByteLength<SharedArrayBufferObject>,
2314 1, 0),
2315 JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer",
2316 intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0),
2317 JS_INLINABLE_FN("PossiblyWrappedTypedArrayLength",
2318 intrinsic_PossiblyWrappedTypedArrayLength, 1, 0,
2319 IntrinsicPossiblyWrappedTypedArrayLength),
2320 JS_FN("PromiseResolve", intrinsic_PromiseResolve, 2, 0),
2321 JS_FN("RegExpConstructRaw", regexp_construct_raw_flags, 2, 0),
2322 JS_FN("RegExpCreate", intrinsic_RegExpCreate, 2, 0),
2323 JS_FN("RegExpGetSubstitution", intrinsic_RegExpGetSubstitution, 5, 0),
2324 JS_INLINABLE_FN("RegExpInstanceOptimizable", RegExpInstanceOptimizable, 1,
2325 0, RegExpInstanceOptimizable),
2326 JS_INLINABLE_FN("RegExpMatcher", RegExpMatcher, 3, 0, RegExpMatcher),
2327 JS_INLINABLE_FN("RegExpPrototypeOptimizable", RegExpPrototypeOptimizable, 1,
2328 0, RegExpPrototypeOptimizable),
2329 JS_INLINABLE_FN("RegExpSearcher", RegExpSearcher, 3, 0, RegExpSearcher),
2330 JS_INLINABLE_FN("RegExpTester", RegExpTester, 3, 0, RegExpTester),
2331 JS_INLINABLE_FN("SameValue", js::obj_is, 2, 0, ObjectIs),
2332 JS_FN("SetCycleRoot", intrinsic_SetCycleRoot, 2, 0),
2333 JS_FN("SharedArrayBufferByteLength",
2334 intrinsic_ArrayBufferByteLength<SharedArrayBufferObject>, 1, 0),
2335 JS_FN("SharedArrayBufferCopyData",
2336 intrinsic_ArrayBufferCopyData<SharedArrayBufferObject>, 6, 0),
2337 JS_FN("SharedArrayBuffersMemorySame",
2338 intrinsic_SharedArrayBuffersMemorySame, 2, 0),
2339 JS_FN("StringReplaceAllString", intrinsic_StringReplaceAllString, 3, 0),
2340 JS_INLINABLE_FN("StringReplaceString", intrinsic_StringReplaceString, 3, 0,
2341 IntrinsicStringReplaceString),
2342 JS_INLINABLE_FN("StringSplitString", intrinsic_StringSplitString, 2, 0,
2343 IntrinsicStringSplitString),
2344 JS_FN("StringSplitStringLimit", intrinsic_StringSplitStringLimit, 3, 0),
2345 JS_INLINABLE_FN("SubstringKernel", intrinsic_SubstringKernel, 3, 0,
2346 IntrinsicSubstringKernel),
2347 JS_FN("ThisNumberValueForToLocaleString", ThisNumberValueForToLocaleString,
2348 0, 0),
2349 JS_FN("ThisTimeValue", intrinsic_ThisTimeValue, 1, 0),
2350 JS_FN("ThrowAggregateError", intrinsic_ThrowAggregateError, 4, 0),
2351 JS_FN("ThrowArgTypeNotObject", intrinsic_ThrowArgTypeNotObject, 2, 0),
2352 JS_FN("ThrowInternalError", intrinsic_ThrowInternalError, 4, 0),
2353 JS_FN("ThrowRangeError", intrinsic_ThrowRangeError, 4, 0),
2354 JS_FN("ThrowSyntaxError", intrinsic_ThrowSyntaxError, 4, 0),
2355 JS_FN("ThrowTypeError", intrinsic_ThrowTypeError, 4, 0),
2356 JS_FN("ToBigInt", intrinsic_ToBigInt, 1, 0),
2357 JS_INLINABLE_FN("ToInteger", intrinsic_ToInteger, 1, 0, IntrinsicToInteger),
2358 JS_INLINABLE_FN("ToLength", intrinsic_ToLength, 1, 0, IntrinsicToLength),
2359 JS_INLINABLE_FN("ToObject", intrinsic_ToObject, 1, 0, IntrinsicToObject),
2360 JS_FN("ToPropertyKey", intrinsic_ToPropertyKey, 1, 0),
2361 JS_FN("ToSource", intrinsic_ToSource, 1, 0),
2362 JS_FN("TypedArrayBitwiseSlice", intrinsic_TypedArrayBitwiseSlice, 4, 0),
2363 JS_FN("TypedArrayBuffer", intrinsic_TypedArrayBuffer, 1, 0),
2364 JS_INLINABLE_FN("TypedArrayByteOffset", intrinsic_TypedArrayByteOffset, 1,
2365 0, IntrinsicTypedArrayByteOffset),
2366 JS_INLINABLE_FN("TypedArrayElementSize", intrinsic_TypedArrayElementSize, 1,
2367 0, IntrinsicTypedArrayElementSize),
2368 JS_FN("TypedArrayInitFromPackedArray",
2369 intrinsic_TypedArrayInitFromPackedArray, 2, 0),
2370 JS_INLINABLE_FN("TypedArrayLength", intrinsic_TypedArrayLength, 1, 0,
2371 IntrinsicTypedArrayLength),
2372 JS_INLINABLE_FN("UnsafeGetBooleanFromReservedSlot",
2373 intrinsic_UnsafeGetBooleanFromReservedSlot, 2, 0,
2374 IntrinsicUnsafeGetBooleanFromReservedSlot),
2375 JS_INLINABLE_FN("UnsafeGetInt32FromReservedSlot",
2376 intrinsic_UnsafeGetInt32FromReservedSlot, 2, 0,
2377 IntrinsicUnsafeGetInt32FromReservedSlot),
2378 JS_INLINABLE_FN("UnsafeGetObjectFromReservedSlot",
2379 intrinsic_UnsafeGetObjectFromReservedSlot, 2, 0,
2380 IntrinsicUnsafeGetObjectFromReservedSlot),
2381 JS_INLINABLE_FN("UnsafeGetReservedSlot", intrinsic_UnsafeGetReservedSlot, 2,
2382 0, IntrinsicUnsafeGetReservedSlot),
2383 JS_INLINABLE_FN("UnsafeGetStringFromReservedSlot",
2384 intrinsic_UnsafeGetStringFromReservedSlot, 2, 0,
2385 IntrinsicUnsafeGetStringFromReservedSlot),
2386 JS_INLINABLE_FN("UnsafeSetReservedSlot", intrinsic_UnsafeSetReservedSlot, 3,
2387 0, IntrinsicUnsafeSetReservedSlot),
2388
2389 // Intrinsics and standard functions used by Intl API implementation.
2390 #ifdef JS_HAS_INTL_API
2391 JS_FN("intl_BestAvailableLocale", intl_BestAvailableLocale, 3, 0),
2392 JS_FN("intl_CallCollatorMethodIfWrapped",
2393 CallNonGenericSelfhostedMethod<Is<CollatorObject>>, 2, 0),
2394 JS_FN("intl_CallDateTimeFormatMethodIfWrapped",
2395 CallNonGenericSelfhostedMethod<Is<DateTimeFormatObject>>, 2, 0),
2396 JS_FN("intl_CallDisplayNamesMethodIfWrapped",
2397 CallNonGenericSelfhostedMethod<Is<DisplayNamesObject>>, 2, 0),
2398 JS_FN("intl_CallListFormatMethodIfWrapped",
2399 CallNonGenericSelfhostedMethod<Is<ListFormatObject>>, 2, 0),
2400 JS_FN("intl_CallNumberFormatMethodIfWrapped",
2401 CallNonGenericSelfhostedMethod<Is<NumberFormatObject>>, 2, 0),
2402 JS_FN("intl_CallPluralRulesMethodIfWrapped",
2403 CallNonGenericSelfhostedMethod<Is<PluralRulesObject>>, 2, 0),
2404 JS_FN("intl_CallRelativeTimeFormatMethodIfWrapped",
2405 CallNonGenericSelfhostedMethod<Is<RelativeTimeFormatObject>>, 2, 0),
2406 JS_FN("intl_Collator", intl_Collator, 2, 0),
2407 JS_FN("intl_CompareStrings", intl_CompareStrings, 3, 0),
2408 JS_FN("intl_ComputeDisplayName", intl_ComputeDisplayName, 6, 0),
2409 JS_FN("intl_ComputeDisplayNames", intl_ComputeDisplayNames, 3, 0),
2410 JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2, 0),
2411 JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2, 0),
2412 JS_FN("intl_FormatDateTimeRange", intl_FormatDateTimeRange, 4, 0),
2413 JS_FN("intl_FormatList", intl_FormatList, 3, 0),
2414 JS_FN("intl_FormatNumber", intl_FormatNumber, 3, 0),
2415 JS_FN("intl_FormatRelativeTime", intl_FormatRelativeTime, 4, 0),
2416 JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1, 0),
2417 JS_FN("intl_GetLocaleInfo", intl_GetLocaleInfo, 1, 0),
2418 JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 1, 0),
2419 JS_INLINABLE_FN("intl_GuardToCollator",
2420 intrinsic_GuardToBuiltin<CollatorObject>, 1, 0,
2421 IntlGuardToCollator),
2422 JS_INLINABLE_FN("intl_GuardToDateTimeFormat",
2423 intrinsic_GuardToBuiltin<DateTimeFormatObject>, 1, 0,
2424 IntlGuardToDateTimeFormat),
2425 JS_INLINABLE_FN("intl_GuardToDisplayNames",
2426 intrinsic_GuardToBuiltin<DisplayNamesObject>, 1, 0,
2427 IntlGuardToDisplayNames),
2428 JS_INLINABLE_FN("intl_GuardToListFormat",
2429 intrinsic_GuardToBuiltin<ListFormatObject>, 1, 0,
2430 IntlGuardToListFormat),
2431 JS_INLINABLE_FN("intl_GuardToNumberFormat",
2432 intrinsic_GuardToBuiltin<NumberFormatObject>, 1, 0,
2433 IntlGuardToNumberFormat),
2434 JS_INLINABLE_FN("intl_GuardToPluralRules",
2435 intrinsic_GuardToBuiltin<PluralRulesObject>, 1, 0,
2436 IntlGuardToPluralRules),
2437 JS_INLINABLE_FN("intl_GuardToRelativeTimeFormat",
2438 intrinsic_GuardToBuiltin<RelativeTimeFormatObject>, 1, 0,
2439 IntlGuardToRelativeTimeFormat),
2440 JS_FN("intl_IsRuntimeDefaultLocale", intrinsic_IsRuntimeDefaultLocale, 1,
2441 0),
2442 JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1, 0),
2443 JS_FN("intl_IsWrappedDateTimeFormat",
2444 intrinsic_IsWrappedInstanceOfBuiltin<DateTimeFormatObject>, 1, 0),
2445 JS_FN("intl_IsWrappedNumberFormat",
2446 intrinsic_IsWrappedInstanceOfBuiltin<NumberFormatObject>, 1, 0),
2447 JS_FN("intl_NumberFormat", intl_NumberFormat, 2, 0),
2448 JS_FN("intl_RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0, 0),
2449 JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2, 0),
2450 JS_FN("intl_TryValidateAndCanonicalizeLanguageTag",
2451 intl_TryValidateAndCanonicalizeLanguageTag, 1, 0),
2452 JS_FN("intl_ValidateAndCanonicalizeLanguageTag",
2453 intl_ValidateAndCanonicalizeLanguageTag, 2, 0),
2454 JS_FN("intl_ValidateAndCanonicalizeUnicodeExtensionType",
2455 intl_ValidateAndCanonicalizeUnicodeExtensionType, 3, 0),
2456 JS_FN("intl_availableCalendars", intl_availableCalendars, 1, 0),
2457 JS_FN("intl_availableCollations", intl_availableCollations, 1, 0),
2458 # if DEBUG || MOZ_SYSTEM_ICU
2459 JS_FN("intl_availableMeasurementUnits", intl_availableMeasurementUnits, 0,
2460 0),
2461 # endif
2462 JS_FN("intl_canonicalizeTimeZone", intl_canonicalizeTimeZone, 1, 0),
2463 JS_FN("intl_defaultCalendar", intl_defaultCalendar, 1, 0),
2464 JS_FN("intl_defaultTimeZone", intl_defaultTimeZone, 0, 0),
2465 JS_FN("intl_defaultTimeZoneOffset", intl_defaultTimeZoneOffset, 0, 0),
2466 JS_FN("intl_isDefaultTimeZone", intl_isDefaultTimeZone, 1, 0),
2467 JS_FN("intl_isUpperCaseFirst", intl_isUpperCaseFirst, 1, 0),
2468 JS_FN("intl_numberingSystem", intl_numberingSystem, 1, 0),
2469 JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 3, 0),
2470 JS_FN("intl_patternForStyle", intl_patternForStyle, 6, 0),
2471 JS_FN("intl_skeletonForPattern", intl_skeletonForPattern, 1, 0),
2472 JS_FN("intl_supportedLocaleOrFallback", intl_supportedLocaleOrFallback, 1,
2473 0),
2474 JS_FN("intl_toLocaleLowerCase", intl_toLocaleLowerCase, 2, 0),
2475 JS_FN("intl_toLocaleUpperCase", intl_toLocaleUpperCase, 2, 0),
2476 #endif // JS_HAS_INTL_API
2477
2478 // Standard builtins used by self-hosting.
2479 JS_INLINABLE_FN("std_Array", array_construct, 1, 0, Array),
2480 JS_INLINABLE_FN("std_Array_pop", array_pop, 0, 0, ArrayPop),
2481 JS_INLINABLE_FN("std_Array_push", array_push, 1, 0, ArrayPush),
2482 JS_FN("std_BigInt_valueOf", BigIntObject::valueOf, 0, 0),
2483 JS_FN("std_Date_now", date_now, 0, 0),
2484 JS_FN("std_Function_apply", fun_apply, 2, 0),
2485 JS_FN("std_Map_entries", MapObject::entries, 0, 0),
2486 JS_INLINABLE_FN("std_Math_abs", math_abs, 1, 0, MathAbs),
2487 JS_INLINABLE_FN("std_Math_floor", math_floor, 1, 0, MathFloor),
2488 JS_INLINABLE_FN("std_Math_max", math_max, 2, 0, MathMax),
2489 JS_INLINABLE_FN("std_Math_min", math_min, 2, 0, MathMin),
2490 JS_INLINABLE_FN("std_Math_trunc", math_trunc, 1, 0, MathTrunc),
2491 JS_INLINABLE_FN("std_Object_create", obj_create, 2, 0, ObjectCreate),
2492 JS_INLINABLE_FN("std_Object_isPrototypeOf", obj_isPrototypeOf, 1, 0,
2493 ObjectIsPrototypeOf),
2494 JS_FN("std_Object_propertyIsEnumerable", obj_propertyIsEnumerable, 1, 0),
2495 JS_FN("std_Object_setProto", obj_setProto, 1, 0),
2496 JS_FN("std_Object_toString", obj_toString, 0, 0),
2497 JS_INLINABLE_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf, 1, 0,
2498 ReflectGetPrototypeOf),
2499 JS_FN("std_Reflect_isExtensible", Reflect_isExtensible, 1, 0),
2500 JS_FN("std_Reflect_ownKeys", Reflect_ownKeys, 1, 0),
2501 JS_FN("std_Set_values", SetObject::values, 0, 0),
2502 JS_INLINABLE_FN("std_String_charCodeAt", str_charCodeAt, 1, 0,
2503 StringCharCodeAt),
2504 JS_FN("std_String_endsWith", str_endsWith, 1, 0),
2505 JS_INLINABLE_FN("std_String_fromCharCode", str_fromCharCode, 1, 0,
2506 StringFromCharCode),
2507 JS_INLINABLE_FN("std_String_fromCodePoint", str_fromCodePoint, 1, 0,
2508 StringFromCodePoint),
2509 JS_FN("std_String_includes", str_includes, 1, 0),
2510 JS_FN("std_String_indexOf", str_indexOf, 1, 0),
2511 JS_FN("std_String_startsWith", str_startsWith, 1, 0),
2512 JS_FN("std_TypedArray_buffer", js::TypedArray_bufferGetter, 1, 0),
2513
2514 JS_FS_END};
2515
FillSelfHostingCompileOptions(CompileOptions & options)2516 void js::FillSelfHostingCompileOptions(CompileOptions& options) {
2517 /*
2518 * In self-hosting mode, scripts use JSOp::GetIntrinsic instead of
2519 * JSOp::GetName or JSOp::GetGName to access unbound variables.
2520 * JSOp::GetIntrinsic does a name lookup on a special object, whose
2521 * properties are filled in lazily upon first access for a given global.
2522 *
2523 * As that object is inaccessible to client code, the lookups are
2524 * guaranteed to return the original objects, ensuring safe implementation
2525 * of self-hosted builtins.
2526 *
2527 * Additionally, the special syntax callFunction(fun, receiver, ...args)
2528 * is supported, for which bytecode is emitted that invokes |fun| with
2529 * |receiver| as the this-object and ...args as the arguments.
2530 */
2531 options.setIntroductionType("self-hosted");
2532 options.setFileAndLine("self-hosted", 1);
2533 options.setSkipFilenameValidation(true);
2534 options.setSelfHostingMode(true);
2535 options.setForceFullParse();
2536 options.setForceStrictMode();
2537 options.setDiscardSource();
2538 options.setIsRunOnce(true);
2539 options.setNoScriptRval(true);
2540 }
2541
createSelfHostingGlobal(JSContext * cx)2542 GlobalObject* JSRuntime::createSelfHostingGlobal(JSContext* cx) {
2543 MOZ_ASSERT(!cx->isExceptionPending());
2544 MOZ_ASSERT(!cx->realm());
2545
2546 JS::RealmOptions options;
2547 options.creationOptions().setNewCompartmentInSelfHostingZone();
2548 // Debugging the selfHosted zone is not supported because CCWs are not
2549 // allowed in that zone.
2550 options.creationOptions().setInvisibleToDebugger(true);
2551
2552 Realm* realm = NewRealm(cx, nullptr, options);
2553 if (!realm) {
2554 return nullptr;
2555 }
2556
2557 static const JSClassOps shgClassOps = {
2558 nullptr, // addProperty
2559 nullptr, // delProperty
2560 nullptr, // enumerate
2561 nullptr, // newEnumerate
2562 nullptr, // resolve
2563 nullptr, // mayResolve
2564 nullptr, // finalize
2565 nullptr, // call
2566 nullptr, // hasInstance
2567 nullptr, // construct
2568 JS_GlobalObjectTraceHook, // trace
2569 };
2570
2571 static const JSClass shgClass = {"self-hosting-global", JSCLASS_GLOBAL_FLAGS,
2572 &shgClassOps};
2573
2574 AutoRealmUnchecked ar(cx, realm);
2575 Rooted<GlobalObject*> shg(cx, GlobalObject::createInternal(cx, &shgClass));
2576 if (!shg) {
2577 return nullptr;
2578 }
2579
2580 cx->runtime()->selfHostingGlobal_ = shg;
2581 MOZ_ASSERT(realm->zone()->isSelfHostingZone());
2582 realm->setIsSelfHostingRealm();
2583
2584 if (!GlobalObject::initSelfHostingBuiltins(cx, shg, intrinsic_functions)) {
2585 return nullptr;
2586 }
2587
2588 JS_FireOnNewGlobalObject(cx, shg);
2589
2590 return shg;
2591 }
2592
2593 class MOZ_STACK_CLASS AutoSelfHostingErrorReporter {
2594 JSContext* cx_;
2595 JS::WarningReporter oldReporter_;
2596
2597 public:
AutoSelfHostingErrorReporter(JSContext * cx)2598 explicit AutoSelfHostingErrorReporter(JSContext* cx) : cx_(cx) {
2599 oldReporter_ = JS::SetWarningReporter(cx_, selfHosting_WarningReporter);
2600 }
~AutoSelfHostingErrorReporter()2601 ~AutoSelfHostingErrorReporter() {
2602 JS::SetWarningReporter(cx_, oldReporter_);
2603
2604 // Exceptions in self-hosted code will usually be printed to stderr in
2605 // ErrorToException, but not all exceptions are handled there. For
2606 // instance, ReportOutOfMemory will throw the "out of memory" string
2607 // without going through ErrorToException. We handle these other
2608 // exceptions here.
2609 MaybePrintAndClearPendingException(cx_);
2610 }
2611 };
2612
VerifyGlobalNames(JSContext * cx,Handle<GlobalObject * > shg)2613 static bool VerifyGlobalNames(JSContext* cx, Handle<GlobalObject*> shg) {
2614 #ifdef DEBUG
2615 // The `intrinsic_functions` list must be sorted so that we can use
2616 // mozilla::BinarySearch to do lookups on demand.
2617 const char* prev = "";
2618 for (JSFunctionSpec spec : intrinsic_functions) {
2619 if (spec.name.string()) {
2620 MOZ_ASSERT(strcmp(prev, spec.name.string()) < 0,
2621 "Self-hosted intrinsics must be sorted");
2622 prev = spec.name.string();
2623 }
2624 }
2625
2626 RootedId id(cx);
2627 bool nameMissing = false;
2628
2629 for (auto base = cx->zone()->cellIter<BaseScript>();
2630 !base.done() && !nameMissing; base.next()) {
2631 if (!base->hasBytecode()) {
2632 continue;
2633 }
2634 JSScript* script = base->asJSScript();
2635
2636 for (BytecodeLocation loc : AllBytecodesIterable(script)) {
2637 JSOp op = loc.getOp();
2638
2639 if (op == JSOp::GetIntrinsic) {
2640 PropertyName* name = loc.getPropertyName(script);
2641 id = NameToId(name);
2642
2643 if (shg->lookupPure(id).isNothing()) {
2644 // cellIter disallows GCs, but error reporting wants to
2645 // have them, so we need to move it out of the loop.
2646 nameMissing = true;
2647 break;
2648 }
2649 }
2650 }
2651 }
2652
2653 if (nameMissing) {
2654 return Throw(cx, id, JSMSG_NO_SUCH_SELF_HOSTED_PROP);
2655 }
2656 #endif // DEBUG
2657
2658 return true;
2659 }
2660
InitSelfHostingFromStencil(JSContext * cx,Handle<GlobalObject * > shg,frontend::CompilationInput & input,const frontend::CompilationStencil & stencil)2661 [[nodiscard]] bool InitSelfHostingFromStencil(
2662 JSContext* cx, Handle<GlobalObject*> shg, frontend::CompilationInput& input,
2663 const frontend::CompilationStencil& stencil) {
2664 // Instantiate the stencil and run the script.
2665 // NOTE: Use a block here so the GC roots are dropped before freezing the Zone
2666 // below.
2667 {
2668 Rooted<frontend::CompilationGCOutput> output(cx);
2669 if (!frontend::CompilationStencil::instantiateStencils(cx, input, stencil,
2670 output.get())) {
2671 return false;
2672 }
2673
2674 // Run the script
2675 RootedScript script(cx, output.get().script);
2676 RootedValue rval(cx);
2677 if (!JS_ExecuteScript(cx, script, &rval)) {
2678 return false;
2679 }
2680 }
2681
2682 if (!VerifyGlobalNames(cx, shg)) {
2683 return false;
2684 }
2685
2686 // Garbage collect the self hosting zone once when it is created. It should
2687 // not be modified after this point.
2688 cx->runtime()->gc.freezeSelfHostingZone();
2689
2690 return true;
2691 }
2692
initSelfHosting(JSContext * cx,JS::SelfHostedCache xdrCache,JS::SelfHostedWriter xdrWriter)2693 bool JSRuntime::initSelfHosting(JSContext* cx, JS::SelfHostedCache xdrCache,
2694 JS::SelfHostedWriter xdrWriter) {
2695 MOZ_ASSERT(!selfHostingGlobal_);
2696
2697 if (cx->runtime()->parentRuntime) {
2698 selfHostingGlobal_ = cx->runtime()->parentRuntime->selfHostingGlobal_;
2699 return true;
2700 }
2701
2702 Rooted<GlobalObject*> shg(cx, JSRuntime::createSelfHostingGlobal(cx));
2703 if (!shg) {
2704 return false;
2705 }
2706
2707 JSAutoRealm ar(cx, shg);
2708
2709 /*
2710 * Set a temporary error reporter printing to stderr because it is too
2711 * early in the startup process for any other reporter to be registered
2712 * and we don't want errors in self-hosted code to be silently swallowed.
2713 *
2714 * This class also overrides the warning reporter to print warnings to
2715 * stderr. See selfHosting_WarningReporter.
2716 */
2717 AutoSelfHostingErrorReporter errorReporter(cx);
2718
2719 // Variables used to instantiate scripts.
2720 CompileOptions options(cx);
2721 FillSelfHostingCompileOptions(options);
2722
2723 // Try initializing from Stencil XDR.
2724 bool decodeOk = false;
2725 Rooted<frontend::CompilationGCOutput> output(cx);
2726 if (xdrCache.Length() > 0) {
2727 // Allow the VM to directly use bytecode from the XDR buffer without
2728 // copying it. The buffer must outlive all runtimes (including workers).
2729 options.usePinnedBytecode = true;
2730
2731 Rooted<frontend::CompilationInput> input(
2732 cx, frontend::CompilationInput(options));
2733 if (!input.get().initForSelfHostingGlobal(cx)) {
2734 return false;
2735 }
2736
2737 frontend::CompilationStencil stencil(input.get().source);
2738 if (!stencil.deserializeStencils(cx, input.get(), xdrCache, &decodeOk)) {
2739 return false;
2740 }
2741
2742 if (decodeOk) {
2743 return InitSelfHostingFromStencil(cx, shg, input.get(), stencil);
2744 }
2745 }
2746
2747 // If script wasn't generated, it means XDR was either not provided or that it
2748 // failed the decoding phase. Parse from text as before.
2749 uint32_t srcLen = GetRawScriptsSize();
2750 const unsigned char* compressed = compressedSources;
2751 uint32_t compressedLen = GetCompressedSize();
2752 auto src = cx->make_pod_array<char>(srcLen);
2753 if (!src) {
2754 return false;
2755 }
2756 if (!DecompressString(compressed, compressedLen,
2757 reinterpret_cast<unsigned char*>(src.get()), srcLen)) {
2758 return false;
2759 }
2760
2761 JS::SourceText<mozilla::Utf8Unit> srcBuf;
2762 if (!srcBuf.init(cx, std::move(src), srcLen)) {
2763 return false;
2764 }
2765
2766 Rooted<frontend::CompilationInput> input(cx,
2767 frontend::CompilationInput(options));
2768 auto stencil = frontend::CompileGlobalScriptToStencil(cx, input.get(), srcBuf,
2769 ScopeKind::Global);
2770 if (!stencil) {
2771 return false;
2772 }
2773
2774 // Serialize the stencil to XDR.
2775 if (xdrWriter) {
2776 JS::TranscodeBuffer xdrBuffer;
2777 if (!stencil->serializeStencils(cx, input.get(), xdrBuffer)) {
2778 return false;
2779 }
2780
2781 if (!xdrWriter(cx, xdrBuffer)) {
2782 return false;
2783 }
2784 }
2785
2786 return InitSelfHostingFromStencil(cx, shg, input.get(), *stencil);
2787 }
2788
finishSelfHosting()2789 void JSRuntime::finishSelfHosting() { selfHostingGlobal_ = nullptr; }
2790
traceSelfHostingGlobal(JSTracer * trc)2791 void JSRuntime::traceSelfHostingGlobal(JSTracer* trc) {
2792 if (selfHostingGlobal_ && !parentRuntime) {
2793 TraceRoot(trc, const_cast<NativeObject**>(&selfHostingGlobal_.ref()),
2794 "self-hosting global");
2795 }
2796 }
2797
getSelfHostedFunctionGeneratorKind(JSAtom * name)2798 GeneratorKind JSRuntime::getSelfHostedFunctionGeneratorKind(JSAtom* name) {
2799 JSFunction* fun = getUnclonedSelfHostedFunction(name->asPropertyName());
2800 return fun->generatorKind();
2801 }
2802
2803 static bool CloneValue(JSContext* cx, HandleValue selfHostedValue,
2804 MutableHandleValue vp);
2805
GetUnclonedValue(NativeObject * selfHostedObject,const PropertyKey & id,Value * vp)2806 static void GetUnclonedValue(NativeObject* selfHostedObject,
2807 const PropertyKey& id, Value* vp) {
2808 if (JSID_IS_INT(id)) {
2809 size_t index = JSID_TO_INT(id);
2810 if (index < selfHostedObject->getDenseInitializedLength() &&
2811 !selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE)) {
2812 *vp = selfHostedObject->getDenseElement(JSID_TO_INT(id));
2813 return;
2814 }
2815 }
2816
2817 // Since all atoms used by self-hosting are marked as permanent, the only
2818 // reason we'd see a non-permanent atom here is code looking for
2819 // properties on the self hosted global which aren't present.
2820 // Since we ensure that that can't happen during startup, encountering
2821 // non-permanent atoms here should be impossible.
2822 MOZ_ASSERT_IF(JSID_IS_STRING(id), JSID_TO_STRING(id)->isPermanentAtom());
2823
2824 mozilla::Maybe<PropertyInfo> prop = selfHostedObject->lookupPure(id);
2825 MOZ_ASSERT(prop.isSome());
2826 MOZ_ASSERT(prop->isDataProperty());
2827 *vp = selfHostedObject->getSlot(prop->slot());
2828 }
2829
CloneProperties(JSContext * cx,HandleNativeObject selfHostedObject,HandleObject clone)2830 static bool CloneProperties(JSContext* cx, HandleNativeObject selfHostedObject,
2831 HandleObject clone) {
2832 RootedIdVector ids(cx);
2833 Vector<uint8_t, 16> attrs(cx);
2834
2835 for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) {
2836 if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
2837 if (!ids.append(INT_TO_JSID(i))) {
2838 return false;
2839 }
2840 if (!attrs.append(JSPROP_ENUMERATE)) {
2841 return false;
2842 }
2843 }
2844 }
2845
2846 Rooted<PropertyInfoWithKeyVector> props(cx, PropertyInfoWithKeyVector(cx));
2847 for (ShapePropertyIter<NoGC> iter(selfHostedObject->shape()); !iter.done();
2848 iter++) {
2849 if (iter->enumerable() && !props.append(*iter)) {
2850 return false;
2851 }
2852 }
2853
2854 // Now our properties are in last-to-first order, so....
2855 std::reverse(props.begin(), props.end());
2856 for (size_t i = 0; i < props.length(); ++i) {
2857 MOZ_ASSERT(props[i].isDataProperty(),
2858 "Can't handle cloning accessors here yet.");
2859 if (!ids.append(props[i].key())) {
2860 return false;
2861 }
2862 PropertyInfo prop = props[i];
2863 uint8_t propAttrs = 0;
2864 if (prop.enumerable()) {
2865 propAttrs |= JSPROP_ENUMERATE;
2866 }
2867 if (!prop.configurable()) {
2868 propAttrs |= JSPROP_PERMANENT;
2869 }
2870 if (!prop.writable()) {
2871 propAttrs |= JSPROP_READONLY;
2872 }
2873 if (!attrs.append(propAttrs)) {
2874 return false;
2875 }
2876 }
2877
2878 RootedId id(cx);
2879 RootedValue val(cx);
2880 RootedValue selfHostedValue(cx);
2881 for (uint32_t i = 0; i < ids.length(); i++) {
2882 id = ids[i];
2883 GetUnclonedValue(selfHostedObject, id, selfHostedValue.address());
2884 if (!CloneValue(cx, selfHostedValue, &val) ||
2885 !JS_DefinePropertyById(cx, clone, id, val, attrs[i])) {
2886 return false;
2887 }
2888 }
2889
2890 return true;
2891 }
2892
CloneString(JSContext * cx,JSLinearString * selfHostedString)2893 static JSString* CloneString(JSContext* cx, JSLinearString* selfHostedString) {
2894 size_t len = selfHostedString->length();
2895 {
2896 JS::AutoCheckCannotGC nogc;
2897 JSString* clone;
2898 if (selfHostedString->hasLatin1Chars()) {
2899 clone =
2900 NewStringCopyN<NoGC>(cx, selfHostedString->latin1Chars(nogc), len);
2901 } else {
2902 clone = NewStringCopyNDontDeflate<NoGC>(
2903 cx, selfHostedString->twoByteChars(nogc), len);
2904 }
2905 if (clone) {
2906 return clone;
2907 }
2908 }
2909
2910 AutoStableStringChars chars(cx);
2911 if (!chars.init(cx, selfHostedString)) {
2912 return nullptr;
2913 }
2914
2915 return chars.isLatin1()
2916 ? NewStringCopyN<CanGC>(cx, chars.latin1Range().begin().get(), len)
2917 : NewStringCopyNDontDeflate<CanGC>(
2918 cx, chars.twoByteRange().begin().get(), len);
2919 }
2920
2921 // Returns the ScriptSourceObject to use for cloned self-hosted scripts in the
2922 // current realm.
SelfHostingScriptSourceObject(JSContext * cx)2923 static ScriptSourceObject* SelfHostingScriptSourceObject(JSContext* cx) {
2924 if (ScriptSourceObject* sso = cx->realm()->selfHostingScriptSource) {
2925 return sso;
2926 }
2927
2928 CompileOptions options(cx);
2929 FillSelfHostingCompileOptions(options);
2930
2931 RefPtr<ScriptSource> source(cx->new_<ScriptSource>());
2932 if (!source) {
2933 return nullptr;
2934 }
2935
2936 if (!source->initFromOptions(cx, options)) {
2937 return nullptr;
2938 }
2939
2940 RootedScriptSourceObject sourceObject(
2941 cx, ScriptSourceObject::create(cx, source.get()));
2942 if (!sourceObject) {
2943 return nullptr;
2944 }
2945
2946 if (!ScriptSourceObject::initFromOptions(cx, sourceObject, options)) {
2947 return nullptr;
2948 }
2949
2950 cx->realm()->selfHostingScriptSource.set(sourceObject);
2951 return sourceObject;
2952 }
2953
CloneObject(JSContext * cx,HandleNativeObject selfHostedObject)2954 static JSObject* CloneObject(JSContext* cx,
2955 HandleNativeObject selfHostedObject) {
2956 #ifdef DEBUG
2957 // Object hash identities are owned by the hashed object, which may be on a
2958 // different thread than the clone target. In theory, these objects are all
2959 // tenured and will not be compacted; however, we simply avoid the issue
2960 // altogether by skipping the cycle-detection when off thread.
2961 mozilla::Maybe<AutoCycleDetector> detect;
2962 if (js::CurrentThreadCanAccessZone(selfHostedObject->zoneFromAnyThread())) {
2963 detect.emplace(cx, selfHostedObject);
2964 if (!detect->init()) {
2965 return nullptr;
2966 }
2967 if (detect->foundCycle()) {
2968 MOZ_CRASH("SelfHosted cloning cannot handle cyclic object graphs.");
2969 }
2970 }
2971 #endif
2972
2973 RootedObject clone(cx);
2974 if (selfHostedObject->is<JSFunction>()) {
2975 RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>());
2976 if (selfHostedFunction->isInterpreted()) {
2977 // Arrow functions use the first extended slot for their lexical |this|
2978 // value. And methods use the first extended slot for their home-object.
2979 // We only expect to see normal functions here.
2980 MOZ_ASSERT(selfHostedFunction->kind() == FunctionFlags::NormalFunction);
2981 MOZ_ASSERT(selfHostedFunction->isLambda() == false);
2982
2983 Handle<GlobalObject*> global = cx->global();
2984 Rooted<GlobalLexicalEnvironmentObject*> globalLexical(
2985 cx, &global->lexicalEnvironment());
2986 RootedScope emptyGlobalScope(cx, &global->emptyGlobalScope());
2987 Rooted<ScriptSourceObject*> sourceObject(
2988 cx, SelfHostingScriptSourceObject(cx));
2989 if (!sourceObject) {
2990 return nullptr;
2991 }
2992 MOZ_ASSERT(
2993 !CanReuseScriptForClone(cx->realm(), selfHostedFunction, global));
2994 clone = CloneFunctionAndScript(cx, selfHostedFunction, globalLexical,
2995 emptyGlobalScope, sourceObject,
2996 gc::AllocKind::FUNCTION_EXTENDED);
2997 if (!clone) {
2998 return nullptr;
2999 }
3000
3001 // Save the original function name that we are cloning from. This allows
3002 // the function to potentially be relazified in the future.
3003 SetClonedSelfHostedFunctionName(&clone->as<JSFunction>(),
3004 selfHostedFunction->explicitName());
3005
3006 // If |_SetCanonicalName| was called on the function, the function name to
3007 // use is stored in the extended slot.
3008 if (JSAtom* name =
3009 GetUnclonedSelfHostedCanonicalName(selfHostedFunction)) {
3010 clone->as<JSFunction>().setAtom(name);
3011 }
3012 } else {
3013 clone = CloneSelfHostingIntrinsic(cx, selfHostedFunction);
3014 }
3015 } else if (selfHostedObject->is<RegExpObject>()) {
3016 RegExpObject& reobj = selfHostedObject->as<RegExpObject>();
3017 RootedAtom source(cx, reobj.getSource());
3018 MOZ_ASSERT(source->isPermanentAtom());
3019 clone = RegExpObject::create(cx, source, reobj.getFlags(), TenuredObject);
3020 } else if (selfHostedObject->is<DateObject>()) {
3021 clone =
3022 JS::NewDateObject(cx, selfHostedObject->as<DateObject>().clippedTime());
3023 } else if (selfHostedObject->is<BooleanObject>()) {
3024 clone = BooleanObject::create(
3025 cx, selfHostedObject->as<BooleanObject>().unbox());
3026 } else if (selfHostedObject->is<NumberObject>()) {
3027 clone =
3028 NumberObject::create(cx, selfHostedObject->as<NumberObject>().unbox());
3029 } else if (selfHostedObject->is<StringObject>()) {
3030 JSString* selfHostedString = selfHostedObject->as<StringObject>().unbox();
3031 if (!selfHostedString->isLinear()) {
3032 MOZ_CRASH();
3033 }
3034 RootedString str(cx, CloneString(cx, &selfHostedString->asLinear()));
3035 if (!str) {
3036 return nullptr;
3037 }
3038 clone = StringObject::create(cx, str);
3039 } else if (selfHostedObject->is<ArrayObject>()) {
3040 clone = NewTenuredDenseEmptyArray(cx, nullptr);
3041 } else {
3042 MOZ_ASSERT(selfHostedObject->is<NativeObject>());
3043 clone = NewObjectWithGivenProto(
3044 cx, selfHostedObject->getClass(), nullptr,
3045 selfHostedObject->asTenured().getAllocKind(), TenuredObject);
3046 }
3047 if (!clone) {
3048 return nullptr;
3049 }
3050
3051 if (!CloneProperties(cx, selfHostedObject, clone)) {
3052 return nullptr;
3053 }
3054 return clone;
3055 }
3056
CloneValue(JSContext * cx,HandleValue selfHostedValue,MutableHandleValue vp)3057 static bool CloneValue(JSContext* cx, HandleValue selfHostedValue,
3058 MutableHandleValue vp) {
3059 if (selfHostedValue.isObject()) {
3060 RootedNativeObject selfHostedObject(
3061 cx, &selfHostedValue.toObject().as<NativeObject>());
3062 JSObject* clone = CloneObject(cx, selfHostedObject);
3063 if (!clone) {
3064 return false;
3065 }
3066 vp.setObject(*clone);
3067 } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() ||
3068 selfHostedValue.isNullOrUndefined()) {
3069 // Nothing to do here: these are represented inline in the value.
3070 vp.set(selfHostedValue);
3071 } else if (selfHostedValue.isString()) {
3072 if (!selfHostedValue.toString()->isLinear()) {
3073 MOZ_CRASH();
3074 }
3075 JSLinearString* selfHostedString = &selfHostedValue.toString()->asLinear();
3076 JSString* clone = CloneString(cx, selfHostedString);
3077 if (!clone) {
3078 return false;
3079 }
3080 vp.setString(clone);
3081 } else if (selfHostedValue.isSymbol()) {
3082 // Well-known symbols are shared.
3083 mozilla::DebugOnly<JS::Symbol*> sym = selfHostedValue.toSymbol();
3084 MOZ_ASSERT(sym->isWellKnownSymbol());
3085 MOZ_ASSERT(cx->wellKnownSymbols().get(sym->code()) == sym);
3086 vp.set(selfHostedValue);
3087 } else {
3088 MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
3089 }
3090 return true;
3091 }
3092
createLazySelfHostedFunctionClone(JSContext * cx,HandlePropertyName selfHostedName,HandleAtom name,unsigned nargs,NewObjectKind newKind,MutableHandleFunction fun)3093 bool JSRuntime::createLazySelfHostedFunctionClone(
3094 JSContext* cx, HandlePropertyName selfHostedName, HandleAtom name,
3095 unsigned nargs, NewObjectKind newKind, MutableHandleFunction fun) {
3096 MOZ_ASSERT(newKind != GenericObject);
3097
3098 RootedAtom funName(cx, name);
3099 JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(selfHostedName);
3100 if (!selfHostedFun) {
3101 return false;
3102 }
3103
3104 // If there is a a canonical name set, use that instead.
3105 if (JSAtom* name = GetUnclonedSelfHostedCanonicalName(selfHostedFun)) {
3106 funName = name;
3107 }
3108
3109 RootedObject proto(cx);
3110 if (!GetFunctionPrototype(cx, selfHostedFun->generatorKind(),
3111 selfHostedFun->asyncKind(), &proto)) {
3112 return false;
3113 }
3114
3115 fun.set(NewScriptedFunction(cx, nargs, FunctionFlags::BASESCRIPT, funName,
3116 proto, gc::AllocKind::FUNCTION_EXTENDED,
3117 newKind));
3118 if (!fun) {
3119 return false;
3120 }
3121 fun->setIsSelfHostedBuiltin();
3122 fun->initSelfHostedLazyScript(&cx->runtime()->selfHostedLazyScript.ref());
3123 SetClonedSelfHostedFunctionName(fun, selfHostedName);
3124 return true;
3125 }
3126
cloneSelfHostedFunctionScript(JSContext * cx,HandlePropertyName name,HandleFunction targetFun)3127 bool JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx,
3128 HandlePropertyName name,
3129 HandleFunction targetFun) {
3130 RootedFunction sourceFun(cx, getUnclonedSelfHostedFunction(name));
3131 if (!sourceFun) {
3132 return false;
3133 }
3134 MOZ_ASSERT(targetFun->isExtended());
3135 MOZ_ASSERT(targetFun->hasSelfHostedLazyScript());
3136
3137 RootedScript sourceScript(cx, JSFunction::getOrCreateScript(cx, sourceFun));
3138 if (!sourceScript) {
3139 return false;
3140 }
3141
3142 Rooted<ScriptSourceObject*> sourceObject(cx,
3143 SelfHostingScriptSourceObject(cx));
3144 if (!sourceObject) {
3145 return false;
3146 }
3147
3148 // Assert that there are no intervening scopes between the global scope
3149 // and the self-hosted script. Toplevel lexicals are explicitly forbidden
3150 // by the parser when parsing self-hosted code. The fact they have the
3151 // global lexical scope on the scope chain is for uniformity and engine
3152 // invariants.
3153 MOZ_ASSERT(sourceScript->outermostScope()->enclosing()->kind() ==
3154 ScopeKind::Global);
3155 RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
3156 if (!CloneScriptIntoFunction(cx, emptyGlobalScope, targetFun, sourceScript,
3157 sourceObject)) {
3158 return false;
3159 }
3160
3161 MOZ_ASSERT(targetFun->hasBytecode());
3162 RootedScript targetScript(cx, targetFun->nonLazyScript());
3163
3164 // Relazifiable self-hosted function may be relazified later into a
3165 // SelfHostedLazyScript. It is important to note that this only applies to
3166 // named self-hosted entry points (that use this clone method). Inner
3167 // functions clones used by self-hosted are never relazified, even if they
3168 // would be able to in normal script.
3169 if (targetScript->isRelazifiable()) {
3170 targetScript->setAllowRelazify();
3171 }
3172
3173 MOZ_ASSERT(sourceFun->nargs() == targetFun->nargs());
3174 MOZ_ASSERT(sourceScript->hasRest() == targetScript->hasRest());
3175 MOZ_ASSERT(targetFun->strict(), "Self-hosted builtins must be strict");
3176
3177 // The target function might have been relazified after its flags changed.
3178 targetFun->setFlags(targetFun->flags().toRaw() | sourceFun->flags().toRaw());
3179 return true;
3180 }
3181
getUnclonedSelfHostedValue(PropertyName * name,Value * vp)3182 void JSRuntime::getUnclonedSelfHostedValue(PropertyName* name, Value* vp) {
3183 PropertyKey id = NameToId(name);
3184 GetUnclonedValue(selfHostingGlobal_, id, vp);
3185 }
3186
getUnclonedSelfHostedFunction(PropertyName * name)3187 JSFunction* JSRuntime::getUnclonedSelfHostedFunction(PropertyName* name) {
3188 Value selfHostedValue;
3189 getUnclonedSelfHostedValue(name, &selfHostedValue);
3190 return &selfHostedValue.toObject().as<JSFunction>();
3191 }
3192
cloneSelfHostedValue(JSContext * cx,HandlePropertyName name,MutableHandleValue vp)3193 bool JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name,
3194 MutableHandleValue vp) {
3195 RootedValue selfHostedValue(cx);
3196 getUnclonedSelfHostedValue(name, selfHostedValue.address());
3197
3198 /*
3199 * We don't clone if we're operating in the self-hosting global, as that
3200 * means we're currently executing the self-hosting script while
3201 * initializing the runtime (see JSRuntime::initSelfHosting).
3202 */
3203 if (cx->global() == selfHostingGlobal_) {
3204 vp.set(selfHostedValue);
3205 return true;
3206 }
3207
3208 return CloneValue(cx, selfHostedValue, vp);
3209 }
3210
assertSelfHostedFunctionHasCanonicalName(JSContext * cx,HandlePropertyName name)3211 void JSRuntime::assertSelfHostedFunctionHasCanonicalName(
3212 JSContext* cx, HandlePropertyName name) {
3213 #ifdef DEBUG
3214 JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(name);
3215 MOZ_ASSERT(selfHostedFun);
3216 MOZ_ASSERT(GetUnclonedSelfHostedCanonicalName(selfHostedFun));
3217 #endif
3218 }
3219
IsSelfHostedFunctionWithName(JSFunction * fun,JSAtom * name)3220 bool js::IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name) {
3221 return fun->isSelfHostedBuiltin() && fun->isExtended() &&
3222 GetClonedSelfHostedFunctionName(fun) == name;
3223 }
3224
3225 static_assert(
3226 JSString::MAX_LENGTH <= INT32_MAX,
3227 "StringIteratorNext in builtin/String.js assumes the stored index "
3228 "into the string is an Int32Value");
3229
3230 static_assert(JSString::MAX_LENGTH == MAX_STRING_LENGTH,
3231 "JSString::MAX_LENGTH matches self-hosted constant for maximum "
3232 "string length");
3233
3234 static_assert(ARGS_LENGTH_MAX == MAX_ARGS_LENGTH,
3235 "ARGS_LENGTH_MAX matches self-hosted constant for maximum "
3236 "arguments length");
3237