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