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