tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

jsapi.cpp (165700B)


      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 /*
      8 * JavaScript API.
      9 */
     10 
     11 #include "jsapi.h"
     12 
     13 #include "mozilla/FloatingPoint.h"
     14 #include "mozilla/Maybe.h"
     15 #include "mozilla/PodOperations.h"
     16 #include "mozilla/Sprintf.h"
     17 
     18 #include <algorithm>
     19 #include <cstdarg>
     20 #ifdef __linux__
     21 #  include <dlfcn.h>
     22 #endif
     23 #include <stdarg.h>
     24 #include <string.h>
     25 
     26 #include "jsexn.h"
     27 #include "jsfriendapi.h"
     28 #include "jsmath.h"
     29 #include "jstypes.h"
     30 
     31 #include "builtin/AtomicsObject.h"
     32 #include "builtin/Eval.h"
     33 #include "builtin/JSON.h"
     34 #include "builtin/Promise.h"
     35 #include "builtin/Symbol.h"
     36 #include "frontend/FrontendContext.h"  // AutoReportFrontendContext
     37 #include "gc/GC.h"
     38 #include "gc/GCContext.h"
     39 #include "gc/Marking.h"
     40 #include "gc/PublicIterators.h"
     41 #include "jit/JitSpewer.h"
     42 #include "jit/TrampolineNatives.h"
     43 #include "js/CallAndConstruct.h"  // JS::IsCallable
     44 #include "js/CharacterEncoding.h"
     45 #include "js/ColumnNumber.h"  // JS::TaggedColumnNumberOneOrigin, JS::ColumnNumberOneOrigin
     46 #include "js/CompileOptions.h"
     47 #include "js/ContextOptions.h"  // JS::ContextOptions{,Ref}
     48 #include "js/Conversions.h"
     49 #include "js/Date.h"  // JS::GetReduceMicrosecondTimePrecisionCallback
     50 #include "js/ErrorInterceptor.h"
     51 #include "js/ErrorReport.h"           // JSErrorBase
     52 #include "js/experimental/JitInfo.h"  // JSJitInfo
     53 #include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
     54 #include "js/friend/StackLimits.h"    // js::AutoCheckRecursionLimit
     55 #include "js/GlobalObject.h"
     56 #include "js/Initialization.h"
     57 #include "js/Interrupt.h"
     58 #include "js/JSON.h"
     59 #include "js/LocaleSensitive.h"
     60 #include "js/MemoryCallbacks.h"
     61 #include "js/MemoryFunctions.h"
     62 #include "js/Prefs.h"
     63 #include "js/PropertySpec.h"
     64 #include "js/Proxy.h"
     65 #include "js/ScriptPrivate.h"
     66 #include "js/StableStringChars.h"
     67 #include "js/Stack.h"  // JS::NativeStackSize, JS::NativeStackLimitMax, JS::GetNativeStackLimit
     68 #include "js/StreamConsumer.h"
     69 #include "js/String.h"  // JS::MaxStringLength
     70 #include "js/Symbol.h"
     71 #include "js/TelemetryTimers.h"
     72 #include "js/Utility.h"
     73 #include "js/WaitCallbacks.h"
     74 #include "js/WasmModule.h"
     75 #include "js/Wrapper.h"
     76 #include "js/WrapperCallbacks.h"
     77 #include "proxy/DOMProxy.h"
     78 #include "util/Identifier.h"  // IsIdentifier
     79 #include "util/StringBuilder.h"
     80 #include "util/Text.h"
     81 #include "vm/BoundFunctionObject.h"
     82 #include "vm/EnvironmentObject.h"
     83 #include "vm/ErrorObject.h"
     84 #include "vm/ErrorReporting.h"
     85 #include "vm/FunctionPrefixKind.h"
     86 #include "vm/Interpreter.h"
     87 #include "vm/JSAtomState.h"
     88 #include "vm/JSAtomUtils.h"  // Atomize, AtomizeWithoutActiveZone, AtomizeChars, PinAtom, ClassName
     89 #include "vm/JSContext.h"
     90 #include "vm/JSFunction.h"
     91 #include "vm/JSObject.h"
     92 #include "vm/JSScript.h"
     93 #include "vm/Logging.h"
     94 #include "vm/PlainObject.h"    // js::PlainObject
     95 #include "vm/PromiseObject.h"  // js::PromiseObject
     96 #include "vm/Runtime.h"
     97 #include "vm/SavedStacks.h"
     98 #include "vm/StringType.h"
     99 #include "vm/Time.h"
    100 #include "vm/ToSource.h"
    101 #include "vm/Watchtower.h"
    102 #include "vm/WrapperObject.h"
    103 #include "wasm/WasmModule.h"
    104 #include "wasm/WasmProcess.h"
    105 
    106 #include "builtin/Promise-inl.h"
    107 #include "debugger/DebugAPI-inl.h"
    108 #include "vm/Compartment-inl.h"
    109 #include "vm/Interpreter-inl.h"
    110 #include "vm/IsGivenTypeObject-inl.h"  // js::IsGivenTypeObject
    111 #include "vm/JSAtomUtils-inl.h"  // AtomToId, PrimitiveValueToId, IndexToId, ClassName
    112 #include "vm/JSFunction-inl.h"
    113 #include "vm/JSScript-inl.h"
    114 #include "vm/NativeObject-inl.h"
    115 #include "vm/SavedStacks-inl.h"
    116 #include "vm/StringType-inl.h"
    117 
    118 using namespace js;
    119 
    120 using mozilla::Maybe;
    121 
    122 using JS::AutoStableStringChars;
    123 using JS::CompileOptions;
    124 using JS::ReadOnlyCompileOptions;
    125 
    126 // See preprocessor definition of JS_BITS_PER_WORD in jstypes.h; make sure
    127 // JS_64BIT (used internally) agrees with it
    128 #ifdef JS_64BIT
    129 static_assert(JS_BITS_PER_WORD == 64, "values must be in sync");
    130 #else
    131 static_assert(JS_BITS_PER_WORD == 32, "values must be in sync");
    132 #endif
    133 
    134 JS_PUBLIC_API void JS::CallArgs::reportMoreArgsNeeded(JSContext* cx,
    135                                                      const char* fnname,
    136                                                      unsigned required,
    137                                                      unsigned actual) {
    138  char requiredArgsStr[40];
    139  SprintfLiteral(requiredArgsStr, "%u", required);
    140  char actualArgsStr[40];
    141  SprintfLiteral(actualArgsStr, "%u", actual);
    142  JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    143                            JSMSG_MORE_ARGS_NEEDED, fnname, requiredArgsStr,
    144                            required == 1 ? "" : "s", actualArgsStr);
    145 }
    146 
    147 static bool ErrorTakesArguments(unsigned msg) {
    148  MOZ_ASSERT(msg < JSErr_Limit);
    149  unsigned argCount = js_ErrorFormatString[msg].argCount;
    150  MOZ_ASSERT(argCount <= 2);
    151  return argCount == 1 || argCount == 2;
    152 }
    153 
    154 static bool ErrorTakesObjectArgument(unsigned msg) {
    155  MOZ_ASSERT(msg < JSErr_Limit);
    156  unsigned argCount = js_ErrorFormatString[msg].argCount;
    157  MOZ_ASSERT(argCount <= 2);
    158  return argCount == 2;
    159 }
    160 
    161 bool JS::ObjectOpResult::reportError(JSContext* cx, HandleObject obj,
    162                                     HandleId id) {
    163  static_assert(unsigned(OkCode) == unsigned(JSMSG_NOT_AN_ERROR),
    164                "unsigned value of OkCode must not be an error code");
    165  MOZ_ASSERT(code_ != Uninitialized);
    166  MOZ_ASSERT(!ok());
    167  cx->check(obj);
    168 
    169  if (code_ == JSMSG_OBJECT_NOT_EXTENSIBLE) {
    170    RootedValue val(cx, ObjectValue(*obj));
    171    return ReportValueError(cx, code_, JSDVG_IGNORE_STACK, val, nullptr);
    172  }
    173 
    174  if (ErrorTakesArguments(code_)) {
    175    UniqueChars propName =
    176        IdToPrintableUTF8(cx, id, IdToPrintableBehavior::IdIsPropertyKey);
    177    if (!propName) {
    178      return false;
    179    }
    180 
    181    if (code_ == JSMSG_SET_NON_OBJECT_RECEIVER) {
    182      // We know that the original receiver was a primitive, so unbox it.
    183      RootedValue val(cx, ObjectValue(*obj));
    184      if (!obj->is<ProxyObject>()) {
    185        if (!Unbox(cx, obj, &val)) {
    186          return false;
    187        }
    188      }
    189      return ReportValueError(cx, code_, JSDVG_IGNORE_STACK, val, nullptr,
    190                              propName.get());
    191    }
    192 
    193    if (ErrorTakesObjectArgument(code_)) {
    194      JSObject* unwrapped = js::CheckedUnwrapStatic(obj);
    195      const char* name = unwrapped ? unwrapped->getClass()->name : "Object";
    196      JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, code_, name,
    197                               propName.get());
    198      return false;
    199    }
    200 
    201    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, code_,
    202                             propName.get());
    203    return false;
    204  }
    205  JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, code_);
    206  return false;
    207 }
    208 
    209 bool JS::ObjectOpResult::reportError(JSContext* cx, HandleObject obj) {
    210  MOZ_ASSERT(code_ != Uninitialized);
    211  MOZ_ASSERT(!ok());
    212  MOZ_ASSERT(!ErrorTakesArguments(code_));
    213  cx->check(obj);
    214 
    215  JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, code_);
    216  return false;
    217 }
    218 
    219 JS_PUBLIC_API bool JS::ObjectOpResult::failCantRedefineProp() {
    220  return fail(JSMSG_CANT_REDEFINE_PROP);
    221 }
    222 
    223 JS_PUBLIC_API bool JS::ObjectOpResult::failReadOnly() {
    224  return fail(JSMSG_READ_ONLY);
    225 }
    226 
    227 JS_PUBLIC_API bool JS::ObjectOpResult::failGetterOnly() {
    228  return fail(JSMSG_GETTER_ONLY);
    229 }
    230 
    231 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDelete() {
    232  return fail(JSMSG_CANT_DELETE);
    233 }
    234 
    235 JS_PUBLIC_API bool JS::ObjectOpResult::failCantSetInterposed() {
    236  return fail(JSMSG_CANT_SET_INTERPOSED);
    237 }
    238 
    239 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowElement() {
    240  return fail(JSMSG_CANT_DEFINE_WINDOW_ELEMENT);
    241 }
    242 
    243 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDeleteWindowElement() {
    244  return fail(JSMSG_CANT_DELETE_WINDOW_ELEMENT);
    245 }
    246 
    247 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowNamedProperty() {
    248  return fail(JSMSG_CANT_DEFINE_WINDOW_NAMED_PROPERTY);
    249 }
    250 
    251 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDeleteWindowNamedProperty() {
    252  return fail(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY);
    253 }
    254 
    255 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowNonConfigurable() {
    256  return fail(JSMSG_CANT_DEFINE_WINDOW_NC);
    257 }
    258 
    259 JS_PUBLIC_API bool JS::ObjectOpResult::failCantPreventExtensions() {
    260  return fail(JSMSG_CANT_PREVENT_EXTENSIONS);
    261 }
    262 
    263 JS_PUBLIC_API bool JS::ObjectOpResult::failCantSetProto() {
    264  return fail(JSMSG_CANT_SET_PROTO);
    265 }
    266 
    267 JS_PUBLIC_API bool JS::ObjectOpResult::failNoNamedSetter() {
    268  return fail(JSMSG_NO_NAMED_SETTER);
    269 }
    270 
    271 JS_PUBLIC_API bool JS::ObjectOpResult::failNoIndexedSetter() {
    272  return fail(JSMSG_NO_INDEXED_SETTER);
    273 }
    274 
    275 JS_PUBLIC_API bool JS::ObjectOpResult::failNotDataDescriptor() {
    276  return fail(JSMSG_NOT_DATA_DESCRIPTOR);
    277 }
    278 
    279 JS_PUBLIC_API bool JS::ObjectOpResult::failInvalidDescriptor() {
    280  return fail(JSMSG_INVALID_DESCRIPTOR);
    281 }
    282 
    283 JS_PUBLIC_API bool JS::ObjectOpResult::failBadArrayLength() {
    284  return fail(JSMSG_BAD_ARRAY_LENGTH);
    285 }
    286 
    287 JS_PUBLIC_API bool JS::ObjectOpResult::failBadIndex() {
    288  return fail(JSMSG_BAD_INDEX);
    289 }
    290 
    291 JS_PUBLIC_API int64_t JS_Now() { return PRMJ_Now(); }
    292 
    293 JS_PUBLIC_API Value JS_GetEmptyStringValue(JSContext* cx) {
    294  return StringValue(cx->runtime()->emptyString);
    295 }
    296 
    297 JS_PUBLIC_API JSString* JS_GetEmptyString(JSContext* cx) {
    298  MOZ_ASSERT(cx->emptyString());
    299  return cx->emptyString();
    300 }
    301 
    302 namespace js {
    303 
    304 void AssertHeapIsIdle() { MOZ_ASSERT(!JS::RuntimeHeapIsBusy()); }
    305 
    306 }  // namespace js
    307 
    308 static void AssertHeapIsIdleOrIterating() {
    309  MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
    310 }
    311 
    312 JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, HandleValue value,
    313                                    MutableHandleObject objp) {
    314  AssertHeapIsIdle();
    315  CHECK_THREAD(cx);
    316  cx->check(value);
    317  if (value.isNullOrUndefined()) {
    318    objp.set(nullptr);
    319    return true;
    320  }
    321  JSObject* obj = ToObject(cx, value);
    322  if (!obj) {
    323    return false;
    324  }
    325  objp.set(obj);
    326  return true;
    327 }
    328 
    329 JS_PUBLIC_API JSFunction* JS_ValueToFunction(JSContext* cx, HandleValue value) {
    330  AssertHeapIsIdle();
    331  CHECK_THREAD(cx);
    332  cx->check(value);
    333  return ReportIfNotFunction(cx, value);
    334 }
    335 
    336 JS_PUBLIC_API JSFunction* JS_ValueToConstructor(JSContext* cx,
    337                                                HandleValue value) {
    338  AssertHeapIsIdle();
    339  CHECK_THREAD(cx);
    340  cx->check(value);
    341  return ReportIfNotFunction(cx, value);
    342 }
    343 
    344 JS_PUBLIC_API JSString* JS_ValueToSource(JSContext* cx, HandleValue value) {
    345  AssertHeapIsIdle();
    346  CHECK_THREAD(cx);
    347  cx->check(value);
    348  return ValueToSource(cx, value);
    349 }
    350 
    351 JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip) {
    352  return mozilla::NumberIsInt32(d, ip);
    353 }
    354 
    355 JS_PUBLIC_API JSType JS_TypeOfValue(JSContext* cx, HandleValue value) {
    356  AssertHeapIsIdle();
    357  CHECK_THREAD(cx);
    358  cx->check(value);
    359  return TypeOfValue(value);
    360 }
    361 
    362 JS_PUBLIC_API bool JS_IsBuiltinEvalFunction(JSFunction* fun) {
    363  return IsAnyBuiltinEval(fun);
    364 }
    365 
    366 JS_PUBLIC_API bool JS_IsBuiltinFunctionConstructor(JSFunction* fun) {
    367  return fun->isBuiltinFunctionConstructor();
    368 }
    369 
    370 JS_PUBLIC_API bool JS_ObjectIsBoundFunction(JSObject* obj) {
    371  return obj->is<BoundFunctionObject>();
    372 }
    373 
    374 JS_PUBLIC_API JSObject* JS_GetBoundFunctionTarget(JSObject* obj) {
    375  return obj->is<BoundFunctionObject>()
    376             ? obj->as<BoundFunctionObject>().getTarget()
    377             : nullptr;
    378 }
    379 
    380 /************************************************************************/
    381 
    382 // Prevent functions from being discarded by linker, so that they are callable
    383 // when debugging.
    384 static void PreventDiscardingFunctions() {
    385  if (reinterpret_cast<uintptr_t>(&PreventDiscardingFunctions) == 1) {
    386    // Never executed.
    387    memset((void*)&js::debug::GetMarkInfo, 0, 1);
    388    memset((void*)&js::debug::GetMarkWordAddress, 0, 1);
    389    memset((void*)&js::debug::GetMarkMask, 0, 1);
    390  }
    391 }
    392 
    393 JS_PUBLIC_API JSContext* JS_NewContext(uint32_t maxbytes,
    394                                       JSRuntime* parentRuntime) {
    395  MOZ_ASSERT(JS::detail::libraryInitState == JS::detail::InitState::Running,
    396             "must call JS_Init prior to creating any JSContexts");
    397 
    398  // Prevent linker from discarding unused debug functions.
    399  PreventDiscardingFunctions();
    400 
    401  // Make sure that all parent runtimes are the topmost parent.
    402  while (parentRuntime && parentRuntime->parentRuntime) {
    403    parentRuntime = parentRuntime->parentRuntime;
    404  }
    405 
    406  return NewContext(maxbytes, parentRuntime);
    407 }
    408 
    409 JS_PUBLIC_API void JS_DestroyContext(JSContext* cx) { DestroyContext(cx); }
    410 
    411 JS_PUBLIC_API void* JS_GetContextPrivate(JSContext* cx) { return cx->data; }
    412 
    413 JS_PUBLIC_API void JS_SetContextPrivate(JSContext* cx, void* data) {
    414  cx->data = data;
    415 }
    416 
    417 JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx) {
    418  cx->fx.setCanWait(true);
    419 }
    420 
    421 JS_PUBLIC_API JSRuntime* JS_GetParentRuntime(JSContext* cx) {
    422  return cx->runtime()->parentRuntime ? cx->runtime()->parentRuntime
    423                                      : cx->runtime();
    424 }
    425 
    426 JS_PUBLIC_API JSRuntime* JS_GetRuntime(JSContext* cx) { return cx->runtime(); }
    427 
    428 JS_PUBLIC_API JS::ContextOptions& JS::ContextOptionsRef(JSContext* cx) {
    429  return cx->options();
    430 }
    431 
    432 JS::ContextOptions& JS::ContextOptions::setFuzzing(bool flag) {
    433 #ifdef FUZZING
    434  fuzzing_ = flag;
    435 #endif
    436  return *this;
    437 }
    438 
    439 JS_PUBLIC_API const char* JS_GetImplementationVersion(void) {
    440  return "JavaScript-C" MOZILLA_VERSION;
    441 }
    442 
    443 JS_PUBLIC_API void JS_SetDestroyZoneCallback(JSContext* cx,
    444                                             JSDestroyZoneCallback callback) {
    445  cx->runtime()->destroyZoneCallback = callback;
    446 }
    447 
    448 JS_PUBLIC_API void JS_SetDestroyCompartmentCallback(
    449    JSContext* cx, JSDestroyCompartmentCallback callback) {
    450  cx->runtime()->destroyCompartmentCallback = callback;
    451 }
    452 
    453 JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback(
    454    JSContext* cx, JSSizeOfIncludingThisCompartmentCallback callback) {
    455  cx->runtime()->sizeOfIncludingThisCompartmentCallback = callback;
    456 }
    457 
    458 JS_PUBLIC_API void JS_SetErrorInterceptorCallback(
    459    JSRuntime* rt, JSErrorInterceptor* callback) {
    460 #if defined(NIGHTLY_BUILD)
    461  rt->errorInterception.interceptor = callback;
    462 #endif  // defined(NIGHTLY_BUILD)
    463 }
    464 
    465 JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback(
    466    JSRuntime* rt) {
    467 #if defined(NIGHTLY_BUILD)
    468  return rt->errorInterception.interceptor;
    469 #else   // !NIGHTLY_BUILD
    470  return nullptr;
    471 #endif  // defined(NIGHTLY_BUILD)
    472 }
    473 
    474 JS_PUBLIC_API Maybe<JSExnType> JS_GetErrorType(const JS::Value& val) {
    475  // All errors are objects.
    476  if (!val.isObject()) {
    477    return mozilla::Nothing();
    478  }
    479 
    480  const JSObject& obj = val.toObject();
    481 
    482  // All errors are `ErrorObject`.
    483  if (!obj.is<js::ErrorObject>()) {
    484    // Not one of the primitive errors.
    485    return mozilla::Nothing();
    486  }
    487 
    488  const js::ErrorObject& err = obj.as<js::ErrorObject>();
    489  return mozilla::Some(err.type());
    490 }
    491 
    492 JS_PUBLIC_API void JS_SetWrapObjectCallbacks(
    493    JSContext* cx, const JSWrapObjectCallbacks* callbacks) {
    494  cx->runtime()->wrapObjectCallbacks = callbacks;
    495 }
    496 
    497 JS_PUBLIC_API Realm* JS::EnterRealm(JSContext* cx, JSObject* target) {
    498  AssertHeapIsIdle();
    499  CHECK_THREAD(cx);
    500 
    501  MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(target));
    502 
    503  Realm* oldRealm = cx->realm();
    504  cx->enterRealmOf(target);
    505  return oldRealm;
    506 }
    507 
    508 JS_PUBLIC_API void JS::LeaveRealm(JSContext* cx, JS::Realm* oldRealm) {
    509  AssertHeapIsIdle();
    510  CHECK_THREAD(cx);
    511  cx->leaveRealm(oldRealm);
    512 }
    513 
    514 JSAutoRealm::JSAutoRealm(JSContext* cx, JSObject* target)
    515    : cx_(cx), oldRealm_(cx->realm()) {
    516  MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(target));
    517  AssertHeapIsIdleOrIterating();
    518  cx_->enterRealmOf(target);
    519 }
    520 
    521 JSAutoRealm::JSAutoRealm(JSContext* cx, JSScript* target)
    522    : cx_(cx), oldRealm_(cx->realm()) {
    523  AssertHeapIsIdleOrIterating();
    524  cx_->enterRealmOf(target);
    525 }
    526 
    527 JSAutoRealm::~JSAutoRealm() { cx_->leaveRealm(oldRealm_); }
    528 
    529 JSAutoNullableRealm::JSAutoNullableRealm(JSContext* cx, JSObject* targetOrNull)
    530    : cx_(cx), oldRealm_(cx->realm()) {
    531  AssertHeapIsIdleOrIterating();
    532  if (targetOrNull) {
    533    MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(targetOrNull));
    534    cx_->enterRealmOf(targetOrNull);
    535  } else {
    536    cx_->enterNullRealm();
    537  }
    538 }
    539 
    540 JSAutoNullableRealm::~JSAutoNullableRealm() { cx_->leaveRealm(oldRealm_); }
    541 
    542 JS_PUBLIC_API void JS_SetCompartmentPrivate(JS::Compartment* compartment,
    543                                            void* data) {
    544  compartment->data = data;
    545 }
    546 
    547 JS_PUBLIC_API void* JS_GetCompartmentPrivate(JS::Compartment* compartment) {
    548  return compartment->data;
    549 }
    550 
    551 JS_PUBLIC_API void JS_MarkCrossZoneId(JSContext* cx, jsid id) {
    552  cx->markId(id);
    553 }
    554 
    555 JS_PUBLIC_API void JS_MarkCrossZoneIdValue(JSContext* cx, const Value& value) {
    556  cx->markAtomValue(value);
    557 }
    558 
    559 JS_PUBLIC_API void JS_SetZoneUserData(JS::Zone* zone, void* data) {
    560  zone->data = data;
    561 }
    562 
    563 JS_PUBLIC_API void* JS_GetZoneUserData(JS::Zone* zone) { return zone->data; }
    564 
    565 JS_PUBLIC_API bool JS_WrapObject(JSContext* cx, MutableHandleObject objp) {
    566  AssertHeapIsIdle();
    567  CHECK_THREAD(cx);
    568  if (objp) {
    569    JS::ExposeObjectToActiveJS(objp);
    570  }
    571  return cx->compartment()->wrap(cx, objp);
    572 }
    573 
    574 JS_PUBLIC_API bool JS_WrapValue(JSContext* cx, MutableHandleValue vp) {
    575  AssertHeapIsIdle();
    576  CHECK_THREAD(cx);
    577  JS::ExposeValueToActiveJS(vp);
    578  return cx->compartment()->wrap(cx, vp);
    579 }
    580 
    581 static void ReleaseAssertObjectHasNoWrappers(JSContext* cx,
    582                                             HandleObject target) {
    583  for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
    584    if (c->lookupWrapper(target)) {
    585      MOZ_CRASH("wrapper found for target object");
    586    }
    587  }
    588 }
    589 
    590 /*
    591 * [SMDOC] Brain transplants.
    592 *
    593 * Not for beginners or the squeamish.
    594 *
    595 * Sometimes a web spec requires us to transplant an object from one
    596 * compartment to another, like when a DOM node is inserted into a document in
    597 * another window and thus gets "adopted". We cannot literally change the
    598 * `.compartment()` of a `JSObject`; that would break the compartment
    599 * invariants. However, as usual, we have a workaround using wrappers.
    600 *
    601 * Of all the wrapper-based workarounds we do, it's safe to say this is the
    602 * most spectacular and questionable.
    603 *
    604 * `JS_TransplantObject(cx, origobj, target)` changes `origobj` into a
    605 * simulacrum of `target`, using highly esoteric means. To JS code, the effect
    606 * is as if `origobj` magically "became" `target`, but most often what actually
    607 * happens is that `origobj` gets turned into a cross-compartment wrapper for
    608 * `target`. The old behavior and contents of `origobj` are overwritten or
    609 * discarded.
    610 *
    611 * Thus, to "transplant" an object from one compartment to another:
    612 *
    613 * 1.  Let `origobj` be the object that you want to move. First, create a
    614 *     clone of it, `target`, in the destination compartment.
    615 *
    616 *     In our DOM adoption example, `target` will be a Node of the same type as
    617 *     `origobj`, same content, but in the adopting document.  We're not done
    618 *     yet: the spec for DOM adoption requires that `origobj.ownerDocument`
    619 *     actually change. All we've done so far is make a copy.
    620 *
    621 * 2.  Call `JS_TransplantObject(cx, origobj, target)`. This typically turns
    622 *     `origobj` into a wrapper for `target`, so that any JS code that has a
    623 *     reference to `origobj` will observe it to have the behavior of `target`
    624 *     going forward. In addition, all existing wrappers for `origobj` are
    625 *     changed into wrappers for `target`, extending the illusion to those
    626 *     compartments as well.
    627 *
    628 * During navigation, we use the above technique to transplant the WindowProxy
    629 * into the new Window's compartment.
    630 *
    631 * A few rules:
    632 *
    633 * -   `origobj` and `target` must be two distinct objects of the same
    634 *     `JSClass`.  Some classes may not support transplantation; WindowProxy
    635 *     objects and DOM nodes are OK.
    636 *
    637 * -   `target` should be created specifically to be passed to this function.
    638 *     There must be no existing cross-compartment wrappers for it; ideally
    639 *     there shouldn't be any pointers to it at all, except the one passed in.
    640 *
    641 * -   `target` shouldn't be used afterwards. Instead, `JS_TransplantObject`
    642 *     returns a pointer to the transplanted object, which might be `target`
    643 *     but might be some other object in the same compartment. Use that.
    644 *
    645 * The reason for this last rule is that JS_TransplantObject does very strange
    646 * things in some cases, like swapping `target`'s brain with that of another
    647 * object. Leaving `target` behaving like its former self is not a goal.
    648 *
    649 * We don't have a good way to recover from failure in this function, so
    650 * we intentionally crash instead.
    651 */
    652 
    653 static void CheckTransplantObject(JSObject* obj) {
    654 #ifdef DEBUG
    655  MOZ_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
    656  JS::AssertCellIsNotGray(obj);
    657 #endif
    658 }
    659 
    660 JS_PUBLIC_API JSObject* JS_TransplantObject(JSContext* cx, HandleObject origobj,
    661                                            HandleObject target) {
    662  AssertHeapIsIdle();
    663  MOZ_ASSERT(origobj != target);
    664  CheckTransplantObject(origobj);
    665  CheckTransplantObject(target);
    666  ReleaseAssertObjectHasNoWrappers(cx, target);
    667 
    668  RootedObject newIdentity(cx);
    669 
    670  // Don't allow a compacting GC to observe any intermediate state.
    671  AutoDisableCompactingGC nocgc(cx);
    672 
    673  AutoDisableProxyCheck adpc;
    674 
    675  AutoEnterOOMUnsafeRegion oomUnsafe;
    676 
    677  JS::Compartment* destination = target->compartment();
    678 
    679  if (origobj->compartment() == destination) {
    680    // If the original object is in the same compartment as the
    681    // destination, then we know that we won't find a wrapper in the
    682    // destination's cross compartment map and that the same
    683    // object will continue to work.
    684    AutoRealm ar(cx, origobj);
    685    JSObject::swap(cx, origobj, target, oomUnsafe);
    686    newIdentity = origobj;
    687  } else if (ObjectWrapperMap::Ptr p = destination->lookupWrapper(origobj)) {
    688    // There might already be a wrapper for the original object in
    689    // the new compartment. If there is, we use its identity and swap
    690    // in the contents of |target|.
    691    newIdentity = p->value().get();
    692 
    693    // When we remove origv from the wrapper map, its wrapper, newIdentity,
    694    // must immediately cease to be a cross-compartment wrapper. Nuke it.
    695    destination->removeWrapper(p);
    696    NukeCrossCompartmentWrapper(cx, newIdentity);
    697 
    698    AutoRealm ar(cx, newIdentity);
    699    JSObject::swap(cx, newIdentity, target, oomUnsafe);
    700  } else {
    701    // Otherwise, we use |target| for the new identity object.
    702    newIdentity = target;
    703  }
    704 
    705  // Now, iterate through other scopes looking for references to the old
    706  // object, and update the relevant cross-compartment wrappers. We do this
    707  // even if origobj is in the same compartment as target and thus
    708  // `newIdentity == origobj`, because this process also clears out any
    709  // cached wrapper state.
    710  if (!RemapAllWrappersForObject(cx, origobj, newIdentity)) {
    711    oomUnsafe.crash("JS_TransplantObject");
    712  }
    713 
    714  // Lastly, update the original object to point to the new one.
    715  if (origobj->compartment() != destination) {
    716    RootedObject newIdentityWrapper(cx, newIdentity);
    717    AutoRealm ar(cx, origobj);
    718    if (!JS_WrapObject(cx, &newIdentityWrapper)) {
    719      MOZ_RELEASE_ASSERT(cx->isThrowingOutOfMemory() ||
    720                         cx->isThrowingOverRecursed());
    721      oomUnsafe.crash("JS_TransplantObject");
    722    }
    723    MOZ_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
    724    JSObject::swap(cx, origobj, newIdentityWrapper, oomUnsafe);
    725    if (origobj->compartment()->lookupWrapper(newIdentity)) {
    726      MOZ_ASSERT(origobj->is<CrossCompartmentWrapperObject>());
    727      if (!origobj->compartment()->putWrapper(cx, newIdentity, origobj)) {
    728        oomUnsafe.crash("JS_TransplantObject");
    729      }
    730    }
    731  }
    732 
    733  // The new identity object might be one of several things. Return it to avoid
    734  // ambiguity.
    735  JS::AssertCellIsNotGray(newIdentity);
    736  return newIdentity;
    737 }
    738 
    739 JS_PUBLIC_API void js::RemapRemoteWindowProxies(
    740    JSContext* cx, CompartmentTransplantCallback* callback,
    741    MutableHandleObject target) {
    742  AssertHeapIsIdle();
    743  CheckTransplantObject(target);
    744  ReleaseAssertObjectHasNoWrappers(cx, target);
    745 
    746  // |target| can't be a remote proxy, because we expect it to get a CCW when
    747  // wrapped across compartments.
    748  MOZ_ASSERT(!js::IsDOMRemoteProxyObject(target));
    749 
    750  // Don't allow a compacting GC to observe any intermediate state.
    751  AutoDisableCompactingGC nocgc(cx);
    752 
    753  AutoDisableProxyCheck adpc;
    754 
    755  AutoEnterOOMUnsafeRegion oomUnsafe;
    756 
    757  AutoCheckRecursionLimit recursion(cx);
    758  if (!recursion.checkSystem(cx)) {
    759    oomUnsafe.crash("js::RemapRemoteWindowProxies");
    760  }
    761 
    762  RootedObject targetCompartmentProxy(cx);
    763  JS::RootedVector<JSObject*> otherProxies(cx);
    764 
    765  // Use the callback to find remote proxies in all compartments that match
    766  // whatever criteria callback uses.
    767  for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
    768    RootedObject remoteProxy(cx, callback->getObjectToTransplant(c));
    769    if (!remoteProxy) {
    770      continue;
    771    }
    772    // The object the callback returns should be a DOM remote proxy object in
    773    // the compartment c. We rely on it being a DOM remote proxy because that
    774    // means that it won't have any cross-compartment wrappers.
    775    MOZ_ASSERT(js::IsDOMRemoteProxyObject(remoteProxy));
    776    MOZ_ASSERT(remoteProxy->compartment() == c);
    777    CheckTransplantObject(remoteProxy);
    778 
    779    // Immediately turn the DOM remote proxy object into a dead proxy object
    780    // so we don't have to worry about anything weird going on with it.
    781    js::NukeNonCCWProxy(cx, remoteProxy);
    782 
    783    if (remoteProxy->compartment() == target->compartment()) {
    784      targetCompartmentProxy = remoteProxy;
    785    } else if (!otherProxies.append(remoteProxy)) {
    786      oomUnsafe.crash("js::RemapRemoteWindowProxies");
    787    }
    788  }
    789 
    790  // If there was a remote proxy in |target|'s compartment, we need to use it
    791  // instead of |target|, in case it had any references, so swap it. Do this
    792  // before any other compartment so that the target object will be set up
    793  // correctly before we start wrapping it into other compartments.
    794  if (targetCompartmentProxy) {
    795    AutoRealm ar(cx, targetCompartmentProxy);
    796    JSObject::swap(cx, targetCompartmentProxy, target, oomUnsafe);
    797    target.set(targetCompartmentProxy);
    798  }
    799 
    800  for (JSObject*& obj : otherProxies) {
    801    RootedObject deadWrapper(cx, obj);
    802    js::RemapDeadWrapper(cx, deadWrapper, target);
    803  }
    804 }
    805 
    806 /*
    807 * Recompute all cross-compartment wrappers for an object, resetting state.
    808 * Gecko uses this to clear Xray wrappers when doing a navigation that reuses
    809 * the inner window and global object.
    810 */
    811 JS_PUBLIC_API bool JS_RefreshCrossCompartmentWrappers(JSContext* cx,
    812                                                      HandleObject obj) {
    813  return RemapAllWrappersForObject(cx, obj, obj);
    814 }
    815 
    816 struct JSStdName {
    817  size_t atomOffset; /* offset of atom pointer in JSAtomState */
    818  JSProtoKey key;
    819  bool isDummy() const { return key == JSProto_Null; }
    820  bool isSentinel() const { return key == JSProto_LIMIT; }
    821 };
    822 
    823 static const JSStdName* LookupStdName(const JSAtomState& names, JSAtom* name,
    824                                      const JSStdName* table) {
    825  for (unsigned i = 0; !table[i].isSentinel(); i++) {
    826    if (table[i].isDummy()) {
    827      continue;
    828    }
    829    JSAtom* atom = AtomStateOffsetToName(names, table[i].atomOffset);
    830    MOZ_ASSERT(atom);
    831    if (name == atom) {
    832      return &table[i];
    833    }
    834  }
    835 
    836  return nullptr;
    837 }
    838 
    839 /*
    840 * Table of standard classes, indexed by JSProtoKey. For entries where the
    841 * JSProtoKey does not correspond to a class with a meaningful constructor, we
    842 * insert a null entry into the table.
    843 */
    844 #define STD_NAME_ENTRY(name, clasp) {NAME_OFFSET(name), JSProto_##name},
    845 #define STD_DUMMY_ENTRY(name, dummy) {0, JSProto_Null},
    846 static const JSStdName standard_class_names[] = {
    847    JS_FOR_PROTOTYPES(STD_NAME_ENTRY, STD_DUMMY_ENTRY){0, JSProto_LIMIT}};
    848 
    849 /*
    850 * Table of top-level function and constant names and the JSProtoKey of the
    851 * standard class that initializes them.
    852 */
    853 static const JSStdName builtin_property_names[] = {
    854    {NAME_OFFSET(eval), JSProto_Object},
    855 
    856    /* Global properties and functions defined by the Number class. */
    857    {NAME_OFFSET(NaN), JSProto_Number},
    858    {NAME_OFFSET(Infinity), JSProto_Number},
    859    {NAME_OFFSET(isNaN), JSProto_Number},
    860    {NAME_OFFSET(isFinite), JSProto_Number},
    861    {NAME_OFFSET(parseFloat), JSProto_Number},
    862    {NAME_OFFSET(parseInt), JSProto_Number},
    863 
    864    /* String global functions. */
    865    {NAME_OFFSET(escape), JSProto_String},
    866    {NAME_OFFSET(unescape), JSProto_String},
    867    {NAME_OFFSET(decodeURI), JSProto_String},
    868    {NAME_OFFSET(encodeURI), JSProto_String},
    869    {NAME_OFFSET(decodeURIComponent), JSProto_String},
    870    {NAME_OFFSET(encodeURIComponent), JSProto_String},
    871    {NAME_OFFSET(uneval), JSProto_String},
    872 
    873    {0, JSProto_LIMIT}};
    874 
    875 static bool SkipUneval(jsid id, JSContext* cx) {
    876  return !cx->realm()->creationOptions().getToSourceEnabled() &&
    877         id == NameToId(cx->names().uneval);
    878 }
    879 
    880 static bool SkipSharedArrayBufferConstructor(JSProtoKey key,
    881                                             GlobalObject* global) {
    882  if (key != JSProto_SharedArrayBuffer) {
    883    return false;
    884  }
    885 
    886  const JS::RealmCreationOptions& options = global->realm()->creationOptions();
    887  MOZ_ASSERT(options.getSharedMemoryAndAtomicsEnabled(),
    888             "shouldn't contemplate defining SharedArrayBuffer if shared "
    889             "memory is disabled");
    890 
    891  // On the web, it isn't presently possible to expose the global
    892  // "SharedArrayBuffer" property unless the page is cross-site-isolated.  Only
    893  // define this constructor if an option on the realm indicates that it should
    894  // be defined.
    895  return !options.defineSharedArrayBufferConstructor();
    896 }
    897 
    898 JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx, HandleObject obj,
    899                                           HandleId id, bool* resolved) {
    900  AssertHeapIsIdle();
    901  CHECK_THREAD(cx);
    902  cx->check(obj, id);
    903 
    904  Handle<GlobalObject*> global = obj.as<GlobalObject>();
    905  *resolved = false;
    906 
    907  if (!id.isAtom()) {
    908    return true;
    909  }
    910 
    911  /* Check whether we're resolving 'undefined', and define it if so. */
    912  JSAtom* idAtom = id.toAtom();
    913  if (idAtom == cx->names().undefined) {
    914    *resolved = true;
    915    return js::DefineDataProperty(
    916        cx, global, id, UndefinedHandleValue,
    917        JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING);
    918  }
    919 
    920  // Resolve a "globalThis" self-referential property if necessary.
    921  if (idAtom == cx->names().globalThis) {
    922    return GlobalObject::maybeResolveGlobalThis(cx, global, resolved);
    923  }
    924 
    925  // Try for class constructors/prototypes named by well-known atoms.
    926  const JSStdName* stdnm =
    927      LookupStdName(cx->names(), idAtom, standard_class_names);
    928  if (!stdnm) {
    929    // Try less frequently used top-level functions and constants.
    930    stdnm = LookupStdName(cx->names(), idAtom, builtin_property_names);
    931    if (!stdnm) {
    932      return true;
    933    }
    934  }
    935 
    936  JSProtoKey key = stdnm->key;
    937  if (key == JSProto_Null || GlobalObject::skipDeselectedConstructor(cx, key) ||
    938      SkipUneval(id, cx)) {
    939    return true;
    940  }
    941 
    942  // If this class is anonymous (or it's "SharedArrayBuffer" but that global
    943  // constructor isn't supposed to be defined), then it doesn't exist as a
    944  // global property, so we won't resolve anything.
    945  const JSClass* clasp = ProtoKeyToClass(key);
    946  if (clasp && !clasp->specShouldDefineConstructor()) {
    947    return true;
    948  }
    949  if (SkipSharedArrayBufferConstructor(key, global)) {
    950    return true;
    951  }
    952 
    953  if (!GlobalObject::ensureConstructor(cx, global, key)) {
    954    return false;
    955  }
    956  *resolved = true;
    957  return true;
    958 }
    959 
    960 JS_PUBLIC_API bool JS_MayResolveStandardClass(const JSAtomState& names, jsid id,
    961                                              JSObject* maybeObj) {
    962  MOZ_ASSERT_IF(maybeObj, maybeObj->is<GlobalObject>());
    963 
    964  // The global object's resolve hook is special: JS_ResolveStandardClass
    965  // initializes the prototype chain lazily. Only attempt to optimize here
    966  // if we know the prototype chain has been initialized.
    967  if (!maybeObj || !maybeObj->staticPrototype()) {
    968    return true;
    969  }
    970 
    971  if (!id.isAtom()) {
    972    return false;
    973  }
    974 
    975  JSAtom* atom = id.toAtom();
    976 
    977  // This will return true even for deselected constructors.  (To do
    978  // better, we need a JSContext here; it's fine as it is.)
    979 
    980  return atom == names.undefined || atom == names.globalThis ||
    981         LookupStdName(names, atom, standard_class_names) ||
    982         LookupStdName(names, atom, builtin_property_names);
    983 }
    984 
    985 JS_PUBLIC_API bool JS_EnumerateStandardClasses(JSContext* cx,
    986                                               HandleObject obj) {
    987  AssertHeapIsIdle();
    988  CHECK_THREAD(cx);
    989  cx->check(obj);
    990  Handle<GlobalObject*> global = obj.as<GlobalObject>();
    991  return GlobalObject::initStandardClasses(cx, global);
    992 }
    993 
    994 static bool EnumerateStandardClassesInTable(JSContext* cx,
    995                                            Handle<GlobalObject*> global,
    996                                            MutableHandleIdVector properties,
    997                                            const JSStdName* table,
    998                                            bool includeResolved) {
    999  for (unsigned i = 0; !table[i].isSentinel(); i++) {
   1000    if (table[i].isDummy()) {
   1001      continue;
   1002    }
   1003 
   1004    JSProtoKey key = table[i].key;
   1005 
   1006    // If the standard class has been resolved, the properties have been
   1007    // defined on the global so we don't need to add them here.
   1008    if (!includeResolved && global->isStandardClassResolved(key)) {
   1009      continue;
   1010    }
   1011 
   1012    if (GlobalObject::skipDeselectedConstructor(cx, key)) {
   1013      continue;
   1014    }
   1015 
   1016    if (const JSClass* clasp = ProtoKeyToClass(key)) {
   1017      if (!clasp->specShouldDefineConstructor() ||
   1018          SkipSharedArrayBufferConstructor(key, global)) {
   1019        continue;
   1020      }
   1021    }
   1022 
   1023    jsid id = NameToId(AtomStateOffsetToName(cx->names(), table[i].atomOffset));
   1024 
   1025    if (SkipUneval(id, cx)) {
   1026      continue;
   1027    }
   1028 
   1029    if (!properties.append(id)) {
   1030      return false;
   1031    }
   1032  }
   1033 
   1034  return true;
   1035 }
   1036 
   1037 static bool EnumerateStandardClasses(JSContext* cx, JS::HandleObject obj,
   1038                                     JS::MutableHandleIdVector properties,
   1039                                     bool enumerableOnly,
   1040                                     bool includeResolved) {
   1041  if (enumerableOnly) {
   1042    // There are no enumerable standard classes and "undefined" is
   1043    // not enumerable.
   1044    return true;
   1045  }
   1046 
   1047  Handle<GlobalObject*> global = obj.as<GlobalObject>();
   1048 
   1049  // It's fine to always append |undefined| here, it's non-configurable and
   1050  // the enumeration code filters duplicates.
   1051  if (!properties.append(NameToId(cx->names().undefined))) {
   1052    return false;
   1053  }
   1054 
   1055  bool resolved = false;
   1056  if (!GlobalObject::maybeResolveGlobalThis(cx, global, &resolved)) {
   1057    return false;
   1058  }
   1059  if (resolved || includeResolved) {
   1060    if (!properties.append(NameToId(cx->names().globalThis))) {
   1061      return false;
   1062    }
   1063  }
   1064 
   1065  if (!EnumerateStandardClassesInTable(cx, global, properties,
   1066                                       standard_class_names, includeResolved)) {
   1067    return false;
   1068  }
   1069  if (!EnumerateStandardClassesInTable(
   1070          cx, global, properties, builtin_property_names, includeResolved)) {
   1071    return false;
   1072  }
   1073 
   1074  return true;
   1075 }
   1076 
   1077 JS_PUBLIC_API bool JS_NewEnumerateStandardClasses(
   1078    JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
   1079    bool enumerableOnly) {
   1080  return EnumerateStandardClasses(cx, obj, properties, enumerableOnly, false);
   1081 }
   1082 
   1083 JS_PUBLIC_API bool JS_NewEnumerateStandardClassesIncludingResolved(
   1084    JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
   1085    bool enumerableOnly) {
   1086  return EnumerateStandardClasses(cx, obj, properties, enumerableOnly, true);
   1087 }
   1088 
   1089 JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key,
   1090                                     MutableHandleObject objp) {
   1091  AssertHeapIsIdle();
   1092  CHECK_THREAD(cx);
   1093  JSObject* obj = GlobalObject::getOrCreateConstructor(cx, key);
   1094  if (!obj) {
   1095    return false;
   1096  }
   1097  objp.set(obj);
   1098  return true;
   1099 }
   1100 
   1101 JS_PUBLIC_API bool JS_GetClassPrototype(JSContext* cx, JSProtoKey key,
   1102                                        MutableHandleObject objp) {
   1103  AssertHeapIsIdle();
   1104  CHECK_THREAD(cx);
   1105 
   1106  // Bound functions don't have their own prototype object: they reuse the
   1107  // prototype of the target object. This is typically Function.prototype so we
   1108  // use that here.
   1109  if (key == JSProto_BoundFunction) {
   1110    key = JSProto_Function;
   1111  }
   1112 
   1113  JSObject* proto = GlobalObject::getOrCreatePrototype(cx, key);
   1114  if (!proto) {
   1115    return false;
   1116  }
   1117  objp.set(proto);
   1118  return true;
   1119 }
   1120 
   1121 namespace JS {
   1122 
   1123 JS_PUBLIC_API void ProtoKeyToId(JSContext* cx, JSProtoKey key,
   1124                                MutableHandleId idp) {
   1125  idp.set(NameToId(ClassName(key, cx)));
   1126 }
   1127 
   1128 } /* namespace JS */
   1129 
   1130 JS_PUBLIC_API JSProtoKey JS_IdToProtoKey(JSContext* cx, HandleId id) {
   1131  AssertHeapIsIdle();
   1132  CHECK_THREAD(cx);
   1133  cx->check(id);
   1134 
   1135  if (!id.isAtom()) {
   1136    return JSProto_Null;
   1137  }
   1138 
   1139  JSAtom* atom = id.toAtom();
   1140  const JSStdName* stdnm =
   1141      LookupStdName(cx->names(), atom, standard_class_names);
   1142  if (!stdnm) {
   1143    return JSProto_Null;
   1144  }
   1145 
   1146  if (GlobalObject::skipDeselectedConstructor(cx, stdnm->key)) {
   1147    return JSProto_Null;
   1148  }
   1149 
   1150  if (SkipSharedArrayBufferConstructor(stdnm->key, cx->global())) {
   1151    MOZ_ASSERT(id == NameToId(cx->names().SharedArrayBuffer));
   1152    return JSProto_Null;
   1153  }
   1154 
   1155  if (SkipUneval(id, cx)) {
   1156    return JSProto_Null;
   1157  }
   1158 
   1159  static_assert(std::size(standard_class_names) == JSProto_LIMIT + 1);
   1160  return static_cast<JSProtoKey>(stdnm - standard_class_names);
   1161 }
   1162 
   1163 extern JS_PUBLIC_API bool JS_IsGlobalObject(JSObject* obj) {
   1164  return obj->is<GlobalObject>();
   1165 }
   1166 
   1167 extern JS_PUBLIC_API JSObject* JS_GlobalLexicalEnvironment(JSObject* obj) {
   1168  return &obj->as<GlobalObject>().lexicalEnvironment();
   1169 }
   1170 
   1171 extern JS_PUBLIC_API bool JS_HasExtensibleLexicalEnvironment(JSObject* obj) {
   1172  return obj->is<GlobalObject>() ||
   1173         ObjectRealm::get(obj).getNonSyntacticLexicalEnvironment(obj);
   1174 }
   1175 
   1176 extern JS_PUBLIC_API JSObject* JS_ExtensibleLexicalEnvironment(JSObject* obj) {
   1177  return ExtensibleLexicalEnvironmentObject::forVarEnvironment(obj);
   1178 }
   1179 
   1180 JS_PUBLIC_API JSObject* JS::CurrentGlobalOrNull(JSContext* cx) {
   1181  AssertHeapIsIdleOrIterating();
   1182  CHECK_THREAD(cx);
   1183  if (!cx->realm()) {
   1184    return nullptr;
   1185  }
   1186  return cx->global();
   1187 }
   1188 
   1189 JS_PUBLIC_API JSObject* JS::GetNonCCWObjectGlobal(JSObject* obj) {
   1190  AssertHeapIsIdleOrIterating();
   1191  MOZ_DIAGNOSTIC_ASSERT(!IsCrossCompartmentWrapper(obj));
   1192  return &obj->nonCCWGlobal();
   1193 }
   1194 
   1195 JS_PUBLIC_API bool JS::detail::ComputeThis(JSContext* cx, Value* vp,
   1196                                           MutableHandleObject thisObject) {
   1197  AssertHeapIsIdle();
   1198  cx->check(vp[0], vp[1]);
   1199 
   1200  MutableHandleValue thisv = MutableHandleValue::fromMarkedLocation(&vp[1]);
   1201  JSObject* obj = BoxNonStrictThis(cx, thisv);
   1202  if (!obj) {
   1203    return false;
   1204  }
   1205 
   1206  thisObject.set(obj);
   1207  return true;
   1208 }
   1209 
   1210 static bool gProfileTimelineRecordingEnabled = false;
   1211 
   1212 JS_PUBLIC_API void JS::SetProfileTimelineRecordingEnabled(bool enabled) {
   1213  gProfileTimelineRecordingEnabled = enabled;
   1214 }
   1215 
   1216 JS_PUBLIC_API bool JS::IsProfileTimelineRecordingEnabled() {
   1217  return gProfileTimelineRecordingEnabled;
   1218 }
   1219 
   1220 JS_PUBLIC_API void* JS_malloc(JSContext* cx, size_t nbytes) {
   1221  AssertHeapIsIdle();
   1222  CHECK_THREAD(cx);
   1223  return static_cast<void*>(cx->maybe_pod_malloc<uint8_t>(nbytes));
   1224 }
   1225 
   1226 JS_PUBLIC_API void* JS_realloc(JSContext* cx, void* p, size_t oldBytes,
   1227                               size_t newBytes) {
   1228  AssertHeapIsIdle();
   1229  CHECK_THREAD(cx);
   1230  return static_cast<void*>(cx->maybe_pod_realloc<uint8_t>(
   1231      static_cast<uint8_t*>(p), oldBytes, newBytes));
   1232 }
   1233 
   1234 JS_PUBLIC_API void JS_free(JSContext* cx, void* p) { return js_free(p); }
   1235 
   1236 JS_PUBLIC_API void* JS_string_malloc(JSContext* cx, size_t nbytes) {
   1237  AssertHeapIsIdle();
   1238  CHECK_THREAD(cx);
   1239  return static_cast<void*>(
   1240      cx->maybe_pod_arena_malloc<uint8_t>(js::StringBufferArena, nbytes));
   1241 }
   1242 
   1243 JS_PUBLIC_API void* JS_string_realloc(JSContext* cx, void* p, size_t oldBytes,
   1244                                      size_t newBytes) {
   1245  AssertHeapIsIdle();
   1246  CHECK_THREAD(cx);
   1247  return static_cast<void*>(cx->maybe_pod_arena_realloc<uint8_t>(
   1248      js::StringBufferArena, static_cast<uint8_t*>(p), oldBytes, newBytes));
   1249 }
   1250 
   1251 JS_PUBLIC_API void JS_string_free(JSContext* cx, void* p) { return js_free(p); }
   1252 
   1253 JS_PUBLIC_API void JS::AddAssociatedMemory(JSObject* obj, size_t nbytes,
   1254                                           JS::MemoryUse use) {
   1255  MOZ_ASSERT(obj);
   1256  if (!nbytes) {
   1257    return;
   1258  }
   1259 
   1260  Zone* zone = obj->zone();
   1261  MOZ_ASSERT(!IsInsideNursery(obj));
   1262  zone->addCellMemory(obj, nbytes, js::MemoryUse(use));
   1263  zone->maybeTriggerGCOnMalloc();
   1264 }
   1265 
   1266 JS_PUBLIC_API void JS::RemoveAssociatedMemory(JSObject* obj, size_t nbytes,
   1267                                              JS::MemoryUse use) {
   1268  MOZ_ASSERT(obj);
   1269  if (!nbytes) {
   1270    return;
   1271  }
   1272 
   1273  GCContext* gcx = obj->runtimeFromMainThread()->gcContext();
   1274  gcx->removeCellMemory(obj, nbytes, js::MemoryUse(use));
   1275 }
   1276 
   1277 #undef JS_AddRoot
   1278 
   1279 JS_PUBLIC_API bool JS_AddExtraGCRootsTracer(JSContext* cx,
   1280                                            JSTraceDataOp traceOp, void* data) {
   1281  return cx->runtime()->gc.addBlackRootsTracer(traceOp, data);
   1282 }
   1283 
   1284 JS_PUBLIC_API void JS_RemoveExtraGCRootsTracer(JSContext* cx,
   1285                                               JSTraceDataOp traceOp,
   1286                                               void* data) {
   1287  return cx->runtime()->gc.removeBlackRootsTracer(traceOp, data);
   1288 }
   1289 
   1290 JS_PUBLIC_API JS::GCReason JS::WantEagerMinorGC(JSRuntime* rt) {
   1291  if (rt->gc.nursery().wantEagerCollection()) {
   1292    return JS::GCReason::EAGER_NURSERY_COLLECTION;
   1293  }
   1294  return JS::GCReason::NO_REASON;
   1295 }
   1296 
   1297 JS_PUBLIC_API JS::GCReason JS::WantEagerMajorGC(JSRuntime* rt) {
   1298  return rt->gc.wantMajorGC(true);
   1299 }
   1300 
   1301 JS_PUBLIC_API void JS::MaybeRunNurseryCollection(JSRuntime* rt,
   1302                                                 JS::GCReason reason) {
   1303  gc::GCRuntime& gc = rt->gc;
   1304  if (gc.nursery().wantEagerCollection()) {
   1305    gc.minorGC(reason);
   1306  }
   1307 }
   1308 
   1309 JS_PUBLIC_API void JS::RunNurseryCollection(
   1310    JSRuntime* rt, JS::GCReason reason,
   1311    mozilla::TimeDuration aSinceLastMinorGC) {
   1312  gc::GCRuntime& gc = rt->gc;
   1313  if (!gc.nursery().lastCollectionEndTime() ||
   1314      (mozilla::TimeStamp::Now() - gc.nursery().lastCollectionEndTime() >
   1315       aSinceLastMinorGC)) {
   1316    gc.minorGC(reason);
   1317  }
   1318 }
   1319 
   1320 JS_PUBLIC_API void JS_GC(JSContext* cx, JS::GCReason reason) {
   1321  AssertHeapIsIdle();
   1322  JS::PrepareForFullGC(cx);
   1323  cx->runtime()->gc.gc(JS::GCOptions::Normal, reason);
   1324 }
   1325 
   1326 JS_PUBLIC_API void JS_MaybeGC(JSContext* cx) {
   1327  AssertHeapIsIdle();
   1328  cx->runtime()->gc.maybeGC();
   1329 }
   1330 
   1331 JS_PUBLIC_API void JS_SetGCCallback(JSContext* cx, JSGCCallback cb,
   1332                                    void* data) {
   1333  AssertHeapIsIdle();
   1334  cx->runtime()->gc.setGCCallback(cb, data);
   1335 }
   1336 
   1337 JS_PUBLIC_API void JS_SetObjectsTenuredCallback(JSContext* cx,
   1338                                                JSObjectsTenuredCallback cb,
   1339                                                void* data) {
   1340  AssertHeapIsIdle();
   1341  cx->runtime()->gc.setObjectsTenuredCallback(cb, data);
   1342 }
   1343 
   1344 JS_PUBLIC_API bool JS_AddFinalizeCallback(JSContext* cx, JSFinalizeCallback cb,
   1345                                          void* data) {
   1346  AssertHeapIsIdle();
   1347  return cx->runtime()->gc.addFinalizeCallback(cb, data);
   1348 }
   1349 
   1350 JS_PUBLIC_API void JS_RemoveFinalizeCallback(JSContext* cx,
   1351                                             JSFinalizeCallback cb) {
   1352  cx->runtime()->gc.removeFinalizeCallback(cb);
   1353 }
   1354 
   1355 JS_PUBLIC_API void JS::SetHostCleanupFinalizationRegistryCallback(
   1356    JSContext* cx, JSHostCleanupFinalizationRegistryCallback cb, void* data) {
   1357  AssertHeapIsIdle();
   1358  cx->runtime()->gc.setHostCleanupFinalizationRegistryCallback(cb, data);
   1359 }
   1360 
   1361 JS_PUBLIC_API void JS::ClearKeptObjects(JSContext* cx) {
   1362  gc::GCRuntime* gc = &cx->runtime()->gc;
   1363 
   1364  for (ZonesIter zone(gc, ZoneSelector::WithAtoms); !zone.done(); zone.next()) {
   1365    zone->clearKeptObjects();
   1366  }
   1367 }
   1368 
   1369 JS_PUBLIC_API bool JS::AtomsZoneIsCollecting(JSRuntime* runtime) {
   1370  return runtime->activeGCInAtomsZone();
   1371 }
   1372 
   1373 JS_PUBLIC_API bool JS::IsAtomsZone(JS::Zone* zone) {
   1374  return zone->isAtomsZone();
   1375 }
   1376 
   1377 JS_PUBLIC_API bool JS_AddWeakPointerZonesCallback(JSContext* cx,
   1378                                                  JSWeakPointerZonesCallback cb,
   1379                                                  void* data) {
   1380  AssertHeapIsIdle();
   1381  return cx->runtime()->gc.addWeakPointerZonesCallback(cb, data);
   1382 }
   1383 
   1384 JS_PUBLIC_API void JS_RemoveWeakPointerZonesCallback(
   1385    JSContext* cx, JSWeakPointerZonesCallback cb) {
   1386  cx->runtime()->gc.removeWeakPointerZonesCallback(cb);
   1387 }
   1388 
   1389 JS_PUBLIC_API bool JS_AddWeakPointerCompartmentCallback(
   1390    JSContext* cx, JSWeakPointerCompartmentCallback cb, void* data) {
   1391  AssertHeapIsIdle();
   1392  return cx->runtime()->gc.addWeakPointerCompartmentCallback(cb, data);
   1393 }
   1394 
   1395 JS_PUBLIC_API void JS_RemoveWeakPointerCompartmentCallback(
   1396    JSContext* cx, JSWeakPointerCompartmentCallback cb) {
   1397  cx->runtime()->gc.removeWeakPointerCompartmentCallback(cb);
   1398 }
   1399 
   1400 JS_PUBLIC_API bool JS_UpdateWeakPointerAfterGC(JSTracer* trc,
   1401                                               JS::Heap<JSObject*>* objp) {
   1402  return TraceWeakEdge(trc, objp);
   1403 }
   1404 
   1405 JS_PUBLIC_API bool JS_UpdateWeakPointerAfterGCUnbarriered(JSTracer* trc,
   1406                                                          JSObject** objp) {
   1407  return TraceManuallyBarrieredWeakEdge(trc, objp, "External weak pointer");
   1408 }
   1409 
   1410 JS_PUBLIC_API void JS_SetGCParameter(JSContext* cx, JSGCParamKey key,
   1411                                     uint32_t value) {
   1412  // Bug 1742118: JS_SetGCParameter has no way to return an error
   1413  // The GC ignores invalid values internally but this is not reported to the
   1414  // caller.
   1415  (void)cx->runtime()->gc.setParameter(cx, key, value);
   1416 }
   1417 
   1418 JS_PUBLIC_API void JS_ResetGCParameter(JSContext* cx, JSGCParamKey key) {
   1419  cx->runtime()->gc.resetParameter(cx, key);
   1420 }
   1421 
   1422 JS_PUBLIC_API uint32_t JS_GetGCParameter(JSContext* cx, JSGCParamKey key) {
   1423  return cx->runtime()->gc.getParameter(key);
   1424 }
   1425 
   1426 JS_PUBLIC_API void JS_SetGCParametersBasedOnAvailableMemory(
   1427    JSContext* cx, uint32_t availMemMB) {
   1428  struct JSGCConfig {
   1429    JSGCParamKey key;
   1430    uint32_t value;
   1431  };
   1432 
   1433  static const JSGCConfig minimal[] = {
   1434      {JSGC_SLICE_TIME_BUDGET_MS, 5},
   1435      {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
   1436      {JSGC_LARGE_HEAP_SIZE_MIN, 250},
   1437      {JSGC_SMALL_HEAP_SIZE_MAX, 50},
   1438      {JSGC_HIGH_FREQUENCY_SMALL_HEAP_GROWTH, 300},
   1439      {JSGC_HIGH_FREQUENCY_LARGE_HEAP_GROWTH, 120},
   1440      {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 120},
   1441      {JSGC_ALLOCATION_THRESHOLD, 15},
   1442      {JSGC_MALLOC_THRESHOLD_BASE, 20},
   1443      {JSGC_SMALL_HEAP_INCREMENTAL_LIMIT, 200},
   1444      {JSGC_LARGE_HEAP_INCREMENTAL_LIMIT, 110},
   1445      {JSGC_URGENT_THRESHOLD_MB, 8}};
   1446 
   1447  static const JSGCConfig nominal[] = {
   1448      {JSGC_SLICE_TIME_BUDGET_MS, 5},
   1449      {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1000},
   1450      {JSGC_LARGE_HEAP_SIZE_MIN, 500},
   1451      {JSGC_SMALL_HEAP_SIZE_MAX, 100},
   1452      {JSGC_HIGH_FREQUENCY_SMALL_HEAP_GROWTH, 300},
   1453      {JSGC_HIGH_FREQUENCY_LARGE_HEAP_GROWTH, 150},
   1454      {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 150},
   1455      {JSGC_ALLOCATION_THRESHOLD, 27},
   1456      {JSGC_MALLOC_THRESHOLD_BASE, 38},
   1457      {JSGC_SMALL_HEAP_INCREMENTAL_LIMIT, 150},
   1458      {JSGC_LARGE_HEAP_INCREMENTAL_LIMIT, 110},
   1459      {JSGC_URGENT_THRESHOLD_MB, 16}};
   1460 
   1461  const auto& configSet = availMemMB > 512 ? nominal : minimal;
   1462  for (const auto& config : configSet) {
   1463    JS_SetGCParameter(cx, config.key, config.value);
   1464  }
   1465 }
   1466 
   1467 JS_PUBLIC_API JSString* JS_NewExternalStringLatin1(
   1468    JSContext* cx, const Latin1Char* chars, size_t length,
   1469    const JSExternalStringCallbacks* callbacks) {
   1470  AssertHeapIsIdle();
   1471  CHECK_THREAD(cx);
   1472  return JSExternalString::new_(cx, chars, length, callbacks);
   1473 }
   1474 
   1475 JS_PUBLIC_API JSString* JS_NewExternalUCString(
   1476    JSContext* cx, const char16_t* chars, size_t length,
   1477    const JSExternalStringCallbacks* callbacks) {
   1478  AssertHeapIsIdle();
   1479  CHECK_THREAD(cx);
   1480  return JSExternalString::new_(cx, chars, length, callbacks);
   1481 }
   1482 
   1483 JS_PUBLIC_API JSString* JS_NewMaybeExternalStringLatin1(
   1484    JSContext* cx, const JS::Latin1Char* chars, size_t length,
   1485    const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) {
   1486  AssertHeapIsIdle();
   1487  CHECK_THREAD(cx);
   1488  return NewMaybeExternalString(cx, chars, length, callbacks,
   1489                                allocatedExternal);
   1490 }
   1491 
   1492 JS_PUBLIC_API JSString* JS_NewMaybeExternalStringUTF8(
   1493    JSContext* cx, const JS::UTF8Chars& utf8,
   1494    const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) {
   1495  AssertHeapIsIdle();
   1496  CHECK_THREAD(cx);
   1497 
   1498  JS::SmallestEncoding encoding = JS::FindSmallestEncoding(utf8);
   1499  if (encoding == JS::SmallestEncoding::ASCII) {
   1500    // ASCII case can use the external buffer as Latin1 buffer.
   1501    return NewMaybeExternalString(
   1502        cx, reinterpret_cast<JS::Latin1Char*>(utf8.begin().get()),
   1503        utf8.length(), callbacks, allocatedExternal);
   1504  }
   1505 
   1506  // Non-ASCII case cannot use the external buffer.
   1507  *allocatedExternal = false;
   1508  return NewStringCopyUTF8N(cx, utf8, encoding);
   1509 }
   1510 
   1511 JS_PUBLIC_API JSString* JS_NewMaybeExternalUCString(
   1512    JSContext* cx, const char16_t* chars, size_t length,
   1513    const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) {
   1514  AssertHeapIsIdle();
   1515  CHECK_THREAD(cx);
   1516  return NewMaybeExternalString(cx, chars, length, callbacks,
   1517                                allocatedExternal);
   1518 }
   1519 
   1520 extern JS_PUBLIC_API const JSExternalStringCallbacks*
   1521 JS_GetExternalStringCallbacks(JSString* str) {
   1522  return str->asExternal().callbacks();
   1523 }
   1524 
   1525 static void SetNativeStackSize(JSContext* cx, JS::StackKind kind,
   1526                               JS::NativeStackSize stackSize) {
   1527 #ifdef __wasi__
   1528  cx->nativeStackLimit[kind] = JS::WASINativeStackLimit;
   1529 #else   // __wasi__
   1530  if (stackSize == 0) {
   1531    cx->nativeStackLimit[kind] = JS::NativeStackLimitMax;
   1532  } else {
   1533    cx->nativeStackLimit[kind] =
   1534        JS::GetNativeStackLimit(cx->nativeStackBase(), stackSize - 1);
   1535  }
   1536 #endif  // !__wasi__
   1537 }
   1538 
   1539 JS_PUBLIC_API void JS_SetNativeStackQuota(
   1540    JSContext* cx, JS::NativeStackSize systemCodeStackSize,
   1541    JS::NativeStackSize trustedScriptStackSize,
   1542    JS::NativeStackSize untrustedScriptStackSize) {
   1543  MOZ_ASSERT(!cx->activation());
   1544 
   1545  if (!trustedScriptStackSize) {
   1546    trustedScriptStackSize = systemCodeStackSize;
   1547  } else {
   1548    MOZ_ASSERT(trustedScriptStackSize < systemCodeStackSize);
   1549  }
   1550 
   1551  if (!untrustedScriptStackSize) {
   1552    untrustedScriptStackSize = trustedScriptStackSize;
   1553  } else {
   1554    MOZ_ASSERT(untrustedScriptStackSize < trustedScriptStackSize);
   1555  }
   1556 
   1557  SetNativeStackSize(cx, JS::StackForSystemCode, systemCodeStackSize);
   1558  SetNativeStackSize(cx, JS::StackForTrustedScript, trustedScriptStackSize);
   1559  SetNativeStackSize(cx, JS::StackForUntrustedScript, untrustedScriptStackSize);
   1560 
   1561  if (cx->runtime()->isMainRuntime()) {
   1562    js::gc::MapStack(systemCodeStackSize);
   1563  }
   1564 
   1565  cx->initJitStackLimit();
   1566 }
   1567 
   1568 /************************************************************************/
   1569 
   1570 JS_PUBLIC_API bool JS_ValueToId(JSContext* cx, HandleValue value,
   1571                                MutableHandleId idp) {
   1572  AssertHeapIsIdle();
   1573  CHECK_THREAD(cx);
   1574  cx->check(value);
   1575  return ToPropertyKey(cx, value, idp);
   1576 }
   1577 
   1578 JS_PUBLIC_API bool JS_StringToId(JSContext* cx, HandleString string,
   1579                                 MutableHandleId idp) {
   1580  AssertHeapIsIdle();
   1581  CHECK_THREAD(cx);
   1582  cx->check(string);
   1583  RootedValue value(cx, StringValue(string));
   1584  return PrimitiveValueToId<CanGC>(cx, value, idp);
   1585 }
   1586 
   1587 JS_PUBLIC_API bool JS_IdToValue(JSContext* cx, jsid id, MutableHandleValue vp) {
   1588  AssertHeapIsIdle();
   1589  CHECK_THREAD(cx);
   1590  cx->check(id);
   1591  vp.set(IdToValue(id));
   1592  cx->check(vp);
   1593  return true;
   1594 }
   1595 
   1596 JS_PUBLIC_API bool JS::ToPrimitive(JSContext* cx, HandleObject obj, JSType hint,
   1597                                   MutableHandleValue vp) {
   1598  AssertHeapIsIdle();
   1599  CHECK_THREAD(cx);
   1600  cx->check(obj);
   1601  MOZ_ASSERT(obj != nullptr);
   1602  MOZ_ASSERT(hint == JSTYPE_UNDEFINED || hint == JSTYPE_STRING ||
   1603             hint == JSTYPE_NUMBER);
   1604  vp.setObject(*obj);
   1605  return ToPrimitiveSlow(cx, hint, vp);
   1606 }
   1607 
   1608 JS_PUBLIC_API bool JS::GetFirstArgumentAsTypeHint(JSContext* cx,
   1609                                                  const CallArgs& args,
   1610                                                  JSType* result) {
   1611  if (!args.get(0).isString()) {
   1612    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1613                              JSMSG_NOT_EXPECTED_TYPE, "Symbol.toPrimitive",
   1614                              "\"string\", \"number\", or \"default\"",
   1615                              InformalValueTypeName(args.get(0)));
   1616    return false;
   1617  }
   1618 
   1619  RootedString str(cx, args.get(0).toString());
   1620  bool match;
   1621 
   1622  if (!EqualStrings(cx, str, cx->names().default_, &match)) {
   1623    return false;
   1624  }
   1625  if (match) {
   1626    *result = JSTYPE_UNDEFINED;
   1627    return true;
   1628  }
   1629 
   1630  if (!EqualStrings(cx, str, cx->names().string, &match)) {
   1631    return false;
   1632  }
   1633  if (match) {
   1634    *result = JSTYPE_STRING;
   1635    return true;
   1636  }
   1637 
   1638  if (!EqualStrings(cx, str, cx->names().number, &match)) {
   1639    return false;
   1640  }
   1641  if (match) {
   1642    *result = JSTYPE_NUMBER;
   1643    return true;
   1644  }
   1645 
   1646  UniqueChars bytes;
   1647  const char* source = ValueToSourceForError(cx, args.get(0), bytes);
   1648  MOZ_ASSERT(source);
   1649 
   1650  JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
   1651                           JSMSG_NOT_EXPECTED_TYPE, "Symbol.toPrimitive",
   1652                           "\"string\", \"number\", or \"default\"", source);
   1653  return false;
   1654 }
   1655 
   1656 JS_PUBLIC_API JSObject* JS_InitClass(
   1657    JSContext* cx, HandleObject obj, const JSClass* protoClass,
   1658    HandleObject protoProto, const char* name, JSNative constructor,
   1659    unsigned nargs, const JSPropertySpec* ps, const JSFunctionSpec* fs,
   1660    const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs) {
   1661  AssertHeapIsIdle();
   1662  CHECK_THREAD(cx);
   1663  cx->check(obj, protoProto);
   1664  return InitClass(cx, obj, protoClass, protoProto, name, constructor, nargs,
   1665                   ps, fs, static_ps, static_fs);
   1666 }
   1667 
   1668 JS_PUBLIC_API bool JS_LinkConstructorAndPrototype(JSContext* cx,
   1669                                                  HandleObject ctor,
   1670                                                  HandleObject proto) {
   1671  return LinkConstructorAndPrototype(cx, ctor, proto);
   1672 }
   1673 
   1674 JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx, HandleObject obj,
   1675                                 const JSClass* clasp, CallArgs* args) {
   1676  AssertHeapIsIdle();
   1677  CHECK_THREAD(cx);
   1678 #ifdef DEBUG
   1679  if (args) {
   1680    cx->check(obj, args->thisv(), args->calleev());
   1681  }
   1682 #endif
   1683  if (!obj || obj->getClass() != clasp) {
   1684    if (args) {
   1685      ReportIncompatibleMethod(cx, *args, clasp);
   1686    }
   1687    return false;
   1688  }
   1689  return true;
   1690 }
   1691 
   1692 JS_PUBLIC_API bool JS_HasInstance(JSContext* cx, HandleObject obj,
   1693                                  HandleValue value, bool* bp) {
   1694  AssertHeapIsIdle();
   1695  cx->check(obj, value);
   1696  return InstanceofOperator(cx, obj, value, bp);
   1697 }
   1698 
   1699 JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx, HandleObject proto) {
   1700  AssertHeapIsIdle();
   1701  CHECK_THREAD(cx);
   1702  cx->check(proto);
   1703 
   1704  RootedValue cval(cx);
   1705  if (!GetProperty(cx, proto, proto, cx->names().constructor, &cval)) {
   1706    return nullptr;
   1707  }
   1708  if (!IsFunctionObject(cval)) {
   1709    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1710                              JSMSG_NO_CONSTRUCTOR, proto->getClass()->name);
   1711    return nullptr;
   1712  }
   1713  return &cval.toObject();
   1714 }
   1715 
   1716 JS::RealmCreationOptions&
   1717 JS::RealmCreationOptions::setNewCompartmentInSystemZone() {
   1718  compSpec_ = CompartmentSpecifier::NewCompartmentInSystemZone;
   1719  comp_ = nullptr;
   1720  return *this;
   1721 }
   1722 
   1723 JS::RealmCreationOptions&
   1724 JS::RealmCreationOptions::setNewCompartmentInExistingZone(JSObject* obj) {
   1725  compSpec_ = CompartmentSpecifier::NewCompartmentInExistingZone;
   1726  zone_ = obj->zone();
   1727  return *this;
   1728 }
   1729 
   1730 JS::RealmCreationOptions& JS::RealmCreationOptions::setExistingCompartment(
   1731    JSObject* obj) {
   1732  compSpec_ = CompartmentSpecifier::ExistingCompartment;
   1733  comp_ = obj->compartment();
   1734  return *this;
   1735 }
   1736 
   1737 JS::RealmCreationOptions& JS::RealmCreationOptions::setExistingCompartment(
   1738    JS::Compartment* compartment) {
   1739  compSpec_ = CompartmentSpecifier::ExistingCompartment;
   1740  comp_ = compartment;
   1741  return *this;
   1742 }
   1743 
   1744 JS::RealmCreationOptions& JS::RealmCreationOptions::setNewCompartmentAndZone() {
   1745  compSpec_ = CompartmentSpecifier::NewCompartmentAndZone;
   1746  comp_ = nullptr;
   1747  return *this;
   1748 }
   1749 
   1750 const JS::RealmCreationOptions& JS::RealmCreationOptionsRef(Realm* realm) {
   1751  return realm->creationOptions();
   1752 }
   1753 
   1754 const JS::RealmCreationOptions& JS::RealmCreationOptionsRef(JSContext* cx) {
   1755  return cx->realm()->creationOptions();
   1756 }
   1757 
   1758 bool JS::RealmCreationOptions::getSharedMemoryAndAtomicsEnabled() const {
   1759  return sharedMemoryAndAtomics_;
   1760 }
   1761 
   1762 JS::RealmCreationOptions&
   1763 JS::RealmCreationOptions::setSharedMemoryAndAtomicsEnabled(bool flag) {
   1764  sharedMemoryAndAtomics_ = flag;
   1765  return *this;
   1766 }
   1767 
   1768 bool JS::RealmCreationOptions::getCoopAndCoepEnabled() const {
   1769  return coopAndCoep_;
   1770 }
   1771 
   1772 JS::RealmCreationOptions& JS::RealmCreationOptions::setCoopAndCoepEnabled(
   1773    bool flag) {
   1774  coopAndCoep_ = flag;
   1775  return *this;
   1776 }
   1777 
   1778 template <class RefCountedString>
   1779 static RefCountedString* CopyStringZ(const char* str) {
   1780  MOZ_ASSERT(str);
   1781 
   1782  const size_t size = strlen(str) + 1;
   1783 
   1784  AutoEnterOOMUnsafeRegion oomUnsafe;
   1785  char* memoryPtr = js_pod_malloc<char>(sizeof(RefCountedString) + size);
   1786  if (!memoryPtr) {
   1787    oomUnsafe.crash("CopyStringZ");
   1788  }
   1789 
   1790  char* strPtr = memoryPtr + sizeof(RefCountedString);
   1791  memcpy(strPtr, str, size);
   1792 
   1793  return new (memoryPtr) RefCountedString(strPtr);
   1794 }
   1795 
   1796 JS::RealmBehaviors& JS::RealmBehaviors::setLocaleOverride(const char* locale) {
   1797  if (locale) {
   1798    localeOverride_ = CopyStringZ<JS::LocaleString>(locale);
   1799  } else {
   1800    localeOverride_ = nullptr;
   1801  }
   1802  return *this;
   1803 }
   1804 
   1805 JS::RealmBehaviors& JS::RealmBehaviors::setTimeZoneOverride(
   1806    const char* timeZone) {
   1807  if (timeZone) {
   1808    timeZoneOverride_ = CopyStringZ<JS::TimeZoneString>(timeZone);
   1809  } else {
   1810    timeZoneOverride_ = nullptr;
   1811  }
   1812  return *this;
   1813 }
   1814 
   1815 const JS::RealmBehaviors& JS::RealmBehaviorsRef(JS::Realm* realm) {
   1816  return realm->behaviors();
   1817 }
   1818 
   1819 const JS::RealmBehaviors& JS::RealmBehaviorsRef(JSContext* cx) {
   1820  return cx->realm()->behaviors();
   1821 }
   1822 
   1823 void JS::SetRealmLocaleOverride(Realm* realm, const char* locale) {
   1824  realm->setLocaleOverride(locale);
   1825 }
   1826 
   1827 void JS::SetRealmTimezoneOverride(Realm* realm, const char* timezone) {
   1828  realm->setTimeZoneOverride(timezone);
   1829 }
   1830 
   1831 void JS::SetRealmNonLive(Realm* realm) { realm->setNonLive(); }
   1832 
   1833 void JS::SetRealmReduceTimerPrecisionCallerType(Realm* realm,
   1834                                                JS::RTPCallerTypeToken type) {
   1835  realm->setReduceTimerPrecisionCallerType(type);
   1836 }
   1837 
   1838 JS_PUBLIC_API JSObject* JS_NewGlobalObject(JSContext* cx, const JSClass* clasp,
   1839                                           JSPrincipals* principals,
   1840                                           JS::OnNewGlobalHookOption hookOption,
   1841                                           const JS::RealmOptions& options) {
   1842  MOZ_RELEASE_ASSERT(
   1843      cx->runtime()->hasInitializedSelfHosting(),
   1844      "Must call JS::InitSelfHostedCode() before creating a global");
   1845 
   1846  AssertHeapIsIdle();
   1847  CHECK_THREAD(cx);
   1848 
   1849  return GlobalObject::new_(cx, clasp, principals, hookOption, options);
   1850 }
   1851 
   1852 JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global) {
   1853  GlobalObject* globalObj = &global->as<GlobalObject>();
   1854  Realm* globalRealm = globalObj->realm();
   1855 
   1856  // If we GC when creating the global, we may not have set that global's
   1857  // realm's global pointer yet. In this case, the realm will not yet contain
   1858  // anything that needs to be traced.
   1859  if (globalRealm->unsafeUnbarrieredMaybeGlobal() != globalObj) {
   1860    return;
   1861  }
   1862 
   1863  // Trace the realm for any GC things that should only stick around if we
   1864  // know the global is live.
   1865  globalRealm->traceGlobalData(trc);
   1866 
   1867  globalObj->traceData(trc, globalObj);
   1868 
   1869  if (JSTraceOp trace = globalRealm->creationOptions().getTrace()) {
   1870    trace(trc, global);
   1871  }
   1872 }
   1873 
   1874 const JSClassOps JS::DefaultGlobalClassOps = {
   1875    nullptr,                         // addProperty
   1876    nullptr,                         // delProperty
   1877    nullptr,                         // enumerate
   1878    JS_NewEnumerateStandardClasses,  // newEnumerate
   1879    JS_ResolveStandardClass,         // resolve
   1880    JS_MayResolveStandardClass,      // mayResolve
   1881    nullptr,                         // finalize
   1882    nullptr,                         // call
   1883    nullptr,                         // construct
   1884    JS_GlobalObjectTraceHook,        // trace
   1885 };
   1886 
   1887 JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx,
   1888                                            JS::HandleObject global) {
   1889  // This hook is infallible, because we don't really want arbitrary script
   1890  // to be able to throw errors during delicate global creation routines.
   1891  // This infallibility will eat OOM and slow script, but if that happens
   1892  // we'll likely run up into them again soon in a fallible context.
   1893  cx->check(global);
   1894 
   1895  Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>());
   1896 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   1897  if (JS::GetReduceMicrosecondTimePrecisionCallback()) {
   1898    MOZ_DIAGNOSTIC_ASSERT(globalObject->realm()
   1899                              ->behaviors()
   1900                              .reduceTimerPrecisionCallerType()
   1901                              .isSome(),
   1902                          "Trying to create a global without setting an "
   1903                          "explicit RTPCallerType!");
   1904  }
   1905 #endif
   1906  DebugAPI::onNewGlobalObject(cx, globalObject);
   1907  cx->runtime()->ensureRealmIsRecordingAllocations(globalObject);
   1908 }
   1909 
   1910 JS_PUBLIC_API JSObject* JS_NewObject(JSContext* cx, const JSClass* clasp) {
   1911  MOZ_ASSERT(!cx->zone()->isAtomsZone());
   1912  AssertHeapIsIdle();
   1913  CHECK_THREAD(cx);
   1914 
   1915  if (!clasp) {
   1916    // Default class is Object.
   1917    return NewPlainObject(cx);
   1918  }
   1919 
   1920  MOZ_ASSERT(!clasp->isJSFunction());
   1921  MOZ_ASSERT(clasp != &PlainObject::class_);
   1922  MOZ_ASSERT(clasp != &ArrayObject::class_);
   1923  MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
   1924 
   1925  return NewBuiltinClassInstance(cx, clasp);
   1926 }
   1927 
   1928 JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProto(JSContext* cx,
   1929                                                   const JSClass* clasp,
   1930                                                   HandleObject proto) {
   1931  MOZ_ASSERT(!cx->zone()->isAtomsZone());
   1932  AssertHeapIsIdle();
   1933  CHECK_THREAD(cx);
   1934  cx->check(proto);
   1935 
   1936  if (!clasp) {
   1937    // Default class is Object.
   1938    return NewPlainObjectWithProto(cx, proto);
   1939  }
   1940 
   1941  MOZ_ASSERT(!clasp->isJSFunction());
   1942  MOZ_ASSERT(clasp != &PlainObject::class_);
   1943  MOZ_ASSERT(clasp != &ArrayObject::class_);
   1944  MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
   1945 
   1946  return NewObjectWithGivenProto(cx, clasp, proto);
   1947 }
   1948 
   1949 JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProtoAndUseAllocSite(
   1950    JSContext* cx, const JSClass* clasp, HandleObject proto) {
   1951  MOZ_ASSERT(!cx->zone()->isAtomsZone());
   1952  AssertHeapIsIdle();
   1953  CHECK_THREAD(cx);
   1954  cx->check(proto);
   1955 
   1956  MOZ_ASSERT(clasp);
   1957  MOZ_ASSERT(!clasp->isJSFunction());
   1958  MOZ_ASSERT(clasp != &PlainObject::class_);
   1959  MOZ_ASSERT(clasp != &ArrayObject::class_);
   1960  MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
   1961 
   1962  return NewObjectWithGivenProtoAndAllocSite(cx, clasp, proto,
   1963                                             cx->realm()->localAllocSite);
   1964 }
   1965 
   1966 JS_PUBLIC_API JSObject* JS_NewPlainObject(JSContext* cx) {
   1967  MOZ_ASSERT(!cx->zone()->isAtomsZone());
   1968  AssertHeapIsIdle();
   1969  CHECK_THREAD(cx);
   1970 
   1971  return NewPlainObject(cx);
   1972 }
   1973 
   1974 JS_PUBLIC_API JSObject* JS_NewObjectForConstructor(JSContext* cx,
   1975                                                   const JSClass* clasp,
   1976                                                   const CallArgs& args) {
   1977  AssertHeapIsIdle();
   1978  CHECK_THREAD(cx);
   1979 
   1980  MOZ_ASSERT(!clasp->isJSFunction());
   1981  MOZ_ASSERT(clasp != &PlainObject::class_);
   1982  MOZ_ASSERT(clasp != &ArrayObject::class_);
   1983  MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
   1984 
   1985  if (!ThrowIfNotConstructing(cx, args, clasp->name)) {
   1986    return nullptr;
   1987  }
   1988 
   1989  RootedObject newTarget(cx, &args.newTarget().toObject());
   1990  cx->check(newTarget);
   1991 
   1992  RootedObject proto(cx);
   1993  if (!GetPrototypeFromConstructor(cx, newTarget,
   1994                                   JSCLASS_CACHED_PROTO_KEY(clasp), &proto)) {
   1995    return nullptr;
   1996  }
   1997 
   1998  return NewObjectWithClassProto(cx, clasp, proto);
   1999 }
   2000 
   2001 JS_PUBLIC_API bool JS_IsNative(JSObject* obj) {
   2002  return obj->is<NativeObject>();
   2003 }
   2004 
   2005 JS_PUBLIC_API void JS::AssertObjectBelongsToCurrentThread(JSObject* obj) {
   2006  JSRuntime* rt = obj->compartment()->runtimeFromAnyThread();
   2007  MOZ_RELEASE_ASSERT(CurrentThreadCanAccessRuntime(rt));
   2008 }
   2009 
   2010 JS_PUBLIC_API void JS::SetFilenameValidationCallback(
   2011    JS::FilenameValidationCallback cb) {
   2012  js::gFilenameValidationCallback = cb;
   2013 }
   2014 
   2015 JS_PUBLIC_API void JS::SetHostEnsureCanAddPrivateElementHook(
   2016    JSContext* cx, JS::EnsureCanAddPrivateElementOp op) {
   2017  cx->runtime()->canAddPrivateElement = op;
   2018 }
   2019 
   2020 JS_PUBLIC_API bool JS::SetBrittleMode(JSContext* cx, bool setting) {
   2021  bool wasBrittle = cx->brittleMode;
   2022  cx->brittleMode = setting;
   2023  return wasBrittle;
   2024 }
   2025 
   2026 /*** Standard internal methods **********************************************/
   2027 
   2028 JS_PUBLIC_API bool JS_GetPrototype(JSContext* cx, HandleObject obj,
   2029                                   MutableHandleObject result) {
   2030  cx->check(obj);
   2031  return GetPrototype(cx, obj, result);
   2032 }
   2033 
   2034 JS_PUBLIC_API bool JS_SetPrototype(JSContext* cx, HandleObject obj,
   2035                                   HandleObject proto) {
   2036  AssertHeapIsIdle();
   2037  CHECK_THREAD(cx);
   2038  cx->check(obj, proto);
   2039 
   2040  return SetPrototype(cx, obj, proto);
   2041 }
   2042 
   2043 JS_PUBLIC_API bool JS_GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj,
   2044                                             bool* isOrdinary,
   2045                                             MutableHandleObject result) {
   2046  cx->check(obj);
   2047  return GetPrototypeIfOrdinary(cx, obj, isOrdinary, result);
   2048 }
   2049 
   2050 JS_PUBLIC_API bool JS_IsExtensible(JSContext* cx, HandleObject obj,
   2051                                   bool* extensible) {
   2052  cx->check(obj);
   2053  return IsExtensible(cx, obj, extensible);
   2054 }
   2055 
   2056 JS_PUBLIC_API bool JS_PreventExtensions(JSContext* cx, JS::HandleObject obj,
   2057                                        ObjectOpResult& result) {
   2058  cx->check(obj);
   2059  return PreventExtensions(cx, obj, result);
   2060 }
   2061 
   2062 JS_PUBLIC_API bool JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj,
   2063                                            bool* succeeded) {
   2064  cx->check(obj);
   2065  return SetImmutablePrototype(cx, obj, succeeded);
   2066 }
   2067 
   2068 /* * */
   2069 
   2070 JS_PUBLIC_API bool JS_FreezeObject(JSContext* cx, HandleObject obj) {
   2071  AssertHeapIsIdle();
   2072  CHECK_THREAD(cx);
   2073  cx->check(obj);
   2074  return FreezeObject(cx, obj);
   2075 }
   2076 
   2077 static bool DeepFreezeSlot(JSContext* cx, const Value& v) {
   2078  if (v.isPrimitive()) {
   2079    return true;
   2080  }
   2081  RootedObject obj(cx, &v.toObject());
   2082  return JS_DeepFreezeObject(cx, obj);
   2083 }
   2084 
   2085 JS_PUBLIC_API bool JS_DeepFreezeObject(JSContext* cx, HandleObject obj) {
   2086  AssertHeapIsIdle();
   2087  CHECK_THREAD(cx);
   2088  cx->check(obj);
   2089 
   2090  // Assume that non-extensible objects are already deep-frozen, to avoid
   2091  // divergence.
   2092  bool extensible;
   2093  if (!IsExtensible(cx, obj, &extensible)) {
   2094    return false;
   2095  }
   2096  if (!extensible) {
   2097    return true;
   2098  }
   2099 
   2100  if (!FreezeObject(cx, obj)) {
   2101    return false;
   2102  }
   2103 
   2104  // Walk slots in obj and if any value is a non-null object, seal it.
   2105  if (obj->is<NativeObject>()) {
   2106    Rooted<NativeObject*> nobj(cx, &obj->as<NativeObject>());
   2107    for (uint32_t i = 0, n = nobj->slotSpan(); i < n; ++i) {
   2108      if (!DeepFreezeSlot(cx, nobj->getSlot(i))) {
   2109        return false;
   2110      }
   2111    }
   2112    for (uint32_t i = 0, n = nobj->getDenseInitializedLength(); i < n; ++i) {
   2113      if (!DeepFreezeSlot(cx, nobj->getDenseElement(i))) {
   2114        return false;
   2115      }
   2116    }
   2117  }
   2118 
   2119  return true;
   2120 }
   2121 
   2122 JS_PUBLIC_API bool JSPropertySpec::getValue(JSContext* cx,
   2123                                            MutableHandleValue vp) const {
   2124  MOZ_ASSERT(!isAccessor());
   2125 
   2126  switch (u.value.type) {
   2127    case ValueWrapper::Type::String: {
   2128      JSAtom* atom = Atomize(cx, u.value.string, strlen(u.value.string));
   2129      if (!atom) {
   2130        return false;
   2131      }
   2132      vp.setString(atom);
   2133      return true;
   2134    }
   2135 
   2136    case ValueWrapper::Type::Int32:
   2137      vp.setInt32(u.value.int32);
   2138      return true;
   2139 
   2140    case ValueWrapper::Type::Double:
   2141      vp.setDouble(u.value.double_);
   2142      return true;
   2143  }
   2144 
   2145  MOZ_CRASH("Unexpected type");
   2146 }
   2147 
   2148 bool PropertySpecNameToId(JSContext* cx, JSPropertySpec::Name name,
   2149                          MutableHandleId id) {
   2150  if (name.isSymbol()) {
   2151    id.set(PropertyKey::Symbol(cx->wellKnownSymbols().get(name.symbol())));
   2152  } else {
   2153    JSAtom* atom = Atomize(cx, name.string(), strlen(name.string()));
   2154    if (!atom) {
   2155      return false;
   2156    }
   2157    id.set(AtomToId(atom));
   2158  }
   2159  return true;
   2160 }
   2161 
   2162 JS_PUBLIC_API bool JS::PropertySpecNameToPermanentId(JSContext* cx,
   2163                                                     JSPropertySpec::Name name,
   2164                                                     jsid* idp) {
   2165  // We are calling fromMarkedLocation(idp) even though idp points to a
   2166  // location that will never be marked. This is OK because the whole point
   2167  // of this API is to populate *idp with a jsid that does not need to be
   2168  // marked.
   2169  MutableHandleId id = MutableHandleId::fromMarkedLocation(idp);
   2170  if (!PropertySpecNameToId(cx, name, id)) {
   2171    return false;
   2172  }
   2173 
   2174  if (id.isString() && !PinAtom(cx, &id.toString()->asAtom())) {
   2175    return false;
   2176  }
   2177 
   2178  return true;
   2179 }
   2180 
   2181 JS_PUBLIC_API bool JS::ToCompletePropertyDescriptor(
   2182    JSContext* cx, HandleValue descriptor,
   2183    MutableHandle<PropertyDescriptor> desc) {
   2184  AssertHeapIsIdle();
   2185  CHECK_THREAD(cx);
   2186  cx->check(descriptor);
   2187  if (!ToPropertyDescriptor(cx, descriptor, /* checkAccessors */ true, desc)) {
   2188    return false;
   2189  }
   2190  CompletePropertyDescriptor(desc);
   2191  return true;
   2192 }
   2193 
   2194 JS_PUBLIC_API void JS_SetAllNonReservedSlotsToUndefined(JS::HandleObject obj) {
   2195  if (!obj->is<NativeObject>()) {
   2196    return;
   2197  }
   2198 
   2199  NativeObject& nobj = obj->as<NativeObject>();
   2200 
   2201  // XPConnect calls this for global objects and global lexical environments
   2202  // that won't be used anymore. These objects can have an associated ObjectFuse
   2203  // but we can ignore them here because the objects are effectively dead (after
   2204  // clearing all slots below it'd be hard to execute JS code without breaking
   2205  // JS semantics).
   2206  MOZ_RELEASE_ASSERT(nobj.is<GlobalObject>() ||
   2207                     nobj.is<GlobalLexicalEnvironmentObject>() ||
   2208                     !Watchtower::watchesPropertyValueChange(&nobj));
   2209 
   2210  const JSClass* clasp = obj->getClass();
   2211  unsigned numReserved = JSCLASS_RESERVED_SLOTS(clasp);
   2212  unsigned numSlots = nobj.slotSpan();
   2213  for (unsigned i = numReserved; i < numSlots; i++) {
   2214    obj->as<NativeObject>().setSlot(i, UndefinedValue());
   2215  }
   2216 }
   2217 
   2218 JS_PUBLIC_API void JS_SetReservedSlot(JSObject* obj, uint32_t index,
   2219                                      const Value& value) {
   2220  // Note: we don't use setReservedSlot so that this also works on swappable DOM
   2221  // objects. See NativeObject::getReservedSlotRef comment.
   2222  NativeObject& nobj = obj->as<NativeObject>();
   2223  MOZ_ASSERT(index < JSCLASS_RESERVED_SLOTS(obj->getClass()));
   2224  nobj.setSlot(index, value);
   2225 }
   2226 
   2227 JS_PUBLIC_API void JS_InitReservedSlot(JSObject* obj, uint32_t index, void* ptr,
   2228                                       size_t nbytes, JS::MemoryUse use) {
   2229  // Note: we don't use InitReservedSlot so that this also works on swappable
   2230  // DOM objects. See NativeObject::getReservedSlotRef comment.
   2231  MOZ_ASSERT(index < JSCLASS_RESERVED_SLOTS(obj->getClass()));
   2232  AddCellMemory(obj, nbytes, js::MemoryUse(use));
   2233  obj->as<NativeObject>().initSlot(index, PrivateValue(ptr));
   2234 }
   2235 
   2236 JS_PUBLIC_API bool JS::IsMapObject(JSContext* cx, JS::HandleObject obj,
   2237                                   bool* isMap) {
   2238  return IsGivenTypeObject(cx, obj, ESClass::Map, isMap);
   2239 }
   2240 
   2241 JS_PUBLIC_API bool JS::IsSetObject(JSContext* cx, JS::HandleObject obj,
   2242                                   bool* isSet) {
   2243  return IsGivenTypeObject(cx, obj, ESClass::Set, isSet);
   2244 }
   2245 
   2246 JS_PUBLIC_API void JS_HoldPrincipals(JSPrincipals* principals) {
   2247  ++principals->refcount;
   2248 }
   2249 
   2250 JS_PUBLIC_API void JS_DropPrincipals(JSContext* cx, JSPrincipals* principals) {
   2251  int rc = --principals->refcount;
   2252  if (rc == 0) {
   2253    JS::AutoSuppressGCAnalysis nogc;
   2254    cx->runtime()->destroyPrincipals(principals);
   2255  }
   2256 }
   2257 
   2258 JS_PUBLIC_API void JS_SetSecurityCallbacks(JSContext* cx,
   2259                                           const JSSecurityCallbacks* scb) {
   2260  MOZ_ASSERT(scb != &NullSecurityCallbacks);
   2261  cx->runtime()->securityCallbacks = scb ? scb : &NullSecurityCallbacks;
   2262 }
   2263 
   2264 JS_PUBLIC_API const JSSecurityCallbacks* JS_GetSecurityCallbacks(
   2265    JSContext* cx) {
   2266  return (cx->runtime()->securityCallbacks != &NullSecurityCallbacks)
   2267             ? cx->runtime()->securityCallbacks.ref()
   2268             : nullptr;
   2269 }
   2270 
   2271 JS_PUBLIC_API void JS_SetTrustedPrincipals(JSContext* cx, JSPrincipals* prin) {
   2272  cx->runtime()->setTrustedPrincipals(prin);
   2273 }
   2274 
   2275 extern JS_PUBLIC_API void JS_InitDestroyPrincipalsCallback(
   2276    JSContext* cx, JSDestroyPrincipalsOp destroyPrincipals) {
   2277  MOZ_ASSERT(destroyPrincipals);
   2278  MOZ_ASSERT(!cx->runtime()->destroyPrincipals);
   2279  cx->runtime()->destroyPrincipals = destroyPrincipals;
   2280 }
   2281 
   2282 extern JS_PUBLIC_API void JS_InitReadPrincipalsCallback(
   2283    JSContext* cx, JSReadPrincipalsOp read) {
   2284  MOZ_ASSERT(read);
   2285  MOZ_ASSERT(!cx->runtime()->readPrincipals);
   2286  cx->runtime()->readPrincipals = read;
   2287 }
   2288 
   2289 JS_PUBLIC_API JSFunction* JS_NewFunction(JSContext* cx, JSNative native,
   2290                                         unsigned nargs, unsigned flags,
   2291                                         const char* name) {
   2292  MOZ_ASSERT(!cx->zone()->isAtomsZone());
   2293 
   2294  AssertHeapIsIdle();
   2295  CHECK_THREAD(cx);
   2296 
   2297  Rooted<JSAtom*> atom(cx);
   2298  if (name) {
   2299    atom = Atomize(cx, name, strlen(name));
   2300    if (!atom) {
   2301      return nullptr;
   2302    }
   2303  }
   2304 
   2305  return (flags & JSFUN_CONSTRUCTOR)
   2306             ? NewNativeConstructor(cx, native, nargs, atom)
   2307             : NewNativeFunction(cx, native, nargs, atom);
   2308 }
   2309 
   2310 JS_PUBLIC_API JSFunction* JS::GetSelfHostedFunction(JSContext* cx,
   2311                                                    const char* selfHostedName,
   2312                                                    HandleId id,
   2313                                                    unsigned nargs) {
   2314  MOZ_ASSERT(!cx->zone()->isAtomsZone());
   2315  AssertHeapIsIdle();
   2316  CHECK_THREAD(cx);
   2317  cx->check(id);
   2318 
   2319  Rooted<JSAtom*> name(cx, IdToFunctionName(cx, id));
   2320  if (!name) {
   2321    return nullptr;
   2322  }
   2323 
   2324  JSAtom* shAtom = Atomize(cx, selfHostedName, strlen(selfHostedName));
   2325  if (!shAtom) {
   2326    return nullptr;
   2327  }
   2328  Rooted<PropertyName*> shName(cx, shAtom->asPropertyName());
   2329  RootedValue funVal(cx);
   2330  if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name,
   2331                                           nargs, &funVal)) {
   2332    return nullptr;
   2333  }
   2334  return &funVal.toObject().as<JSFunction>();
   2335 }
   2336 
   2337 JS_PUBLIC_API JSFunction* JS::NewFunctionFromSpec(JSContext* cx,
   2338                                                  const JSFunctionSpec* fs,
   2339                                                  HandleId id) {
   2340  cx->check(id);
   2341 
   2342 #ifdef DEBUG
   2343  if (fs->name.isSymbol()) {
   2344    JS::Symbol* sym = cx->wellKnownSymbols().get(fs->name.symbol());
   2345    MOZ_ASSERT(PropertyKey::Symbol(sym) == id);
   2346  } else {
   2347    MOZ_ASSERT(id.isString() &&
   2348               StringEqualsAscii(id.toLinearString(), fs->name.string()));
   2349  }
   2350 #endif
   2351 
   2352  // Delay cloning self-hosted functions until they are called. This is
   2353  // achieved by passing DefineFunction a nullptr JSNative which produces an
   2354  // interpreted JSFunction where !hasScript. Interpreted call paths then
   2355  // call InitializeLazyFunctionScript if !hasScript.
   2356  if (fs->selfHostedName) {
   2357    MOZ_ASSERT(!fs->call.op);
   2358    MOZ_ASSERT(!fs->call.info);
   2359 
   2360    JSAtom* shAtom =
   2361        Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName));
   2362    if (!shAtom) {
   2363      return nullptr;
   2364    }
   2365    Rooted<PropertyName*> shName(cx, shAtom->asPropertyName());
   2366    Rooted<JSAtom*> name(cx, IdToFunctionName(cx, id));
   2367    if (!name) {
   2368      return nullptr;
   2369    }
   2370    RootedValue funVal(cx);
   2371    if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name,
   2372                                             fs->nargs, &funVal)) {
   2373      return nullptr;
   2374    }
   2375    return &funVal.toObject().as<JSFunction>();
   2376  }
   2377 
   2378  Rooted<JSAtom*> atom(cx, IdToFunctionName(cx, id));
   2379  if (!atom) {
   2380    return nullptr;
   2381  }
   2382 
   2383  MOZ_ASSERT(fs->call.op);
   2384 
   2385  JSFunction* fun;
   2386  if (fs->flags & JSFUN_CONSTRUCTOR) {
   2387    fun = NewNativeConstructor(cx, fs->call.op, fs->nargs, atom);
   2388  } else {
   2389    fun = NewNativeFunction(cx, fs->call.op, fs->nargs, atom);
   2390  }
   2391  if (!fun) {
   2392    return nullptr;
   2393  }
   2394 
   2395  if (auto* jitInfo = fs->call.info) {
   2396    if (jitInfo->type() == JSJitInfo::OpType::TrampolineNative) {
   2397      jit::SetTrampolineNativeJitEntry(cx, fun, jitInfo->trampolineNative);
   2398    } else {
   2399      fun->setJitInfo(jitInfo);
   2400    }
   2401  }
   2402  return fun;
   2403 }
   2404 
   2405 JS_PUBLIC_API JSFunction* JS::NewFunctionFromSpec(JSContext* cx,
   2406                                                  const JSFunctionSpec* fs) {
   2407  RootedId id(cx);
   2408  if (!PropertySpecNameToId(cx, fs->name, &id)) {
   2409    return nullptr;
   2410  }
   2411 
   2412  return NewFunctionFromSpec(cx, fs, id);
   2413 }
   2414 
   2415 JS_PUBLIC_API JSObject* JS_GetFunctionObject(JSFunction* fun) { return fun; }
   2416 
   2417 JS_PUBLIC_API bool JS_GetFunctionId(JSContext* cx, JS::Handle<JSFunction*> fun,
   2418                                    JS::MutableHandle<JSString*> name) {
   2419  JS::Rooted<JSAtom*> atom(cx);
   2420  if (!fun->getExplicitName(cx, &atom)) {
   2421    return false;
   2422  }
   2423  name.set(atom);
   2424  return true;
   2425 }
   2426 
   2427 JS_PUBLIC_API JSString* JS_GetMaybePartialFunctionId(JSFunction* fun) {
   2428  return fun->maybePartialExplicitName();
   2429 }
   2430 
   2431 JS_PUBLIC_API bool JS_GetFunctionDisplayId(JSContext* cx,
   2432                                           JS::Handle<JSFunction*> fun,
   2433                                           JS::MutableHandle<JSString*> name) {
   2434  JS::Rooted<JSAtom*> atom(cx);
   2435  if (!fun->getDisplayAtom(cx, &atom)) {
   2436    return false;
   2437  }
   2438  name.set(atom);
   2439  return true;
   2440 }
   2441 
   2442 JS_PUBLIC_API JSString* JS_GetMaybePartialFunctionDisplayId(JSFunction* fun) {
   2443  return fun->maybePartialDisplayAtom();
   2444 }
   2445 
   2446 JS_PUBLIC_API uint16_t JS_GetFunctionArity(JSFunction* fun) {
   2447  return fun->nargs();
   2448 }
   2449 
   2450 JS_PUBLIC_API bool JS_GetFunctionLength(JSContext* cx, HandleFunction fun,
   2451                                        uint16_t* length) {
   2452  cx->check(fun);
   2453  return JSFunction::getLength(cx, fun, length);
   2454 }
   2455 
   2456 JS_PUBLIC_API bool JS_ObjectIsFunction(JSObject* obj) {
   2457  return obj->is<JSFunction>();
   2458 }
   2459 
   2460 JS_PUBLIC_API bool JS_IsNativeFunction(JSObject* funobj, JSNative call) {
   2461  if (!funobj->is<JSFunction>()) {
   2462    return false;
   2463  }
   2464  JSFunction* fun = &funobj->as<JSFunction>();
   2465  return fun->isNativeFun() && fun->native() == call;
   2466 }
   2467 
   2468 extern JS_PUBLIC_API bool JS_IsConstructor(JSFunction* fun) {
   2469  return fun->isConstructor();
   2470 }
   2471 
   2472 void JS::CompileOptions::warnAboutConflictingDelazification() const {
   2473  Fprinter out(stderr);
   2474  out.printf(
   2475      "WARNING: Parsing Everything Eagerly is already set "
   2476      "and it cannot be disabled by other parsing strategy.\n"
   2477      "The provided strategy is going to be ignored.\n\n"
   2478      "Parse Everything Eagerly might be used by Code Coverage "
   2479      "to ensure that all functions are known when the report is "
   2480      "generated.\n");
   2481 }
   2482 
   2483 void JS::TransitiveCompileOptions::copyPODTransitiveOptions(
   2484    const TransitiveCompileOptions& rhs) {
   2485  // filename_, introducerFilename_, sourceMapURL_ should be handled in caller.
   2486 
   2487  mutedErrors_ = rhs.mutedErrors_;
   2488  forceStrictMode_ = rhs.forceStrictMode_;
   2489  alwaysUseFdlibm_ = rhs.alwaysUseFdlibm_;
   2490  skipFilenameValidation_ = rhs.skipFilenameValidation_;
   2491  hideScriptFromDebugger_ = rhs.hideScriptFromDebugger_;
   2492  deferDebugMetadata_ = rhs.deferDebugMetadata_;
   2493  eagerDelazificationStrategy_ = rhs.eagerDelazificationStrategy_;
   2494 
   2495  selfHostingMode = rhs.selfHostingMode;
   2496  discardSource = rhs.discardSource;
   2497  sourceIsLazy = rhs.sourceIsLazy;
   2498  allowHTMLComments = rhs.allowHTMLComments;
   2499  nonSyntacticScope = rhs.nonSyntacticScope;
   2500 
   2501  topLevelAwait = rhs.topLevelAwait;
   2502 
   2503  borrowBuffer = rhs.borrowBuffer;
   2504  usePinnedBytecode = rhs.usePinnedBytecode;
   2505 
   2506  prefableOptions_ = rhs.prefableOptions_;
   2507 
   2508  introductionType = rhs.introductionType;
   2509  introductionLineno = rhs.introductionLineno;
   2510  introductionOffset = rhs.introductionOffset;
   2511  hasIntroductionInfo = rhs.hasIntroductionInfo;
   2512 };
   2513 
   2514 void JS::ReadOnlyCompileOptions::copyPODNonTransitiveOptions(
   2515    const ReadOnlyCompileOptions& rhs) {
   2516  lineno = rhs.lineno;
   2517  column = rhs.column;
   2518  scriptSourceOffset = rhs.scriptSourceOffset;
   2519  isRunOnce = rhs.isRunOnce;
   2520  noScriptRval = rhs.noScriptRval;
   2521 }
   2522 
   2523 JS::OwningCompileOptions::OwningCompileOptions(JSContext* cx) {}
   2524 
   2525 void JS::OwningCompileOptions::release() {
   2526  // OwningCompileOptions always owns these, so these casts are okay.
   2527  js_free(const_cast<char*>(filename_.c_str()));
   2528  js_free(const_cast<char16_t*>(sourceMapURL_));
   2529  js_free(const_cast<char*>(introducerFilename_.c_str()));
   2530 
   2531  filename_ = JS::ConstUTF8CharsZ();
   2532  sourceMapURL_ = nullptr;
   2533  introducerFilename_ = JS::ConstUTF8CharsZ();
   2534 }
   2535 
   2536 JS::OwningCompileOptions::~OwningCompileOptions() { release(); }
   2537 
   2538 size_t JS::OwningCompileOptions::sizeOfExcludingThis(
   2539    mozilla::MallocSizeOf mallocSizeOf) const {
   2540  return mallocSizeOf(filename_.c_str()) + mallocSizeOf(sourceMapURL_) +
   2541         mallocSizeOf(introducerFilename_.c_str());
   2542 }
   2543 
   2544 void JS::OwningCompileOptions::steal(JS::OwningCompileOptions&& rhs) {
   2545  // Release existing string allocations.
   2546  release();
   2547 
   2548  copyPODNonTransitiveOptions(rhs);
   2549  copyPODTransitiveOptions(rhs);
   2550 
   2551  filename_ = rhs.filename_;
   2552  rhs.filename_ = JS::ConstUTF8CharsZ();
   2553  introducerFilename_ = rhs.introducerFilename_;
   2554  rhs.introducerFilename_ = JS::ConstUTF8CharsZ();
   2555  sourceMapURL_ = rhs.sourceMapURL_;
   2556  rhs.sourceMapURL_ = nullptr;
   2557 }
   2558 
   2559 void JS::OwningCompileOptions::steal(JS::OwningDecodeOptions&& rhs) {
   2560  // Release existing string allocations.
   2561  release();
   2562 
   2563  rhs.copyPODOptionsTo(*this);
   2564 
   2565  introducerFilename_ = rhs.introducerFilename_;
   2566  rhs.introducerFilename_ = JS::ConstUTF8CharsZ();
   2567 }
   2568 
   2569 template <typename ContextT>
   2570 bool JS::OwningCompileOptions::copyImpl(ContextT* cx,
   2571                                        const ReadOnlyCompileOptions& rhs) {
   2572  // Release existing string allocations.
   2573  release();
   2574 
   2575  copyPODNonTransitiveOptions(rhs);
   2576  copyPODTransitiveOptions(rhs);
   2577 
   2578  if (rhs.filename()) {
   2579    const char* str = DuplicateString(cx, rhs.filename().c_str()).release();
   2580    if (!str) {
   2581      return false;
   2582    }
   2583    filename_ = JS::ConstUTF8CharsZ(str);
   2584  }
   2585 
   2586  if (rhs.sourceMapURL()) {
   2587    sourceMapURL_ = DuplicateString(cx, rhs.sourceMapURL()).release();
   2588    if (!sourceMapURL_) {
   2589      return false;
   2590    }
   2591  }
   2592 
   2593  if (rhs.introducerFilename()) {
   2594    const char* str =
   2595        DuplicateString(cx, rhs.introducerFilename().c_str()).release();
   2596    if (!str) {
   2597      return false;
   2598    }
   2599    introducerFilename_ = JS::ConstUTF8CharsZ(str);
   2600  }
   2601 
   2602  return true;
   2603 }
   2604 
   2605 bool JS::OwningCompileOptions::copy(JSContext* cx,
   2606                                    const ReadOnlyCompileOptions& rhs) {
   2607  return copyImpl(cx, rhs);
   2608 }
   2609 
   2610 bool JS::OwningCompileOptions::copy(JS::FrontendContext* fc,
   2611                                    const ReadOnlyCompileOptions& rhs) {
   2612  return copyImpl(fc, rhs);
   2613 }
   2614 
   2615 JS::CompileOptions::CompileOptions(JSContext* cx) {
   2616  prefableOptions_ = cx->options().compileOptions();
   2617 
   2618  if (cx->options().asmJSOption() == AsmJSOption::Enabled) {
   2619    if (!js::IsAsmJSCompilationAvailable(cx)) {
   2620      prefableOptions_.setAsmJSOption(AsmJSOption::DisabledByNoWasmCompiler);
   2621    } else if (cx->realm() && (cx->realm()->debuggerObservesWasm() ||
   2622                               cx->realm()->debuggerObservesAsmJS())) {
   2623      prefableOptions_.setAsmJSOption(AsmJSOption::DisabledByDebugger);
   2624    }
   2625  }
   2626 
   2627  // Certain modes of operation disallow syntax parsing in general.
   2628  if (coverage::IsLCovEnabled()) {
   2629    eagerDelazificationStrategy_ = DelazificationOption::ParseEverythingEagerly;
   2630  }
   2631 
   2632  // Note: If we parse outside of a specific realm, we do not inherit any realm
   2633  // behaviours. These can still be set manually on the options though.
   2634  if (Realm* realm = cx->realm()) {
   2635    alwaysUseFdlibm_ = realm->creationOptions().alwaysUseFdlibm();
   2636    discardSource = realm->behaviors().discardSource();
   2637  }
   2638 
   2639  if (cx->options().disableFilenameSecurityChecks()) {
   2640    skipFilenameValidation_ = true;
   2641  }
   2642 }
   2643 
   2644 JS::InstantiateOptions::InstantiateOptions() {
   2645  if (coverage::IsLCovEnabled()) {
   2646    eagerDelazificationStrategy_ = DelazificationOption::ParseEverythingEagerly;
   2647  }
   2648 }
   2649 
   2650 CompileOptions& CompileOptions::setIntroductionInfoToCaller(
   2651    JSContext* cx, const char* introductionType,
   2652    MutableHandle<JSScript*> introductionScript) {
   2653  RootedScript maybeScript(cx);
   2654  const char* filename;
   2655  uint32_t lineno;
   2656  uint32_t pcOffset;
   2657  bool mutedErrors;
   2658  DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno,
   2659                                       &pcOffset, &mutedErrors);
   2660  if (filename) {
   2661    introductionScript.set(maybeScript);
   2662    return setIntroductionInfo(filename, introductionType, lineno, pcOffset);
   2663  }
   2664  return setIntroductionType(introductionType);
   2665 }
   2666 
   2667 JS::OwningDecodeOptions::~OwningDecodeOptions() { release(); }
   2668 
   2669 void JS::OwningDecodeOptions::release() {
   2670  js_free(const_cast<char*>(introducerFilename_.c_str()));
   2671 
   2672  introducerFilename_ = JS::ConstUTF8CharsZ();
   2673 }
   2674 
   2675 bool JS::OwningDecodeOptions::copy(JS::FrontendContext* maybeFc,
   2676                                   const JS::ReadOnlyDecodeOptions& rhs) {
   2677  copyPODOptionsFrom(rhs);
   2678 
   2679  if (rhs.introducerFilename()) {
   2680    MOZ_ASSERT(maybeFc);
   2681    const char* str =
   2682        DuplicateString(maybeFc, rhs.introducerFilename().c_str()).release();
   2683    if (!str) {
   2684      return false;
   2685    }
   2686    introducerFilename_ = JS::ConstUTF8CharsZ(str);
   2687  }
   2688 
   2689  return true;
   2690 }
   2691 
   2692 void JS::OwningDecodeOptions::infallibleCopy(
   2693    const JS::ReadOnlyDecodeOptions& rhs) {
   2694  copyPODOptionsFrom(rhs);
   2695 
   2696  MOZ_ASSERT(!rhs.introducerFilename());
   2697 }
   2698 
   2699 size_t JS::OwningDecodeOptions::sizeOfExcludingThis(
   2700    mozilla::MallocSizeOf mallocSizeOf) const {
   2701  return mallocSizeOf(introducerFilename_.c_str());
   2702 }
   2703 
   2704 JS_PUBLIC_API JSObject* JS_GetGlobalFromScript(JSScript* script) {
   2705  return &script->global();
   2706 }
   2707 
   2708 JS_PUBLIC_API const char* JS_GetScriptFilename(JSScript* script) {
   2709  // This is called from ThreadStackHelper which can be called from another
   2710  // thread or inside a signal hander, so we need to be careful in case a
   2711  // copmacting GC is currently moving things around.
   2712  return script->maybeForwardedFilename();
   2713 }
   2714 
   2715 JS_PUBLIC_API unsigned JS_GetScriptBaseLineNumber(JSContext* cx,
   2716                                                  JSScript* script) {
   2717  return script->lineno();
   2718 }
   2719 
   2720 JS_PUBLIC_API JSScript* JS_GetFunctionScript(JSContext* cx,
   2721                                             HandleFunction fun) {
   2722  if (fun->isNativeFun()) {
   2723    return nullptr;
   2724  }
   2725 
   2726  if (fun->hasBytecode()) {
   2727    return fun->nonLazyScript();
   2728  }
   2729 
   2730  AutoRealm ar(cx, fun);
   2731  JSScript* script = JSFunction::getOrCreateScript(cx, fun);
   2732  if (!script) {
   2733    MOZ_CRASH();
   2734  }
   2735  return script;
   2736 }
   2737 
   2738 JS_PUBLIC_API JSString* JS_DecompileScript(JSContext* cx, HandleScript script) {
   2739  MOZ_ASSERT(!cx->zone()->isAtomsZone());
   2740 
   2741  AssertHeapIsIdle();
   2742  CHECK_THREAD(cx);
   2743  RootedFunction fun(cx, script->function());
   2744  if (fun) {
   2745    return JS_DecompileFunction(cx, fun);
   2746  }
   2747  bool haveSource;
   2748  if (!ScriptSource::loadSource(cx, script->scriptSource(), &haveSource)) {
   2749    return nullptr;
   2750  }
   2751  return haveSource ? JSScript::sourceData(cx, script)
   2752                    : NewStringCopyZ<CanGC>(cx, "[no source]");
   2753 }
   2754 
   2755 JS_PUBLIC_API JSString* JS_DecompileFunction(JSContext* cx,
   2756                                             HandleFunction fun) {
   2757  MOZ_ASSERT(!cx->zone()->isAtomsZone());
   2758  AssertHeapIsIdle();
   2759  CHECK_THREAD(cx);
   2760  cx->check(fun);
   2761  return FunctionToString(cx, fun, /* isToSource = */ false);
   2762 }
   2763 
   2764 JS_PUBLIC_API void JS::SetScriptPrivate(JSScript* script,
   2765                                        const JS::Value& value) {
   2766  JSRuntime* rt = script->zone()->runtimeFromMainThread();
   2767  script->sourceObject()->setPrivate(rt, value);
   2768 }
   2769 
   2770 JS_PUBLIC_API JS::Value JS::GetScriptPrivate(JSScript* script) {
   2771  return script->sourceObject()->getPrivate();
   2772 }
   2773 
   2774 JS_PUBLIC_API JS::Value JS::GetScriptedCallerPrivate(JSContext* cx) {
   2775  AssertHeapIsIdle();
   2776  CHECK_THREAD(cx);
   2777 
   2778  NonBuiltinFrameIter iter(cx, cx->realm()->principals());
   2779  if (iter.done() || !iter.hasScript()) {
   2780    return UndefinedValue();
   2781  }
   2782 
   2783  return iter.script()->sourceObject()->getPrivate();
   2784 }
   2785 
   2786 JS_PUBLIC_API void JS::SetScriptPrivateReferenceHooks(
   2787    JSRuntime* rt, JS::ScriptPrivateReferenceHook addRefHook,
   2788    JS::ScriptPrivateReferenceHook releaseHook) {
   2789  AssertHeapIsIdle();
   2790  rt->scriptPrivateAddRefHook = addRefHook;
   2791  rt->scriptPrivateReleaseHook = releaseHook;
   2792 }
   2793 
   2794 JS_PUBLIC_API void JS::SetWaitCallback(JSRuntime* rt,
   2795                                       BeforeWaitCallback beforeWait,
   2796                                       AfterWaitCallback afterWait,
   2797                                       size_t requiredMemory) {
   2798  MOZ_RELEASE_ASSERT(requiredMemory <= WAIT_CALLBACK_CLIENT_MAXMEM);
   2799  MOZ_RELEASE_ASSERT((beforeWait == nullptr) == (afterWait == nullptr));
   2800  rt->beforeWaitCallback = beforeWait;
   2801  rt->afterWaitCallback = afterWait;
   2802 }
   2803 
   2804 JS_PUBLIC_API bool JS_CheckForInterrupt(JSContext* cx) {
   2805  return js::CheckForInterrupt(cx);
   2806 }
   2807 
   2808 JS_PUBLIC_API bool JS_AddInterruptCallback(JSContext* cx,
   2809                                           JSInterruptCallback callback) {
   2810  return cx->interruptCallbacks().append(callback);
   2811 }
   2812 
   2813 JS_PUBLIC_API bool JS_DisableInterruptCallback(JSContext* cx) {
   2814  bool result = cx->interruptCallbackDisabled;
   2815  cx->interruptCallbackDisabled = true;
   2816  return result;
   2817 }
   2818 
   2819 JS_PUBLIC_API void JS_ResetInterruptCallback(JSContext* cx, bool enable) {
   2820  cx->interruptCallbackDisabled = enable;
   2821 }
   2822 
   2823 /************************************************************************/
   2824 
   2825 /*
   2826 * Promises.
   2827 */
   2828 JS_PUBLIC_API void JS::SetJobQueue(JSContext* cx, JobQueue* queue) {
   2829  cx->jobQueue = queue;
   2830 }
   2831 
   2832 extern JS_PUBLIC_API void JS::SetPromiseRejectionTrackerCallback(
   2833    JSContext* cx, PromiseRejectionTrackerCallback callback,
   2834    void* data /* = nullptr */) {
   2835  cx->promiseRejectionTrackerCallback = callback;
   2836  cx->promiseRejectionTrackerCallbackData = data;
   2837 }
   2838 
   2839 extern JS_PUBLIC_API void JS::JobQueueIsEmpty(JSContext* cx) {
   2840  cx->canSkipEnqueuingJobs = true;
   2841 }
   2842 
   2843 extern JS_PUBLIC_API void JS::JobQueueMayNotBeEmpty(JSContext* cx) {
   2844  cx->canSkipEnqueuingJobs = false;
   2845 }
   2846 
   2847 JS_PUBLIC_API JSObject* JS::NewPromiseObject(JSContext* cx,
   2848                                             HandleObject executor) {
   2849  MOZ_ASSERT(!cx->zone()->isAtomsZone());
   2850  AssertHeapIsIdle();
   2851  CHECK_THREAD(cx);
   2852  cx->check(executor);
   2853 
   2854  if (!executor) {
   2855    return PromiseObject::createSkippingExecutor(cx);
   2856  }
   2857 
   2858  MOZ_ASSERT(IsCallable(executor));
   2859  return PromiseObject::create(cx, executor);
   2860 }
   2861 
   2862 JS_PUBLIC_API bool JS::IsPromiseObject(JS::HandleObject obj) {
   2863  return obj->is<PromiseObject>();
   2864 }
   2865 
   2866 JS_PUBLIC_API JSObject* JS::GetPromiseConstructor(JSContext* cx) {
   2867  CHECK_THREAD(cx);
   2868  Rooted<GlobalObject*> global(cx, cx->global());
   2869  return GlobalObject::getOrCreatePromiseConstructor(cx, global);
   2870 }
   2871 
   2872 JS_PUBLIC_API JSObject* JS::GetPromisePrototype(JSContext* cx) {
   2873  CHECK_THREAD(cx);
   2874  Rooted<GlobalObject*> global(cx, cx->global());
   2875  return GlobalObject::getOrCreatePromisePrototype(cx, global);
   2876 }
   2877 
   2878 JS_PUBLIC_API JS::PromiseState JS::GetPromiseState(JS::HandleObject promise) {
   2879  PromiseObject* promiseObj = promise->maybeUnwrapIf<PromiseObject>();
   2880  if (!promiseObj) {
   2881    return JS::PromiseState::Pending;
   2882  }
   2883 
   2884  return promiseObj->state();
   2885 }
   2886 
   2887 JS_PUBLIC_API uint64_t JS::GetPromiseID(JS::HandleObject promise) {
   2888  return promise->as<PromiseObject>().getID();
   2889 }
   2890 
   2891 JS_PUBLIC_API JS::Value JS::GetPromiseResult(JS::HandleObject promiseObj) {
   2892  PromiseObject* promise = &promiseObj->as<PromiseObject>();
   2893  MOZ_ASSERT(promise->state() != JS::PromiseState::Pending);
   2894  return promise->state() == JS::PromiseState::Fulfilled ? promise->value()
   2895                                                         : promise->reason();
   2896 }
   2897 
   2898 JS_PUBLIC_API bool JS::GetPromiseIsHandled(JS::HandleObject promise) {
   2899  PromiseObject* promiseObj = &promise->as<PromiseObject>();
   2900  return !promiseObj->isUnhandled();
   2901 }
   2902 
   2903 static PromiseObject* UnwrapPromise(JSContext* cx, JS::HandleObject promise,
   2904                                    mozilla::Maybe<AutoRealm>& ar) {
   2905  AssertHeapIsIdle();
   2906  CHECK_THREAD(cx);
   2907  cx->check(promise);
   2908 
   2909  PromiseObject* promiseObj;
   2910  if (IsWrapper(promise)) {
   2911    promiseObj = promise->maybeUnwrapAs<PromiseObject>();
   2912    if (!promiseObj) {
   2913      ReportAccessDenied(cx);
   2914      return nullptr;
   2915    }
   2916    ar.emplace(cx, promiseObj);
   2917  } else {
   2918    promiseObj = promise.as<PromiseObject>();
   2919  }
   2920  return promiseObj;
   2921 }
   2922 
   2923 JS_PUBLIC_API bool JS::SetSettledPromiseIsHandled(JSContext* cx,
   2924                                                  JS::HandleObject promise) {
   2925  mozilla::Maybe<AutoRealm> ar;
   2926  Rooted<PromiseObject*> promiseObj(cx, UnwrapPromise(cx, promise, ar));
   2927  if (!promiseObj) {
   2928    return false;
   2929  }
   2930  js::SetSettledPromiseIsHandled(cx, promiseObj);
   2931  return true;
   2932 }
   2933 
   2934 JS_PUBLIC_API bool JS::SetAnyPromiseIsHandled(JSContext* cx,
   2935                                              JS::HandleObject promise) {
   2936  mozilla::Maybe<AutoRealm> ar;
   2937  Rooted<PromiseObject*> promiseObj(cx, UnwrapPromise(cx, promise, ar));
   2938  if (!promiseObj) {
   2939    return false;
   2940  }
   2941  js::SetAnyPromiseIsHandled(cx, promiseObj);
   2942  return true;
   2943 }
   2944 
   2945 JS_PUBLIC_API JSObject* JS::GetPromiseAllocationSite(JS::HandleObject promise) {
   2946  return promise->as<PromiseObject>().allocationSite();
   2947 }
   2948 
   2949 JS_PUBLIC_API JSObject* JS::GetPromiseResolutionSite(JS::HandleObject promise) {
   2950  return promise->as<PromiseObject>().resolutionSite();
   2951 }
   2952 
   2953 #ifdef DEBUG
   2954 JS_PUBLIC_API void JS::DumpPromiseAllocationSite(JSContext* cx,
   2955                                                 JS::HandleObject promise) {
   2956  RootedObject stack(cx, promise->as<PromiseObject>().allocationSite());
   2957  JSPrincipals* principals = cx->realm()->principals();
   2958  UniqueChars stackStr = BuildUTF8StackString(cx, principals, stack);
   2959  if (stackStr) {
   2960    fputs(stackStr.get(), stderr);
   2961  }
   2962 }
   2963 
   2964 JS_PUBLIC_API void JS::DumpPromiseResolutionSite(JSContext* cx,
   2965                                                 JS::HandleObject promise) {
   2966  RootedObject stack(cx, promise->as<PromiseObject>().resolutionSite());
   2967  JSPrincipals* principals = cx->realm()->principals();
   2968  UniqueChars stackStr = BuildUTF8StackString(cx, principals, stack);
   2969  if (stackStr) {
   2970    fputs(stackStr.get(), stderr);
   2971  }
   2972 }
   2973 #endif
   2974 
   2975 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseResolve(
   2976    JSContext* cx, JS::HandleValue resolutionValue) {
   2977  AssertHeapIsIdle();
   2978  CHECK_THREAD(cx);
   2979  cx->check(resolutionValue);
   2980 
   2981  RootedObject promise(cx,
   2982                       PromiseObject::unforgeableResolve(cx, resolutionValue));
   2983  MOZ_ASSERT_IF(promise, promise->canUnwrapAs<PromiseObject>());
   2984  return promise;
   2985 }
   2986 
   2987 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseReject(
   2988    JSContext* cx, JS::HandleValue rejectionValue) {
   2989  AssertHeapIsIdle();
   2990  CHECK_THREAD(cx);
   2991  cx->check(rejectionValue);
   2992 
   2993  RootedObject promise(cx,
   2994                       PromiseObject::unforgeableReject(cx, rejectionValue));
   2995  MOZ_ASSERT_IF(promise, promise->canUnwrapAs<PromiseObject>());
   2996  return promise;
   2997 }
   2998 
   2999 static bool ResolveOrRejectPromise(JSContext* cx, JS::HandleObject promiseObj,
   3000                                   JS::HandleValue resultOrReason_,
   3001                                   bool reject) {
   3002  AssertHeapIsIdle();
   3003  CHECK_THREAD(cx);
   3004  cx->check(promiseObj, resultOrReason_);
   3005 
   3006  mozilla::Maybe<AutoRealm> ar;
   3007  Rooted<PromiseObject*> promise(cx);
   3008  RootedValue resultOrReason(cx, resultOrReason_);
   3009  if (IsWrapper(promiseObj)) {
   3010    promise = promiseObj->maybeUnwrapAs<PromiseObject>();
   3011    if (!promise) {
   3012      ReportAccessDenied(cx);
   3013      return false;
   3014    }
   3015    ar.emplace(cx, promise);
   3016    if (!cx->compartment()->wrap(cx, &resultOrReason)) {
   3017      return false;
   3018    }
   3019  } else {
   3020    promise = promiseObj.as<PromiseObject>();
   3021  }
   3022 
   3023  return reject ? PromiseObject::reject(cx, promise, resultOrReason)
   3024                : PromiseObject::resolve(cx, promise, resultOrReason);
   3025 }
   3026 
   3027 JS_PUBLIC_API bool JS::ResolvePromise(JSContext* cx,
   3028                                      JS::HandleObject promiseObj,
   3029                                      JS::HandleValue resolutionValue) {
   3030  return ResolveOrRejectPromise(cx, promiseObj, resolutionValue, false);
   3031 }
   3032 
   3033 JS_PUBLIC_API bool JS::RejectPromise(JSContext* cx, JS::HandleObject promiseObj,
   3034                                     JS::HandleValue rejectionValue) {
   3035  return ResolveOrRejectPromise(cx, promiseObj, rejectionValue, true);
   3036 }
   3037 
   3038 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseThen(
   3039    JSContext* cx, JS::HandleObject promiseObj, JS::HandleObject onFulfilled,
   3040    JS::HandleObject onRejected) {
   3041  AssertHeapIsIdle();
   3042  CHECK_THREAD(cx);
   3043  cx->check(promiseObj, onFulfilled, onRejected);
   3044 
   3045  MOZ_ASSERT_IF(onFulfilled, IsCallable(onFulfilled));
   3046  MOZ_ASSERT_IF(onRejected, IsCallable(onRejected));
   3047 
   3048  return OriginalPromiseThen(cx, promiseObj, onFulfilled, onRejected);
   3049 }
   3050 
   3051 [[nodiscard]] static bool ReactToPromise(JSContext* cx,
   3052                                         JS::Handle<JSObject*> promiseObj,
   3053                                         JS::Handle<JSObject*> onFulfilled,
   3054                                         JS::Handle<JSObject*> onRejected,
   3055                                         UnhandledRejectionBehavior behavior) {
   3056  AssertHeapIsIdle();
   3057  CHECK_THREAD(cx);
   3058  cx->check(promiseObj, onFulfilled, onRejected);
   3059 
   3060  MOZ_ASSERT_IF(onFulfilled, IsCallable(onFulfilled));
   3061  MOZ_ASSERT_IF(onRejected, IsCallable(onRejected));
   3062 
   3063  Rooted<PromiseObject*> unwrappedPromise(cx);
   3064  {
   3065    RootedValue promiseVal(cx, ObjectValue(*promiseObj));
   3066    unwrappedPromise = UnwrapAndTypeCheckValue<PromiseObject>(
   3067        cx, promiseVal, [cx, promiseObj] {
   3068          JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
   3069                                     JSMSG_INCOMPATIBLE_PROTO, "Promise",
   3070                                     "then", promiseObj->getClass()->name);
   3071        });
   3072    if (!unwrappedPromise) {
   3073      return false;
   3074    }
   3075  }
   3076 
   3077  return ReactToUnwrappedPromise(cx, unwrappedPromise, onFulfilled, onRejected,
   3078                                 behavior);
   3079 }
   3080 
   3081 JS_PUBLIC_API bool JS::AddPromiseReactions(JSContext* cx,
   3082                                           JS::HandleObject promiseObj,
   3083                                           JS::HandleObject onFulfilled,
   3084                                           JS::HandleObject onRejected) {
   3085  return ReactToPromise(cx, promiseObj, onFulfilled, onRejected,
   3086                        UnhandledRejectionBehavior::Report);
   3087 }
   3088 
   3089 JS_PUBLIC_API bool JS::AddPromiseReactionsIgnoringUnhandledRejection(
   3090    JSContext* cx, JS::HandleObject promiseObj, JS::HandleObject onFulfilled,
   3091    JS::HandleObject onRejected) {
   3092  return ReactToPromise(cx, promiseObj, onFulfilled, onRejected,
   3093                        UnhandledRejectionBehavior::Ignore);
   3094 }
   3095 
   3096 JS_PUBLIC_API JS::PromiseUserInputEventHandlingState
   3097 JS::GetPromiseUserInputEventHandlingState(JS::HandleObject promiseObj_) {
   3098  PromiseObject* promise = promiseObj_->maybeUnwrapIf<PromiseObject>();
   3099  if (!promise) {
   3100    return JS::PromiseUserInputEventHandlingState::DontCare;
   3101  }
   3102 
   3103  if (!promise->requiresUserInteractionHandling()) {
   3104    return JS::PromiseUserInputEventHandlingState::DontCare;
   3105  }
   3106  if (promise->hadUserInteractionUponCreation()) {
   3107    return JS::PromiseUserInputEventHandlingState::HadUserInteractionAtCreation;
   3108  }
   3109  return JS::PromiseUserInputEventHandlingState::
   3110      DidntHaveUserInteractionAtCreation;
   3111 }
   3112 
   3113 JS_PUBLIC_API bool JS::SetPromiseUserInputEventHandlingState(
   3114    JS::HandleObject promiseObj_,
   3115    JS::PromiseUserInputEventHandlingState state) {
   3116  PromiseObject* promise = promiseObj_->maybeUnwrapIf<PromiseObject>();
   3117  if (!promise) {
   3118    return false;
   3119  }
   3120 
   3121  switch (state) {
   3122    case JS::PromiseUserInputEventHandlingState::DontCare:
   3123      promise->setRequiresUserInteractionHandling(false);
   3124      break;
   3125    case JS::PromiseUserInputEventHandlingState::HadUserInteractionAtCreation:
   3126      promise->setRequiresUserInteractionHandling(true);
   3127      promise->setHadUserInteractionUponCreation(true);
   3128      break;
   3129    case JS::PromiseUserInputEventHandlingState::
   3130        DidntHaveUserInteractionAtCreation:
   3131      promise->setRequiresUserInteractionHandling(true);
   3132      promise->setHadUserInteractionUponCreation(false);
   3133      break;
   3134    default:
   3135      MOZ_ASSERT_UNREACHABLE(
   3136          "Invalid PromiseUserInputEventHandlingState enum value");
   3137      return false;
   3138  }
   3139  return true;
   3140 }
   3141 
   3142 /* static */
   3143 void JS::Dispatchable::Run(JSContext* cx,
   3144                           js::UniquePtr<JS::Dispatchable>&& task,
   3145                           MaybeShuttingDown maybeShuttingDown) {
   3146  // Release the uniquePtr so that we don't have a double delete.
   3147  JS::Dispatchable* rawTaskPtr = task.release();
   3148  // Execute run. This will result in the task being deleted.
   3149  rawTaskPtr->run(cx, maybeShuttingDown);
   3150 }
   3151 
   3152 /* static */
   3153 void JS::Dispatchable::ReleaseFailedTask(
   3154    js::UniquePtr<JS::Dispatchable>&& task) {
   3155  // release the task from the uniquePtr so that it does not delete.
   3156  JS::Dispatchable* rawTaskPtr = task.release();
   3157  // We've attempted to transfer to the embedding, but this has failed.
   3158  // Transfer the task back to the runtime, as defined by the subclass of
   3159  // JS::Dispatchable. The Runtime will delete the task once we are sure
   3160  // we are once more executing on the main thread.
   3161  rawTaskPtr->transferToRuntime();
   3162 }
   3163 
   3164 /**
   3165 * Unforgeable version of Promise.all for internal use.
   3166 *
   3167 * Takes a dense array of Promise objects and returns a promise that's
   3168 * resolved with an array of resolution values when all those promises ahve
   3169 * been resolved, or rejected with the rejection value of the first rejected
   3170 * promise.
   3171 *
   3172 * Asserts that the array is dense and all entries are Promise objects.
   3173 */
   3174 JS_PUBLIC_API JSObject* JS::GetWaitForAllPromise(
   3175    JSContext* cx, JS::HandleObjectVector promises) {
   3176  AssertHeapIsIdle();
   3177  CHECK_THREAD(cx);
   3178 
   3179  return js::GetWaitForAllPromise(cx, promises);
   3180 }
   3181 
   3182 JS_PUBLIC_API void JS::InitAsyncTaskCallbacks(
   3183    JSContext* cx, JS::DispatchToEventLoopCallback dispatchCallback,
   3184    JS::DelayedDispatchToEventLoopCallback delayedDispatchCallback,
   3185    JS::AsyncTaskStartedCallback asyncTaskStartedCallback,
   3186    JS::AsyncTaskFinishedCallback asyncTaskFinishedCallback, void* closure) {
   3187  cx->runtime()->offThreadPromiseState.ref().init(
   3188      dispatchCallback, delayedDispatchCallback, asyncTaskStartedCallback,
   3189      asyncTaskFinishedCallback, closure);
   3190 }
   3191 
   3192 JS_PUBLIC_API void JS::CancelAsyncTasks(JSContext* cx) {
   3193  cx->runtime()->offThreadPromiseState.ref().cancelTasks(cx);
   3194 }
   3195 
   3196 JS_PUBLIC_API void JS::ShutdownAsyncTasks(JSContext* cx) {
   3197  cx->runtime()->offThreadPromiseState.ref().shutdown(cx);
   3198 }
   3199 
   3200 JS_PUBLIC_API void JS::InitConsumeStreamCallback(
   3201    JSContext* cx, ConsumeStreamCallback consume,
   3202    ReportStreamErrorCallback report) {
   3203  cx->runtime()->consumeStreamCallback = consume;
   3204  cx->runtime()->reportStreamErrorCallback = report;
   3205 }
   3206 
   3207 JS_PUBLIC_API void JS_RequestInterruptCallback(JSContext* cx) {
   3208  cx->requestInterrupt(InterruptReason::CallbackUrgent);
   3209 }
   3210 
   3211 JS_PUBLIC_API void JS_RequestInterruptCallbackCanWait(JSContext* cx) {
   3212  cx->requestInterrupt(InterruptReason::CallbackCanWait);
   3213 }
   3214 
   3215 JS::AutoSetAsyncStackForNewCalls::AutoSetAsyncStackForNewCalls(
   3216    JSContext* cx, JSObject* stack, const char* asyncCause,
   3217    JS::AutoSetAsyncStackForNewCalls::AsyncCallKind kind)
   3218    : cx(cx),
   3219      oldAsyncStack(cx, cx->asyncStackForNewActivations()),
   3220      oldAsyncCause(cx->asyncCauseForNewActivations),
   3221      oldAsyncCallIsExplicit(cx->asyncCallIsExplicit) {
   3222  CHECK_THREAD(cx);
   3223 
   3224  // The option determines whether we actually use the new values at this
   3225  // point. It will not affect restoring the previous values when the object
   3226  // is destroyed, so if the option changes it won't cause consistency issues.
   3227  if (!cx->options().asyncStack()) {
   3228    return;
   3229  }
   3230 
   3231  SavedFrame* asyncStack = &stack->as<SavedFrame>();
   3232 
   3233  cx->asyncStackForNewActivations() = asyncStack;
   3234  cx->asyncCauseForNewActivations = asyncCause;
   3235  cx->asyncCallIsExplicit = kind == AsyncCallKind::EXPLICIT;
   3236 }
   3237 
   3238 JS::AutoSetAsyncStackForNewCalls::~AutoSetAsyncStackForNewCalls() {
   3239  cx->asyncCauseForNewActivations = oldAsyncCause;
   3240  cx->asyncStackForNewActivations() =
   3241      oldAsyncStack ? &oldAsyncStack->as<SavedFrame>() : nullptr;
   3242  cx->asyncCallIsExplicit = oldAsyncCallIsExplicit;
   3243 }
   3244 
   3245 /************************************************************************/
   3246 JS_PUBLIC_API JSString* JS_NewStringCopyN(JSContext* cx, const char* s,
   3247                                          size_t n) {
   3248  AssertHeapIsIdle();
   3249  CHECK_THREAD(cx);
   3250  return NewStringCopyN<CanGC>(cx, s, n);
   3251 }
   3252 
   3253 JS_PUBLIC_API JSString* JS_NewStringCopyZ(JSContext* cx, const char* s) {
   3254  AssertHeapIsIdle();
   3255  CHECK_THREAD(cx);
   3256  if (!s) {
   3257    return cx->runtime()->emptyString;
   3258  }
   3259  return NewStringCopyZ<CanGC>(cx, s);
   3260 }
   3261 
   3262 JS_PUBLIC_API JSString* JS_NewStringCopyUTF8Z(JSContext* cx,
   3263                                              const JS::ConstUTF8CharsZ s) {
   3264  AssertHeapIsIdle();
   3265  CHECK_THREAD(cx);
   3266  return NewStringCopyUTF8Z(cx, s);
   3267 }
   3268 
   3269 JS_PUBLIC_API JSString* JS_NewStringCopyUTF8N(JSContext* cx,
   3270                                              const JS::UTF8Chars& s) {
   3271  AssertHeapIsIdle();
   3272  CHECK_THREAD(cx);
   3273  return NewStringCopyUTF8N(cx, s);
   3274 }
   3275 
   3276 JS_PUBLIC_API bool JS_StringHasBeenPinned(JSContext* cx, JSString* str) {
   3277  AssertHeapIsIdle();
   3278  CHECK_THREAD(cx);
   3279 
   3280  if (!str->isAtom()) {
   3281    return false;
   3282  }
   3283 
   3284  return AtomIsPinned(cx, &str->asAtom());
   3285 }
   3286 
   3287 JS_PUBLIC_API JSString* JS_AtomizeString(JSContext* cx, const char* s) {
   3288  return JS_AtomizeStringN(cx, s, strlen(s));
   3289 }
   3290 
   3291 JS_PUBLIC_API JSString* JS_AtomizeStringN(JSContext* cx, const char* s,
   3292                                          size_t length) {
   3293  AssertHeapIsIdle();
   3294  CHECK_THREAD(cx);
   3295  return Atomize(cx, s, length);
   3296 }
   3297 
   3298 JS_PUBLIC_API JSString* JS_AtomizeAndPinString(JSContext* cx, const char* s) {
   3299  return JS_AtomizeAndPinStringN(cx, s, strlen(s));
   3300 }
   3301 
   3302 JS_PUBLIC_API JSString* JS_AtomizeAndPinStringN(JSContext* cx, const char* s,
   3303                                                size_t length) {
   3304  AssertHeapIsIdle();
   3305  CHECK_THREAD(cx);
   3306 
   3307  JSAtom* atom = cx->zone() ? Atomize(cx, s, length)
   3308                            : AtomizeWithoutActiveZone(cx, s, length);
   3309  if (!atom || !PinAtom(cx, atom)) {
   3310    return nullptr;
   3311  }
   3312 
   3313  MOZ_ASSERT(JS_StringHasBeenPinned(cx, atom));
   3314  return atom;
   3315 }
   3316 
   3317 JS_PUBLIC_API JSString* JS_NewLatin1String(
   3318    JSContext* cx, js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> chars,
   3319    size_t length) {
   3320  AssertHeapIsIdle();
   3321  CHECK_THREAD(cx);
   3322  return NewString<CanGC>(cx, std::move(chars), length);
   3323 }
   3324 
   3325 JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx,
   3326                                       JS::UniqueTwoByteChars chars,
   3327                                       size_t length) {
   3328  AssertHeapIsIdle();
   3329  CHECK_THREAD(cx);
   3330  return NewString<CanGC>(cx, std::move(chars), length);
   3331 }
   3332 
   3333 JS_PUBLIC_API JSString* JS_NewUCStringDontDeflate(JSContext* cx,
   3334                                                  JS::UniqueTwoByteChars chars,
   3335                                                  size_t length) {
   3336  AssertHeapIsIdle();
   3337  CHECK_THREAD(cx);
   3338  return NewStringDontDeflate<CanGC>(cx, std::move(chars), length);
   3339 }
   3340 
   3341 JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx, const char16_t* s,
   3342                                            size_t n) {
   3343  AssertHeapIsIdle();
   3344  CHECK_THREAD(cx);
   3345  if (!n) {
   3346    return cx->names().empty_;
   3347  }
   3348  return NewStringCopyN<CanGC>(cx, s, n);
   3349 }
   3350 
   3351 JS_PUBLIC_API JSString* JS_NewUCStringCopyZ(JSContext* cx, const char16_t* s) {
   3352  AssertHeapIsIdle();
   3353  CHECK_THREAD(cx);
   3354  if (!s) {
   3355    return cx->runtime()->emptyString;
   3356  }
   3357  return NewStringCopyZ<CanGC>(cx, s);
   3358 }
   3359 
   3360 JS_PUBLIC_API JSString* JS_AtomizeUCString(JSContext* cx, const char16_t* s) {
   3361  return JS_AtomizeUCStringN(cx, s, js_strlen(s));
   3362 }
   3363 
   3364 JS_PUBLIC_API JSString* JS_AtomizeUCStringN(JSContext* cx, const char16_t* s,
   3365                                            size_t length) {
   3366  AssertHeapIsIdle();
   3367  CHECK_THREAD(cx);
   3368  return AtomizeChars(cx, s, length);
   3369 }
   3370 
   3371 JS_PUBLIC_API size_t JS_GetStringLength(JSString* str) { return str->length(); }
   3372 
   3373 JS_PUBLIC_API bool JS_StringIsLinear(JSString* str) { return str->isLinear(); }
   3374 
   3375 JS_PUBLIC_API bool JS_DeprecatedStringHasLatin1Chars(JSString* str) {
   3376  return str->hasLatin1Chars();
   3377 }
   3378 
   3379 JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength(
   3380    JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str,
   3381    size_t* plength) {
   3382  MOZ_ASSERT(plength);
   3383  AssertHeapIsIdle();
   3384  CHECK_THREAD(cx);
   3385  cx->check(str);
   3386  JSLinearString* linear = str->ensureLinear(cx);
   3387  if (!linear) {
   3388    return nullptr;
   3389  }
   3390  *plength = linear->length();
   3391  return linear->latin1Chars(nogc);
   3392 }
   3393 
   3394 JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength(
   3395    JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str,
   3396    size_t* plength) {
   3397  MOZ_ASSERT(plength);
   3398  AssertHeapIsIdle();
   3399  CHECK_THREAD(cx);
   3400  cx->check(str);
   3401  JSLinearString* linear = str->ensureLinear(cx);
   3402  if (!linear) {
   3403    return nullptr;
   3404  }
   3405  *plength = linear->length();
   3406  return linear->twoByteChars(nogc);
   3407 }
   3408 
   3409 JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars(JSString* str) {
   3410  return str->asExternal().twoByteChars();
   3411 }
   3412 
   3413 JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str,
   3414                                      size_t index, char16_t* res) {
   3415  AssertHeapIsIdle();
   3416  CHECK_THREAD(cx);
   3417  cx->check(str);
   3418 
   3419  JSLinearString* linear = str->ensureLinear(cx);
   3420  if (!linear) {
   3421    return false;
   3422  }
   3423 
   3424  *res = linear->latin1OrTwoByteChar(index);
   3425  return true;
   3426 }
   3427 
   3428 JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx,
   3429                                      const mozilla::Range<char16_t>& dest,
   3430                                      JSString* str) {
   3431  AssertHeapIsIdle();
   3432  CHECK_THREAD(cx);
   3433  cx->check(str);
   3434 
   3435  JSLinearString* linear = str->ensureLinear(cx);
   3436  if (!linear) {
   3437    return false;
   3438  }
   3439 
   3440  MOZ_ASSERT(linear->length() <= dest.length());
   3441  CopyChars(dest.begin().get(), *linear);
   3442  return true;
   3443 }
   3444 
   3445 extern JS_PUBLIC_API JS::UniqueTwoByteChars JS_CopyStringCharsZ(JSContext* cx,
   3446                                                                JSString* str) {
   3447  AssertHeapIsIdle();
   3448  CHECK_THREAD(cx);
   3449 
   3450  JSLinearString* linear = str->ensureLinear(cx);
   3451  if (!linear) {
   3452    return nullptr;
   3453  }
   3454 
   3455  size_t len = linear->length();
   3456 
   3457  static_assert(JS::MaxStringLength < UINT32_MAX,
   3458                "len + 1 must not overflow on 32-bit platforms");
   3459 
   3460  UniqueTwoByteChars chars(cx->pod_malloc<char16_t>(len + 1));
   3461  if (!chars) {
   3462    return nullptr;
   3463  }
   3464 
   3465  CopyChars(chars.get(), *linear);
   3466  chars[len] = '\0';
   3467 
   3468  return chars;
   3469 }
   3470 
   3471 extern JS_PUBLIC_API JSLinearString* JS_EnsureLinearString(JSContext* cx,
   3472                                                           JSString* str) {
   3473  AssertHeapIsIdle();
   3474  CHECK_THREAD(cx);
   3475  cx->check(str);
   3476  return str->ensureLinear(cx);
   3477 }
   3478 
   3479 JS_PUBLIC_API bool JS_CompareStrings(JSContext* cx, JSString* str1,
   3480                                     JSString* str2, int32_t* result) {
   3481  AssertHeapIsIdle();
   3482  CHECK_THREAD(cx);
   3483 
   3484  return CompareStrings(cx, str1, str2, result);
   3485 }
   3486 
   3487 JS_PUBLIC_API bool JS_StringEqualsAscii(JSContext* cx, JSString* str,
   3488                                        const char* asciiBytes, bool* match) {
   3489  AssertHeapIsIdle();
   3490  CHECK_THREAD(cx);
   3491 
   3492  JSLinearString* linearStr = str->ensureLinear(cx);
   3493  if (!linearStr) {
   3494    return false;
   3495  }
   3496  *match = StringEqualsAscii(linearStr, asciiBytes);
   3497  return true;
   3498 }
   3499 
   3500 JS_PUBLIC_API bool JS_StringEqualsAscii(JSContext* cx, JSString* str,
   3501                                        const char* asciiBytes, size_t length,
   3502                                        bool* match) {
   3503  AssertHeapIsIdle();
   3504  CHECK_THREAD(cx);
   3505 
   3506  JSLinearString* linearStr = str->ensureLinear(cx);
   3507  if (!linearStr) {
   3508    return false;
   3509  }
   3510  *match = StringEqualsAscii(linearStr, asciiBytes, length);
   3511  return true;
   3512 }
   3513 
   3514 JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str,
   3515                                              const char* asciiBytes) {
   3516  return StringEqualsAscii(str, asciiBytes);
   3517 }
   3518 
   3519 JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str,
   3520                                              const char* asciiBytes,
   3521                                              size_t length) {
   3522  return StringEqualsAscii(str, asciiBytes, length);
   3523 }
   3524 
   3525 JS_PUBLIC_API size_t JS_PutEscapedLinearString(char* buffer, size_t size,
   3526                                               JSLinearString* str,
   3527                                               char quote) {
   3528  return PutEscapedString(buffer, size, str, quote);
   3529 }
   3530 
   3531 JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer,
   3532                                         size_t size, JSString* str,
   3533                                         char quote) {
   3534  AssertHeapIsIdle();
   3535  JSLinearString* linearStr = str->ensureLinear(cx);
   3536  if (!linearStr) {
   3537    return size_t(-1);
   3538  }
   3539  return PutEscapedString(buffer, size, linearStr, quote);
   3540 }
   3541 
   3542 JS_PUBLIC_API JSString* JS_NewDependentString(JSContext* cx, HandleString str,
   3543                                              size_t start, size_t length) {
   3544  AssertHeapIsIdle();
   3545  CHECK_THREAD(cx);
   3546  return NewDependentString(cx, str, start, length);
   3547 }
   3548 
   3549 JS_PUBLIC_API JSString* JS_ConcatStrings(JSContext* cx, HandleString left,
   3550                                         HandleString right) {
   3551  AssertHeapIsIdle();
   3552  CHECK_THREAD(cx);
   3553  return ConcatStrings<CanGC>(cx, left, right);
   3554 }
   3555 
   3556 JS_PUBLIC_API bool JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen,
   3557                                  char16_t* dst, size_t* dstlenp) {
   3558  AssertHeapIsIdle();
   3559  CHECK_THREAD(cx);
   3560 
   3561  if (!dst) {
   3562    *dstlenp = srclen;
   3563    return true;
   3564  }
   3565 
   3566  size_t dstlen = *dstlenp;
   3567 
   3568  if (srclen > dstlen) {
   3569    CopyAndInflateChars(dst, src, dstlen);
   3570 
   3571    gc::AutoSuppressGC suppress(cx);
   3572    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   3573                              JSMSG_BUFFER_TOO_SMALL);
   3574    return false;
   3575  }
   3576 
   3577  CopyAndInflateChars(dst, src, srclen);
   3578  *dstlenp = srclen;
   3579  return true;
   3580 }
   3581 
   3582 JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToASCII(JSContext* cx,
   3583                                                     JSString* str) {
   3584  AssertHeapIsIdle();
   3585  CHECK_THREAD(cx);
   3586 
   3587  return js::EncodeAscii(cx, str);
   3588 }
   3589 
   3590 JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToLatin1(JSContext* cx,
   3591                                                      JSString* str) {
   3592  AssertHeapIsIdle();
   3593  CHECK_THREAD(cx);
   3594 
   3595  return js::EncodeLatin1(cx, str);
   3596 }
   3597 
   3598 JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToUTF8(JSContext* cx,
   3599                                                    HandleString str) {
   3600  AssertHeapIsIdle();
   3601  CHECK_THREAD(cx);
   3602 
   3603  return StringToNewUTF8CharsZ(cx, *str);
   3604 }
   3605 
   3606 JS_PUBLIC_API size_t JS_GetStringEncodingLength(JSContext* cx, JSString* str) {
   3607  AssertHeapIsIdle();
   3608  CHECK_THREAD(cx);
   3609 
   3610  if (!str->ensureLinear(cx)) {
   3611    return size_t(-1);
   3612  }
   3613  return str->length();
   3614 }
   3615 
   3616 JS_PUBLIC_API bool JS_EncodeStringToBuffer(JSContext* cx, JSString* str,
   3617                                           char* buffer, size_t length) {
   3618  AssertHeapIsIdle();
   3619  CHECK_THREAD(cx);
   3620 
   3621  JSLinearString* linear = str->ensureLinear(cx);
   3622  if (!linear) {
   3623    return false;
   3624  }
   3625 
   3626  JS::AutoCheckCannotGC nogc;
   3627  size_t writeLength = std::min(linear->length(), length);
   3628  if (linear->hasLatin1Chars()) {
   3629    mozilla::PodCopy(reinterpret_cast<Latin1Char*>(buffer),
   3630                     linear->latin1Chars(nogc), writeLength);
   3631  } else {
   3632    const char16_t* src = linear->twoByteChars(nogc);
   3633    for (size_t i = 0; i < writeLength; i++) {
   3634      buffer[i] = char(src[i]);
   3635    }
   3636  }
   3637  return true;
   3638 }
   3639 
   3640 JS_PUBLIC_API mozilla::Maybe<std::tuple<size_t, size_t>>
   3641 JS_EncodeStringToUTF8BufferPartial(JSContext* cx, JSString* str,
   3642                                   mozilla::Span<char> buffer) {
   3643  AssertHeapIsIdle();
   3644  CHECK_THREAD(cx);
   3645  JS::AutoCheckCannotGC nogc;
   3646  return str->encodeUTF8Partial(nogc, buffer);
   3647 }
   3648 
   3649 JS_PUBLIC_API JS::Symbol* JS::NewSymbol(JSContext* cx,
   3650                                        HandleString description) {
   3651  AssertHeapIsIdle();
   3652  CHECK_THREAD(cx);
   3653  if (description) {
   3654    cx->check(description);
   3655  }
   3656 
   3657  return Symbol::new_(cx, SymbolCode::UniqueSymbol, description);
   3658 }
   3659 
   3660 JS_PUBLIC_API JS::Symbol* JS::GetSymbolFor(JSContext* cx, HandleString key) {
   3661  AssertHeapIsIdle();
   3662  CHECK_THREAD(cx);
   3663  cx->check(key);
   3664 
   3665  return Symbol::for_(cx, key);
   3666 }
   3667 
   3668 JS_PUBLIC_API JSString* JS::GetSymbolDescription(HandleSymbol symbol) {
   3669  return symbol->description();
   3670 }
   3671 
   3672 JS_PUBLIC_API JS::SymbolCode JS::GetSymbolCode(Handle<Symbol*> symbol) {
   3673  return symbol->code();
   3674 }
   3675 
   3676 JS_PUBLIC_API JS::Symbol* JS::GetWellKnownSymbol(JSContext* cx,
   3677                                                 JS::SymbolCode which) {
   3678  return cx->wellKnownSymbols().get(which);
   3679 }
   3680 
   3681 JS_PUBLIC_API JS::PropertyKey JS::GetWellKnownSymbolKey(JSContext* cx,
   3682                                                        JS::SymbolCode which) {
   3683  return PropertyKey::Symbol(cx->wellKnownSymbols().get(which));
   3684 }
   3685 
   3686 static bool AddPrefix(JSContext* cx, JS::Handle<JS::PropertyKey> id,
   3687                      FunctionPrefixKind prefixKind,
   3688                      JS::MutableHandle<JS::PropertyKey> out) {
   3689  JSAtom* atom = js::IdToFunctionName(cx, id, prefixKind);
   3690  if (!atom) {
   3691    return false;
   3692  }
   3693 
   3694  out.set(JS::PropertyKey::NonIntAtom(atom));
   3695  return true;
   3696 }
   3697 
   3698 JS_PUBLIC_API bool JS::ToGetterId(JSContext* cx, JS::Handle<JS::PropertyKey> id,
   3699                                  JS::MutableHandle<JS::PropertyKey> getterId) {
   3700  return AddPrefix(cx, id, FunctionPrefixKind::Get, getterId);
   3701 }
   3702 
   3703 JS_PUBLIC_API bool JS::ToSetterId(JSContext* cx, JS::Handle<JS::PropertyKey> id,
   3704                                  JS::MutableHandle<JS::PropertyKey> setterId) {
   3705  return AddPrefix(cx, id, FunctionPrefixKind::Set, setterId);
   3706 }
   3707 
   3708 #ifdef DEBUG
   3709 static bool PropertySpecNameIsDigits(JSPropertySpec::Name name) {
   3710  if (name.isSymbol()) {
   3711    return false;
   3712  }
   3713  const char* s = name.string();
   3714  if (!*s) {
   3715    return false;
   3716  }
   3717  for (; *s; s++) {
   3718    if (*s < '0' || *s > '9') {
   3719      return false;
   3720    }
   3721  }
   3722  return true;
   3723 }
   3724 #endif  // DEBUG
   3725 
   3726 JS_PUBLIC_API bool JS::PropertySpecNameEqualsId(JSPropertySpec::Name name,
   3727                                                HandleId id) {
   3728  if (name.isSymbol()) {
   3729    return id.isWellKnownSymbol(name.symbol());
   3730  }
   3731 
   3732  MOZ_ASSERT(!PropertySpecNameIsDigits(name));
   3733  return id.isAtom() && JS_LinearStringEqualsAscii(id.toAtom(), name.string());
   3734 }
   3735 
   3736 JS_PUBLIC_API bool JS_Stringify(JSContext* cx, MutableHandleValue vp,
   3737                                HandleObject replacer, HandleValue space,
   3738                                JSONWriteCallback callback, void* data) {
   3739  return JS_StringifyWithLengthHint(cx, vp, replacer, space, callback, data, 0);
   3740 }
   3741 
   3742 JS_PUBLIC_API bool JS_StringifyWithLengthHint(JSContext* cx,
   3743                                              MutableHandleValue vp,
   3744                                              HandleObject replacer,
   3745                                              HandleValue space,
   3746                                              JSONWriteCallback callback,
   3747                                              void* data, size_t lengthHint) {
   3748  AssertHeapIsIdle();
   3749  CHECK_THREAD(cx);
   3750  cx->check(replacer, space);
   3751  StringBuilder sb(cx);
   3752  if (!sb.ensureTwoByteChars()) {
   3753    return false;
   3754  }
   3755  if (lengthHint && !sb.reserve(lengthHint)) {
   3756    return false;
   3757  }
   3758  if (!Stringify(cx, vp, replacer, space, sb, StringifyBehavior::Normal)) {
   3759    return false;
   3760  }
   3761  if (sb.empty() && !sb.append(cx->names().null)) {
   3762    return false;
   3763  }
   3764  return callback(sb.rawTwoByteBegin(), sb.length(), data);
   3765 }
   3766 
   3767 JS_PUBLIC_API bool JS::ToJSON(JSContext* cx, HandleValue value,
   3768                              HandleObject replacer, HandleValue space,
   3769                              JSONWriteCallback callback, void* data) {
   3770  AssertHeapIsIdle();
   3771  CHECK_THREAD(cx);
   3772  cx->check(replacer, space);
   3773  StringBuilder sb(cx);
   3774  if (!sb.ensureTwoByteChars()) {
   3775    return false;
   3776  }
   3777  RootedValue v(cx, value);
   3778  if (!Stringify(cx, &v, replacer, space, sb, StringifyBehavior::Normal)) {
   3779    return false;
   3780  }
   3781  if (sb.empty()) {
   3782    return true;
   3783  }
   3784  return callback(sb.rawTwoByteBegin(), sb.length(), data);
   3785 }
   3786 
   3787 JS_PUBLIC_API bool JS::ToJSONMaybeSafely(JSContext* cx, JS::HandleObject input,
   3788                                         JSONWriteCallback callback,
   3789                                         void* data) {
   3790  AssertHeapIsIdle();
   3791  CHECK_THREAD(cx);
   3792  cx->check(input);
   3793 
   3794  StringBuilder sb(cx);
   3795  if (!sb.ensureTwoByteChars()) {
   3796    return false;
   3797  }
   3798 
   3799  RootedValue inputValue(cx, ObjectValue(*input));
   3800  if (!Stringify(cx, &inputValue, nullptr, NullHandleValue, sb,
   3801                 StringifyBehavior::RestrictedSafe))
   3802    return false;
   3803 
   3804  if (sb.empty() && !sb.append(cx->names().null)) {
   3805    return false;
   3806  }
   3807 
   3808  return callback(sb.rawTwoByteBegin(), sb.length(), data);
   3809 }
   3810 
   3811 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, const char16_t* chars,
   3812                                uint32_t len, MutableHandleValue vp) {
   3813  AssertHeapIsIdle();
   3814  CHECK_THREAD(cx);
   3815  return ParseJSONWithReviver(cx, mozilla::Range<const char16_t>(chars, len),
   3816                              NullHandleValue, vp);
   3817 }
   3818 
   3819 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, HandleString str,
   3820                                MutableHandleValue vp) {
   3821  return JS_ParseJSONWithReviver(cx, str, NullHandleValue, vp);
   3822 }
   3823 
   3824 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, const Latin1Char* chars,
   3825                                uint32_t len, MutableHandleValue vp) {
   3826  AssertHeapIsIdle();
   3827  CHECK_THREAD(cx);
   3828  return ParseJSONWithReviver(cx, mozilla::Range<const Latin1Char>(chars, len),
   3829                              NullHandleValue, vp);
   3830 }
   3831 
   3832 JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, const char16_t* chars,
   3833                                           uint32_t len, HandleValue reviver,
   3834                                           MutableHandleValue vp) {
   3835  AssertHeapIsIdle();
   3836  CHECK_THREAD(cx);
   3837  return ParseJSONWithReviver(cx, mozilla::Range<const char16_t>(chars, len),
   3838                              reviver, vp);
   3839 }
   3840 
   3841 JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, HandleString str,
   3842                                           HandleValue reviver,
   3843                                           MutableHandleValue vp) {
   3844  AssertHeapIsIdle();
   3845  CHECK_THREAD(cx);
   3846  cx->check(str);
   3847 
   3848  AutoStableStringChars stableChars(cx);
   3849  if (!stableChars.init(cx, str)) {
   3850    return false;
   3851  }
   3852 
   3853  return stableChars.isLatin1()
   3854             ? ParseJSONWithReviver(cx, stableChars.latin1Range(), reviver, vp)
   3855             : ParseJSONWithReviver(cx, stableChars.twoByteRange(), reviver,
   3856                                    vp);
   3857 }
   3858 
   3859 /************************************************************************/
   3860 
   3861 JS_PUBLIC_API void JS_ReportErrorASCII(JSContext* cx, const char* format, ...) {
   3862  va_list ap;
   3863 
   3864  AssertHeapIsIdle();
   3865  va_start(ap, format);
   3866  ReportErrorVA(cx, IsWarning::No, format, ArgumentsAreASCII, ap);
   3867  va_end(ap);
   3868 }
   3869 
   3870 JS_PUBLIC_API void JS_ReportErrorLatin1(JSContext* cx, const char* format,
   3871                                        ...) {
   3872  va_list ap;
   3873 
   3874  AssertHeapIsIdle();
   3875  va_start(ap, format);
   3876  ReportErrorVA(cx, IsWarning::No, format, ArgumentsAreLatin1, ap);
   3877  va_end(ap);
   3878 }
   3879 
   3880 JS_PUBLIC_API void JS_ReportErrorUTF8(JSContext* cx, const char* format, ...) {
   3881  va_list ap;
   3882 
   3883  AssertHeapIsIdle();
   3884  va_start(ap, format);
   3885  ReportErrorVA(cx, IsWarning::No, format, ArgumentsAreUTF8, ap);
   3886  va_end(ap);
   3887 }
   3888 
   3889 JS_PUBLIC_API void JS_ReportErrorNumberASCII(JSContext* cx,
   3890                                             JSErrorCallback errorCallback,
   3891                                             void* userRef,
   3892                                             const unsigned errorNumber, ...) {
   3893  va_list ap;
   3894  va_start(ap, errorNumber);
   3895  JS_ReportErrorNumberASCIIVA(cx, errorCallback, userRef, errorNumber, ap);
   3896  va_end(ap);
   3897 }
   3898 
   3899 JS_PUBLIC_API void JS_ReportErrorNumberASCIIVA(JSContext* cx,
   3900                                               JSErrorCallback errorCallback,
   3901                                               void* userRef,
   3902                                               const unsigned errorNumber,
   3903                                               va_list ap) {
   3904  AssertHeapIsIdle();
   3905  ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber,
   3906                      ArgumentsAreASCII, ap);
   3907 }
   3908 
   3909 JS_PUBLIC_API void JS_ReportErrorNumberLatin1(JSContext* cx,
   3910                                              JSErrorCallback errorCallback,
   3911                                              void* userRef,
   3912                                              const unsigned errorNumber, ...) {
   3913  va_list ap;
   3914  va_start(ap, errorNumber);
   3915  JS_ReportErrorNumberLatin1VA(cx, errorCallback, userRef, errorNumber, ap);
   3916  va_end(ap);
   3917 }
   3918 
   3919 JS_PUBLIC_API void JS_ReportErrorNumberLatin1VA(JSContext* cx,
   3920                                                JSErrorCallback errorCallback,
   3921                                                void* userRef,
   3922                                                const unsigned errorNumber,
   3923                                                va_list ap) {
   3924  AssertHeapIsIdle();
   3925  ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber,
   3926                      ArgumentsAreLatin1, ap);
   3927 }
   3928 
   3929 JS_PUBLIC_API void JS_ReportErrorNumberUTF8(JSContext* cx,
   3930                                            JSErrorCallback errorCallback,
   3931                                            void* userRef,
   3932                                            const unsigned errorNumber, ...) {
   3933  va_list ap;
   3934  va_start(ap, errorNumber);
   3935  JS_ReportErrorNumberUTF8VA(cx, errorCallback, userRef, errorNumber, ap);
   3936  va_end(ap);
   3937 }
   3938 
   3939 JS_PUBLIC_API void JS_ReportErrorNumberUTF8VA(JSContext* cx,
   3940                                              JSErrorCallback errorCallback,
   3941                                              void* userRef,
   3942                                              const unsigned errorNumber,
   3943                                              va_list ap) {
   3944  AssertHeapIsIdle();
   3945  ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber,
   3946                      ArgumentsAreUTF8, ap);
   3947 }
   3948 
   3949 JS_PUBLIC_API void JS_ReportErrorNumberUTF8Array(JSContext* cx,
   3950                                                 JSErrorCallback errorCallback,
   3951                                                 void* userRef,
   3952                                                 const unsigned errorNumber,
   3953                                                 const char** args) {
   3954  AssertHeapIsIdle();
   3955  ReportErrorNumberUTF8Array(cx, IsWarning::No, errorCallback, userRef,
   3956                             errorNumber, args);
   3957 }
   3958 
   3959 JS_PUBLIC_API void JS_ReportErrorNumberUC(JSContext* cx,
   3960                                          JSErrorCallback errorCallback,
   3961                                          void* userRef,
   3962                                          const unsigned errorNumber, ...) {
   3963  va_list ap;
   3964 
   3965  AssertHeapIsIdle();
   3966  va_start(ap, errorNumber);
   3967  ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber,
   3968                      ArgumentsAreUnicode, ap);
   3969  va_end(ap);
   3970 }
   3971 
   3972 JS_PUBLIC_API void JS_ReportErrorNumberUCArray(JSContext* cx,
   3973                                               JSErrorCallback errorCallback,
   3974                                               void* userRef,
   3975                                               const unsigned errorNumber,
   3976                                               const char16_t** args) {
   3977  AssertHeapIsIdle();
   3978  ReportErrorNumberUCArray(cx, IsWarning::No, errorCallback, userRef,
   3979                           errorNumber, args);
   3980 }
   3981 
   3982 JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx) {
   3983  ReportOutOfMemory(cx);
   3984 }
   3985 
   3986 JS_PUBLIC_API void JS_ReportAllocationOverflow(JSContext* cx) {
   3987  ReportAllocationOverflow(cx);
   3988 }
   3989 
   3990 JS_PUBLIC_API void JS::ReportUncatchableException(JSContext* cx) {
   3991  cx->reportUncatchableException();
   3992 }
   3993 
   3994 JS_PUBLIC_API bool JS_ExpandErrorArgumentsASCII(JSContext* cx,
   3995                                                JSErrorCallback errorCallback,
   3996                                                const unsigned errorNumber,
   3997                                                JSErrorReport* reportp, ...) {
   3998  va_list ap;
   3999  bool ok;
   4000 
   4001  AssertHeapIsIdle();
   4002  va_start(ap, reportp);
   4003  AutoReportFrontendContext fc(cx);
   4004  ok = ExpandErrorArgumentsVA(&fc, errorCallback, nullptr, errorNumber,
   4005                              ArgumentsAreASCII, reportp, ap);
   4006  va_end(ap);
   4007  return ok;
   4008 }
   4009 /************************************************************************/
   4010 
   4011 JS_PUBLIC_API bool JS_SetDefaultLocale(JSRuntime* rt, const char* locale) {
   4012  AssertHeapIsIdle();
   4013  return rt->setDefaultLocale(locale);
   4014 }
   4015 
   4016 JS_PUBLIC_API UniqueChars JS_GetDefaultLocale(JSContext* cx) {
   4017  AssertHeapIsIdle();
   4018  if (const char* locale = cx->runtime()->getDefaultLocale()) {
   4019    return DuplicateString(cx, locale);
   4020  }
   4021 
   4022  return nullptr;
   4023 }
   4024 
   4025 JS_PUBLIC_API void JS_ResetDefaultLocale(JSRuntime* rt) {
   4026  AssertHeapIsIdle();
   4027  rt->resetDefaultLocale();
   4028 }
   4029 
   4030 JS_PUBLIC_API void JS_SetLocaleCallbacks(JSRuntime* rt,
   4031                                         const JSLocaleCallbacks* callbacks) {
   4032  AssertHeapIsIdle();
   4033  rt->localeCallbacks = callbacks;
   4034 }
   4035 
   4036 JS_PUBLIC_API const JSLocaleCallbacks* JS_GetLocaleCallbacks(JSRuntime* rt) {
   4037  /* This function can be called by a finalizer. */
   4038  return rt->localeCallbacks;
   4039 }
   4040 
   4041 /************************************************************************/
   4042 
   4043 JS_PUBLIC_API bool JS_IsExceptionPending(JSContext* cx) {
   4044  /* This function can be called by a finalizer. */
   4045  return (bool)cx->isExceptionPending();
   4046 }
   4047 
   4048 JS_PUBLIC_API bool JS_IsThrowingOutOfMemory(JSContext* cx) {
   4049  return cx->isThrowingOutOfMemory();
   4050 }
   4051 
   4052 JS_PUBLIC_API bool JS_GetPendingException(JSContext* cx,
   4053                                          MutableHandleValue vp) {
   4054  AssertHeapIsIdle();
   4055  CHECK_THREAD(cx);
   4056  if (!cx->isExceptionPending()) {
   4057    return false;
   4058  }
   4059  return cx->getPendingException(vp);
   4060 }
   4061 
   4062 JS_PUBLIC_API void JS_SetPendingException(JSContext* cx, HandleValue value,
   4063                                          JS::ExceptionStackBehavior behavior) {
   4064  AssertHeapIsIdle();
   4065  CHECK_THREAD(cx);
   4066  // We don't check the compartment of `value` here, because we're not
   4067  // doing anything with it other than storing it, and stored
   4068  // exception values can be in an abitrary compartment.
   4069 
   4070  if (behavior == JS::ExceptionStackBehavior::Capture) {
   4071    cx->setPendingException(value, ShouldCaptureStack::Always);
   4072  } else {
   4073    cx->setPendingException(value, nullptr);
   4074  }
   4075 }
   4076 
   4077 JS_PUBLIC_API void JS_ClearPendingException(JSContext* cx) {
   4078  AssertHeapIsIdle();
   4079  cx->clearPendingException();
   4080 }
   4081 
   4082 JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext* cx)
   4083    : context(cx), status(cx->status), exceptionValue(cx), exceptionStack(cx) {
   4084  AssertHeapIsIdle();
   4085  CHECK_THREAD(cx);
   4086  if (IsCatchableExceptionStatus(status)) {
   4087    exceptionValue = cx->unwrappedException();
   4088    exceptionStack = cx->unwrappedExceptionStack();
   4089  }
   4090  cx->clearPendingException();
   4091 }
   4092 
   4093 void JS::AutoSaveExceptionState::drop() {
   4094  status = JS::ExceptionStatus::None;
   4095  exceptionValue.setUndefined();
   4096  exceptionStack = nullptr;
   4097 }
   4098 
   4099 void JS::AutoSaveExceptionState::restore() {
   4100  context->status = status;
   4101  context->unwrappedException() = exceptionValue;
   4102  if (exceptionStack) {
   4103    context->unwrappedExceptionStack() = &exceptionStack->as<SavedFrame>();
   4104  }
   4105  drop();
   4106 }
   4107 
   4108 JS::AutoSaveExceptionState::~AutoSaveExceptionState() {
   4109  // NOTE: An interrupt/uncatchable exception or a debugger-forced-return may be
   4110  //       clobbered here by the saved exception. If that is not desired, this
   4111  //       state should be dropped before the destructor fires.
   4112  if (!context->isExceptionPending()) {
   4113    if (status != JS::ExceptionStatus::None) {
   4114      context->status = status;
   4115    }
   4116    if (IsCatchableExceptionStatus(status)) {
   4117      context->unwrappedException() = exceptionValue;
   4118      if (exceptionStack) {
   4119        context->unwrappedExceptionStack() = &exceptionStack->as<SavedFrame>();
   4120      }
   4121    }
   4122  }
   4123 }
   4124 
   4125 JS_PUBLIC_API JSErrorReport* JS_ErrorFromException(JSContext* cx,
   4126                                                   HandleObject obj) {
   4127  AssertHeapIsIdle();
   4128  CHECK_THREAD(cx);
   4129  cx->check(obj);
   4130  return ErrorFromException(cx, obj);
   4131 }
   4132 
   4133 void JSErrorReport::initBorrowedLinebuf(const char16_t* linebufArg,
   4134                                        size_t linebufLengthArg,
   4135                                        size_t tokenOffsetArg) {
   4136  MOZ_ASSERT(linebufArg);
   4137  MOZ_ASSERT(tokenOffsetArg <= linebufLengthArg);
   4138  MOZ_ASSERT(linebufArg[linebufLengthArg] == '\0');
   4139 
   4140  linebuf_ = linebufArg;
   4141  linebufLength_ = linebufLengthArg;
   4142  tokenOffset_ = tokenOffsetArg;
   4143 }
   4144 
   4145 void JSErrorReport::freeLinebuf() {
   4146  if (ownsLinebuf_ && linebuf_) {
   4147    js_free((void*)linebuf_);
   4148    ownsLinebuf_ = false;
   4149  }
   4150  linebuf_ = nullptr;
   4151 }
   4152 
   4153 JSString* JSErrorBase::newMessageString(JSContext* cx) {
   4154  if (!message_) {
   4155    return cx->runtime()->emptyString;
   4156  }
   4157 
   4158  return JS_NewStringCopyUTF8Z(cx, message_);
   4159 }
   4160 
   4161 void JSErrorBase::freeMessage() {
   4162  if (ownsMessage_) {
   4163    js_free((void*)message_.get());
   4164    ownsMessage_ = false;
   4165  }
   4166  message_ = JS::ConstUTF8CharsZ();
   4167 }
   4168 
   4169 JSErrorNotes::JSErrorNotes() = default;
   4170 
   4171 JSErrorNotes::~JSErrorNotes() = default;
   4172 
   4173 static UniquePtr<JSErrorNotes::Note> CreateErrorNoteVA(
   4174    FrontendContext* fc, const char* filename, unsigned sourceId,
   4175    uint32_t lineno, JS::ColumnNumberOneOrigin column,
   4176    JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber,
   4177    ErrorArgumentsType argumentsType, va_list ap) {
   4178  auto note = MakeUnique<JSErrorNotes::Note>();
   4179  if (!note) {
   4180    ReportOutOfMemory(fc);
   4181    return nullptr;
   4182  }
   4183 
   4184  note->errorNumber = errorNumber;
   4185  note->filename = JS::ConstUTF8CharsZ(filename);
   4186  note->sourceId = sourceId;
   4187  note->lineno = lineno;
   4188  note->column = column;
   4189 
   4190  if (!ExpandErrorArgumentsVA(fc, errorCallback, userRef, errorNumber, nullptr,
   4191                              argumentsType, note.get(), ap)) {
   4192    return nullptr;
   4193  }
   4194 
   4195  return note;
   4196 }
   4197 
   4198 bool JSErrorNotes::addNoteVA(FrontendContext* fc, const char* filename,
   4199                             unsigned sourceId, uint32_t lineno,
   4200                             JS::ColumnNumberOneOrigin column,
   4201                             JSErrorCallback errorCallback, void* userRef,
   4202                             const unsigned errorNumber,
   4203                             ErrorArgumentsType argumentsType, va_list ap) {
   4204  auto note =
   4205      CreateErrorNoteVA(fc, filename, sourceId, lineno, column, errorCallback,
   4206                        userRef, errorNumber, argumentsType, ap);
   4207 
   4208  if (!note) {
   4209    return false;
   4210  }
   4211  if (!notes_.append(std::move(note))) {
   4212    ReportOutOfMemory(fc);
   4213    return false;
   4214  }
   4215  return true;
   4216 }
   4217 
   4218 bool JSErrorNotes::addNoteASCII(JSContext* cx, const char* filename,
   4219                                unsigned sourceId, uint32_t lineno,
   4220                                JS::ColumnNumberOneOrigin column,
   4221                                JSErrorCallback errorCallback, void* userRef,
   4222                                const unsigned errorNumber, ...) {
   4223  AutoReportFrontendContext fc(cx);
   4224  va_list ap;
   4225  va_start(ap, errorNumber);
   4226  bool ok = addNoteVA(&fc, filename, sourceId, lineno, column, errorCallback,
   4227                      userRef, errorNumber, ArgumentsAreASCII, ap);
   4228  va_end(ap);
   4229  return ok;
   4230 }
   4231 
   4232 bool JSErrorNotes::addNoteASCII(FrontendContext* fc, const char* filename,
   4233                                unsigned sourceId, uint32_t lineno,
   4234                                JS::ColumnNumberOneOrigin column,
   4235                                JSErrorCallback errorCallback, void* userRef,
   4236                                const unsigned errorNumber, ...) {
   4237  va_list ap;
   4238  va_start(ap, errorNumber);
   4239  bool ok = addNoteVA(fc, filename, sourceId, lineno, column, errorCallback,
   4240                      userRef, errorNumber, ArgumentsAreASCII, ap);
   4241  va_end(ap);
   4242  return ok;
   4243 }
   4244 
   4245 bool JSErrorNotes::addNoteLatin1(JSContext* cx, const char* filename,
   4246                                 unsigned sourceId, uint32_t lineno,
   4247                                 JS::ColumnNumberOneOrigin column,
   4248                                 JSErrorCallback errorCallback, void* userRef,
   4249                                 const unsigned errorNumber, ...) {
   4250  AutoReportFrontendContext fc(cx);
   4251  va_list ap;
   4252  va_start(ap, errorNumber);
   4253  bool ok = addNoteVA(&fc, filename, sourceId, lineno, column, errorCallback,
   4254                      userRef, errorNumber, ArgumentsAreLatin1, ap);
   4255  va_end(ap);
   4256  return ok;
   4257 }
   4258 
   4259 bool JSErrorNotes::addNoteLatin1(FrontendContext* fc, const char* filename,
   4260                                 unsigned sourceId, uint32_t lineno,
   4261                                 JS::ColumnNumberOneOrigin column,
   4262                                 JSErrorCallback errorCallback, void* userRef,
   4263                                 const unsigned errorNumber, ...) {
   4264  va_list ap;
   4265  va_start(ap, errorNumber);
   4266  bool ok = addNoteVA(fc, filename, sourceId, lineno, column, errorCallback,
   4267                      userRef, errorNumber, ArgumentsAreLatin1, ap);
   4268  va_end(ap);
   4269  return ok;
   4270 }
   4271 
   4272 bool JSErrorNotes::addNoteUTF8(JSContext* cx, const char* filename,
   4273                               unsigned sourceId, uint32_t lineno,
   4274                               JS::ColumnNumberOneOrigin column,
   4275                               JSErrorCallback errorCallback, void* userRef,
   4276                               const unsigned errorNumber, ...) {
   4277  AutoReportFrontendContext fc(cx);
   4278  va_list ap;
   4279  va_start(ap, errorNumber);
   4280  bool ok = addNoteVA(&fc, filename, sourceId, lineno, column, errorCallback,
   4281                      userRef, errorNumber, ArgumentsAreUTF8, ap);
   4282  va_end(ap);
   4283  return ok;
   4284 }
   4285 
   4286 bool JSErrorNotes::addNoteUTF8(FrontendContext* fc, const char* filename,
   4287                               unsigned sourceId, uint32_t lineno,
   4288                               JS::ColumnNumberOneOrigin column,
   4289                               JSErrorCallback errorCallback, void* userRef,
   4290                               const unsigned errorNumber, ...) {
   4291  va_list ap;
   4292  va_start(ap, errorNumber);
   4293  bool ok = addNoteVA(fc, filename, sourceId, lineno, column, errorCallback,
   4294                      userRef, errorNumber, ArgumentsAreUTF8, ap);
   4295  va_end(ap);
   4296  return ok;
   4297 }
   4298 
   4299 JS_PUBLIC_API size_t JSErrorNotes::length() { return notes_.length(); }
   4300 
   4301 UniquePtr<JSErrorNotes> JSErrorNotes::copy(JSContext* cx) {
   4302  auto copiedNotes = MakeUnique<JSErrorNotes>();
   4303  if (!copiedNotes) {
   4304    ReportOutOfMemory(cx);
   4305    return nullptr;
   4306  }
   4307 
   4308  for (auto&& note : *this) {
   4309    UniquePtr<JSErrorNotes::Note> copied = CopyErrorNote(cx, note.get());
   4310    if (!copied) {
   4311      return nullptr;
   4312    }
   4313 
   4314    if (!copiedNotes->notes_.append(std::move(copied))) {
   4315      return nullptr;
   4316    }
   4317  }
   4318 
   4319  return copiedNotes;
   4320 }
   4321 
   4322 JS_PUBLIC_API JSErrorNotes::iterator JSErrorNotes::begin() {
   4323  return iterator(notes_.begin());
   4324 }
   4325 
   4326 JS_PUBLIC_API JSErrorNotes::iterator JSErrorNotes::end() {
   4327  return iterator(notes_.end());
   4328 }
   4329 
   4330 extern MOZ_NEVER_INLINE JS_PUBLIC_API void JS_AbortIfWrongThread(
   4331    JSContext* cx) {
   4332  if (!CurrentThreadCanAccessRuntime(cx->runtime())) {
   4333    MOZ_CRASH();
   4334  }
   4335  if (TlsContext.get() != cx) {
   4336    MOZ_CRASH();
   4337  }
   4338 }
   4339 
   4340 JS_PUBLIC_API void JS_SetOffthreadBaselineCompilationEnabled(JSContext* cx,
   4341                                                             bool enabled) {
   4342  cx->runtime()->setOffthreadBaselineCompilationEnabled(enabled);
   4343 }
   4344 
   4345 JS_PUBLIC_API void JS_SetOffthreadIonCompilationEnabled(JSContext* cx,
   4346                                                        bool enabled) {
   4347  cx->runtime()->setOffthreadIonCompilationEnabled(enabled);
   4348 }
   4349 
   4350 JS_PUBLIC_API void JS_SetGlobalJitCompilerOption(JSContext* cx,
   4351                                                 JSJitCompilerOption opt,
   4352                                                 uint32_t value) {
   4353  JSRuntime* rt = cx->runtime();
   4354  switch (opt) {
   4355 #ifdef ENABLE_PORTABLE_BASELINE_INTERP
   4356    case JSJITCOMPILER_PORTABLE_BASELINE_ENABLE:
   4357      if (value == 1) {
   4358        jit::JitOptions.portableBaselineInterpreter = true;
   4359      } else if (value == 0) {
   4360        jit::JitOptions.portableBaselineInterpreter = false;
   4361      }
   4362      break;
   4363    case JSJITCOMPILER_PORTABLE_BASELINE_WARMUP_THRESHOLD:
   4364      if (value == uint32_t(-1)) {
   4365        jit::DefaultJitOptions defaultValues;
   4366        value = defaultValues.portableBaselineInterpreterWarmUpThreshold;
   4367      }
   4368      jit::JitOptions.portableBaselineInterpreterWarmUpThreshold = value;
   4369      break;
   4370 #endif
   4371    case JSJITCOMPILER_BASELINE_INTERPRETER_WARMUP_TRIGGER:
   4372      if (value == uint32_t(-1)) {
   4373        jit::DefaultJitOptions defaultValues;
   4374        value = defaultValues.baselineInterpreterWarmUpThreshold;
   4375      }
   4376      jit::JitOptions.baselineInterpreterWarmUpThreshold = value;
   4377      break;
   4378    case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER:
   4379      if (value == uint32_t(-1)) {
   4380        jit::DefaultJitOptions defaultValues;
   4381        value = defaultValues.baselineJitWarmUpThreshold;
   4382      }
   4383      jit::JitOptions.baselineJitWarmUpThreshold = value;
   4384      break;
   4385    case JSJITCOMPILER_IC_FORCE_MEGAMORPHIC:
   4386      jit::JitOptions.forceMegamorphicICs = !!value;
   4387      break;
   4388    case JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER:
   4389      if (value == uint32_t(-1)) {
   4390        jit::JitOptions.resetNormalIonWarmUpThreshold();
   4391        break;
   4392      }
   4393      jit::JitOptions.setNormalIonWarmUpThreshold(value);
   4394      break;
   4395    case JSJITCOMPILER_ION_GVN_ENABLE:
   4396      if (value == 0) {
   4397        jit::JitOptions.enableGvn(false);
   4398        JitSpew(js::jit::JitSpew_IonScripts, "Disable ion's GVN");
   4399      } else {
   4400        jit::JitOptions.enableGvn(true);
   4401        JitSpew(js::jit::JitSpew_IonScripts, "Enable ion's GVN");
   4402      }
   4403      break;
   4404    case JSJITCOMPILER_ION_FORCE_IC:
   4405      if (value == 0) {
   4406        jit::JitOptions.forceInlineCaches = false;
   4407        JitSpew(js::jit::JitSpew_IonScripts,
   4408                "Ion: Enable non-IC optimizations.");
   4409      } else {
   4410        jit::JitOptions.forceInlineCaches = true;
   4411        JitSpew(js::jit::JitSpew_IonScripts,
   4412                "Ion: Disable non-IC optimizations.");
   4413      }
   4414      break;
   4415    case JSJITCOMPILER_ION_CHECK_RANGE_ANALYSIS:
   4416      if (value == 0) {
   4417        jit::JitOptions.checkRangeAnalysis = false;
   4418        JitSpew(js::jit::JitSpew_IonScripts,
   4419                "Ion: Enable range analysis checks.");
   4420      } else {
   4421        jit::JitOptions.checkRangeAnalysis = true;
   4422        JitSpew(js::jit::JitSpew_IonScripts,
   4423                "Ion: Disable range analysis checks.");
   4424      }
   4425      break;
   4426    case JSJITCOMPILER_ION_ENABLE:
   4427      if (value == 1) {
   4428        jit::JitOptions.ion = true;
   4429        JitSpew(js::jit::JitSpew_IonScripts, "Enable ion");
   4430      } else if (value == 0) {
   4431        jit::JitOptions.ion = false;
   4432        JitSpew(js::jit::JitSpew_IonScripts, "Disable ion");
   4433      }
   4434      break;
   4435    case JSJITCOMPILER_JIT_TRUSTEDPRINCIPALS_ENABLE:
   4436      if (value == 1) {
   4437        jit::JitOptions.jitForTrustedPrincipals = true;
   4438        JitSpew(js::jit::JitSpew_IonScripts,
   4439                "Enable ion and baselinejit for trusted principals");
   4440      } else if (value == 0) {
   4441        jit::JitOptions.jitForTrustedPrincipals = false;
   4442        JitSpew(js::jit::JitSpew_IonScripts,
   4443                "Disable ion and baselinejit for trusted principals");
   4444      }
   4445      break;
   4446    case JSJITCOMPILER_ION_FREQUENT_BAILOUT_THRESHOLD:
   4447      if (value == uint32_t(-1)) {
   4448        jit::DefaultJitOptions defaultValues;
   4449        value = defaultValues.frequentBailoutThreshold;
   4450      }
   4451      jit::JitOptions.frequentBailoutThreshold = value;
   4452      break;
   4453    case JSJITCOMPILER_BASE_REG_FOR_LOCALS: {
   4454 #ifdef JS_CODEGEN_ARM64
   4455      bool canUseBaseRegForLocals = !fuzzingSafe;
   4456 #else
   4457      bool canUseBaseRegForLocals = true;
   4458 #endif
   4459      if (canUseBaseRegForLocals) {
   4460        if (value == 0) {
   4461          jit::JitOptions.baseRegForLocals = jit::BaseRegForAddress::SP;
   4462        } else if (value == 1) {
   4463          jit::JitOptions.baseRegForLocals = jit::BaseRegForAddress::FP;
   4464        } else {
   4465          jit::DefaultJitOptions defaultValues;
   4466          jit::JitOptions.baseRegForLocals = defaultValues.baseRegForLocals;
   4467        }
   4468      } else {
   4469        JitSpew(js::jit::JitSpew_BaselineScripts,
   4470                "base-reg-for-locals is always SP.");
   4471      }
   4472      break;
   4473    }
   4474    case JSJITCOMPILER_BASELINE_INTERPRETER_ENABLE:
   4475      if (value == 1) {
   4476        jit::JitOptions.baselineInterpreter = true;
   4477      } else if (value == 0) {
   4478        ReleaseAllJITCode(rt->gcContext());
   4479        jit::JitOptions.baselineInterpreter = false;
   4480      }
   4481      break;
   4482    case JSJITCOMPILER_BASELINE_ENABLE:
   4483      if (value == 1) {
   4484        jit::JitOptions.baselineJit = true;
   4485        ReleaseAllJITCode(rt->gcContext());
   4486        JitSpew(js::jit::JitSpew_BaselineScripts, "Enable baseline");
   4487      } else if (value == 0) {
   4488        jit::JitOptions.baselineJit = false;
   4489        ReleaseAllJITCode(rt->gcContext());
   4490        JitSpew(js::jit::JitSpew_BaselineScripts, "Disable baseline");
   4491      }
   4492      break;
   4493    case JSJITCOMPILER_NATIVE_REGEXP_ENABLE:
   4494      jit::JitOptions.nativeRegExp = !!value;
   4495      break;
   4496    case JSJITCOMPILER_JIT_HINTS_ENABLE:
   4497      jit::JitOptions.disableJitHints = !value;
   4498      break;
   4499    case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE:
   4500      if (value == 1) {
   4501        rt->setOffthreadCompilationEnabled(true);
   4502        JitSpew(js::jit::JitSpew_IonScripts, "Enable offthread compilation");
   4503      } else if (value == 0) {
   4504        rt->setOffthreadCompilationEnabled(false);
   4505        JitSpew(js::jit::JitSpew_IonScripts, "Disable offthread compilation");
   4506      }
   4507      break;
   4508    case JSJITCOMPILER_INLINING_BYTECODE_MAX_LENGTH:
   4509      if (value == uint32_t(-1)) {
   4510        jit::DefaultJitOptions defaultValues;
   4511        value = defaultValues.smallFunctionMaxBytecodeLength;
   4512      }
   4513      jit::JitOptions.smallFunctionMaxBytecodeLength = value;
   4514      break;
   4515    case JSJITCOMPILER_JUMP_THRESHOLD:
   4516      if (value == uint32_t(-1)) {
   4517        jit::DefaultJitOptions defaultValues;
   4518        value = defaultValues.jumpThreshold;
   4519      }
   4520      jit::JitOptions.jumpThreshold = value;
   4521      break;
   4522    case JSJITCOMPILER_SPECTRE_INDEX_MASKING:
   4523      jit::JitOptions.spectreIndexMasking = !!value;
   4524      break;
   4525    case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS:
   4526      jit::JitOptions.spectreObjectMitigations = !!value;
   4527      break;
   4528    case JSJITCOMPILER_SPECTRE_STRING_MITIGATIONS:
   4529      jit::JitOptions.spectreStringMitigations = !!value;
   4530      break;
   4531    case JSJITCOMPILER_SPECTRE_VALUE_MASKING:
   4532      jit::JitOptions.spectreValueMasking = !!value;
   4533      break;
   4534    case JSJITCOMPILER_SPECTRE_JIT_TO_CXX_CALLS:
   4535      jit::JitOptions.spectreJitToCxxCalls = !!value;
   4536      break;
   4537    case JSJITCOMPILER_WRITE_PROTECT_CODE:
   4538      jit::JitOptions.maybeSetWriteProtectCode(!!value);
   4539      break;
   4540    case JSJITCOMPILER_WASM_FOLD_OFFSETS:
   4541      jit::JitOptions.wasmFoldOffsets = !!value;
   4542      break;
   4543    case JSJITCOMPILER_WASM_DELAY_TIER2:
   4544      jit::JitOptions.wasmDelayTier2 = !!value;
   4545      break;
   4546    case JSJITCOMPILER_WASM_JIT_BASELINE:
   4547      JS::ContextOptionsRef(cx).setWasmBaseline(!!value);
   4548      break;
   4549    case JSJITCOMPILER_WASM_JIT_OPTIMIZING:
   4550      JS::ContextOptionsRef(cx).setWasmIon(!!value);
   4551      break;
   4552 #ifdef DEBUG
   4553    case JSJITCOMPILER_FULL_DEBUG_CHECKS:
   4554      jit::JitOptions.fullDebugChecks = !!value;
   4555      break;
   4556 #endif
   4557    default:
   4558      break;
   4559  }
   4560 }
   4561 
   4562 JS_PUBLIC_API bool JS_GetGlobalJitCompilerOption(JSContext* cx,
   4563                                                 JSJitCompilerOption opt,
   4564                                                 uint32_t* valueOut) {
   4565  MOZ_ASSERT(valueOut);
   4566 #ifndef JS_CODEGEN_NONE
   4567  JSRuntime* rt = cx->runtime();
   4568  switch (opt) {
   4569    case JSJITCOMPILER_BASELINE_INTERPRETER_WARMUP_TRIGGER:
   4570      *valueOut = jit::JitOptions.baselineInterpreterWarmUpThreshold;
   4571      break;
   4572    case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER:
   4573      *valueOut = jit::JitOptions.baselineJitWarmUpThreshold;
   4574      break;
   4575    case JSJITCOMPILER_IC_FORCE_MEGAMORPHIC:
   4576      *valueOut = jit::JitOptions.forceMegamorphicICs;
   4577      break;
   4578    case JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER:
   4579      *valueOut = jit::JitOptions.normalIonWarmUpThreshold;
   4580      break;
   4581    case JSJITCOMPILER_ION_FORCE_IC:
   4582      *valueOut = jit::JitOptions.forceInlineCaches;
   4583      break;
   4584    case JSJITCOMPILER_ION_CHECK_RANGE_ANALYSIS:
   4585      *valueOut = jit::JitOptions.checkRangeAnalysis;
   4586      break;
   4587    case JSJITCOMPILER_ION_ENABLE:
   4588      *valueOut = jit::JitOptions.ion;
   4589      break;
   4590    case JSJITCOMPILER_ION_FREQUENT_BAILOUT_THRESHOLD:
   4591      *valueOut = jit::JitOptions.frequentBailoutThreshold;
   4592      break;
   4593    case JSJITCOMPILER_BASE_REG_FOR_LOCALS:
   4594      *valueOut = uint32_t(jit::JitOptions.baseRegForLocals);
   4595      break;
   4596    case JSJITCOMPILER_INLINING_BYTECODE_MAX_LENGTH:
   4597      *valueOut = jit::JitOptions.smallFunctionMaxBytecodeLength;
   4598      break;
   4599    case JSJITCOMPILER_BASELINE_INTERPRETER_ENABLE:
   4600      *valueOut = jit::JitOptions.baselineInterpreter;
   4601      break;
   4602    case JSJITCOMPILER_BASELINE_ENABLE:
   4603      *valueOut = jit::JitOptions.baselineJit;
   4604      break;
   4605    case JSJITCOMPILER_NATIVE_REGEXP_ENABLE:
   4606      *valueOut = jit::JitOptions.nativeRegExp;
   4607      break;
   4608    case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE:
   4609      *valueOut = rt->canUseOffthreadIonCompilation();
   4610      break;
   4611    case JSJITCOMPILER_SPECTRE_INDEX_MASKING:
   4612      *valueOut = jit::JitOptions.spectreIndexMasking ? 1 : 0;
   4613      break;
   4614    case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS:
   4615      *valueOut = jit::JitOptions.spectreObjectMitigations ? 1 : 0;
   4616      break;
   4617    case JSJITCOMPILER_SPECTRE_STRING_MITIGATIONS:
   4618      *valueOut = jit::JitOptions.spectreStringMitigations ? 1 : 0;
   4619      break;
   4620    case JSJITCOMPILER_SPECTRE_VALUE_MASKING:
   4621      *valueOut = jit::JitOptions.spectreValueMasking ? 1 : 0;
   4622      break;
   4623    case JSJITCOMPILER_SPECTRE_JIT_TO_CXX_CALLS:
   4624      *valueOut = jit::JitOptions.spectreJitToCxxCalls ? 1 : 0;
   4625      break;
   4626    case JSJITCOMPILER_WRITE_PROTECT_CODE:
   4627      *valueOut = jit::JitOptions.writeProtectCode ? 1 : 0;
   4628      break;
   4629    case JSJITCOMPILER_WASM_FOLD_OFFSETS:
   4630      *valueOut = jit::JitOptions.wasmFoldOffsets ? 1 : 0;
   4631      break;
   4632    case JSJITCOMPILER_WASM_JIT_BASELINE:
   4633      *valueOut = JS::ContextOptionsRef(cx).wasmBaseline() ? 1 : 0;
   4634      break;
   4635    case JSJITCOMPILER_WASM_JIT_OPTIMIZING:
   4636      *valueOut = JS::ContextOptionsRef(cx).wasmIon() ? 1 : 0;
   4637      break;
   4638 #  ifdef DEBUG
   4639    case JSJITCOMPILER_FULL_DEBUG_CHECKS:
   4640      *valueOut = jit::JitOptions.fullDebugChecks ? 1 : 0;
   4641      break;
   4642 #  endif
   4643    default:
   4644      return false;
   4645  }
   4646 #else
   4647  switch (opt) {
   4648 #  ifdef ENABLE_PORTABLE_BASELINE_INTERP
   4649    case JSJITCOMPILER_PORTABLE_BASELINE_ENABLE:
   4650      *valueOut = jit::JitOptions.portableBaselineInterpreter;
   4651      break;
   4652    case JSJITCOMPILER_PORTABLE_BASELINE_WARMUP_THRESHOLD:
   4653      *valueOut = jit::JitOptions.portableBaselineInterpreterWarmUpThreshold;
   4654      break;
   4655 #  endif
   4656    default:
   4657      *valueOut = 0;
   4658  }
   4659 #endif
   4660  return true;
   4661 }
   4662 
   4663 JS_PUBLIC_API void JS::DisableSpectreMitigationsAfterInit() {
   4664  // This is used to turn off Spectre mitigations in pre-allocated child
   4665  // processes used for isolated web content. Assert there's a single runtime
   4666  // and cancel off-thread compilations, to ensure we're not racing with any
   4667  // compilations.
   4668  JSContext* cx = TlsContext.get();
   4669  MOZ_RELEASE_ASSERT(cx);
   4670  MOZ_RELEASE_ASSERT(JSRuntime::hasSingleLiveRuntime());
   4671  MOZ_RELEASE_ASSERT(cx->runtime()->wasmInstances.lock()->empty());
   4672 
   4673  CancelOffThreadIonCompile(cx->runtime());
   4674 
   4675  jit::JitOptions.spectreIndexMasking = false;
   4676  jit::JitOptions.spectreObjectMitigations = false;
   4677  jit::JitOptions.spectreStringMitigations = false;
   4678  jit::JitOptions.spectreValueMasking = false;
   4679  jit::JitOptions.spectreJitToCxxCalls = false;
   4680 }
   4681 
   4682 /************************************************************************/
   4683 
   4684 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && \
   4685    defined(XP_WIN) && (defined(MOZ_MEMORY) || !defined(JS_STANDALONE))
   4686 
   4687 #  include "util/WindowsWrapper.h"
   4688 
   4689 /*
   4690 * Initialization routine for the JS DLL.
   4691 */
   4692 BOOL WINAPI DllMain(HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) {
   4693  return TRUE;
   4694 }
   4695 
   4696 #endif
   4697 
   4698 JS_PUBLIC_API bool JS_IndexToId(JSContext* cx, uint32_t index,
   4699                                MutableHandleId id) {
   4700  return IndexToId(cx, index, id);
   4701 }
   4702 
   4703 JS_PUBLIC_API bool JS_CharsToId(JSContext* cx, JS::TwoByteChars chars,
   4704                                MutableHandleId idp) {
   4705  JSAtom* atom = AtomizeChars(cx, chars.begin().get(), chars.length());
   4706  if (!atom) {
   4707    return false;
   4708  }
   4709 #ifdef DEBUG
   4710  MOZ_ASSERT(!atom->isIndex(), "API misuse: |chars| must not encode an index");
   4711 #endif
   4712  idp.set(AtomToId(atom));
   4713  return true;
   4714 }
   4715 
   4716 JS_PUBLIC_API bool JS_IsIdentifier(JSContext* cx, HandleString str,
   4717                                   bool* isIdentifier) {
   4718  cx->check(str);
   4719 
   4720  JSLinearString* linearStr = str->ensureLinear(cx);
   4721  if (!linearStr) {
   4722    return false;
   4723  }
   4724 
   4725  *isIdentifier = IsIdentifier(linearStr);
   4726  return true;
   4727 }
   4728 
   4729 JS_PUBLIC_API bool JS_IsIdentifier(const char16_t* chars, size_t length) {
   4730  return IsIdentifier(chars, length);
   4731 }
   4732 
   4733 namespace JS {
   4734 
   4735 void AutoFilename::reset() {
   4736  if (ss_) {
   4737    ss_->Release();
   4738    ss_ = nullptr;
   4739  }
   4740  if (filename_.is<const char*>()) {
   4741    filename_.as<const char*>() = nullptr;
   4742  } else {
   4743    filename_.as<UniqueChars>().reset();
   4744  }
   4745 }
   4746 
   4747 void AutoFilename::setScriptSource(js::ScriptSource* p) {
   4748  MOZ_ASSERT(!ss_);
   4749  MOZ_ASSERT(!get());
   4750  ss_ = p;
   4751  if (p) {
   4752    p->AddRef();
   4753    setUnowned(p->filename());
   4754  }
   4755 }
   4756 
   4757 void AutoFilename::setUnowned(const char* filename) {
   4758  MOZ_ASSERT(!get());
   4759  filename_.as<const char*>() = filename ? filename : "";
   4760 }
   4761 
   4762 void AutoFilename::setOwned(UniqueChars&& filename) {
   4763  MOZ_ASSERT(!get());
   4764  filename_ = mozilla::AsVariant(std::move(filename));
   4765 }
   4766 
   4767 const char* AutoFilename::get() const {
   4768  if (filename_.is<const char*>()) {
   4769    return filename_.as<const char*>();
   4770  }
   4771  return filename_.as<UniqueChars>().get();
   4772 }
   4773 
   4774 JS_PUBLIC_API bool DescribeScriptedCaller(AutoFilename* filename, JSContext* cx,
   4775                                          uint32_t* lineno,
   4776                                          JS::ColumnNumberOneOrigin* column) {
   4777 #ifdef DEBUG
   4778  auto noThrow = mozilla::MakeScopeExit([=]() {
   4779    MOZ_ASSERT(!cx->isThrowingOutOfMemory() && !cx->isThrowingOverRecursed() &&
   4780               !cx->isExceptionPending());
   4781  });
   4782 #endif
   4783  if (filename) {
   4784    filename->reset();
   4785  }
   4786  if (lineno) {
   4787    *lineno = 0;
   4788  }
   4789  if (column) {
   4790    *column = JS::ColumnNumberOneOrigin();
   4791  }
   4792 
   4793  if (!cx->compartment()) {
   4794    return false;
   4795  }
   4796 
   4797  NonBuiltinFrameIter i(cx, cx->realm()->principals());
   4798  if (i.done()) {
   4799    return false;
   4800  }
   4801 
   4802  // If the caller is hidden, the embedding wants us to return false here so
   4803  // that it can check its own stack (see HideScriptedCaller).
   4804  if (i.activation()->scriptedCallerIsHidden()) {
   4805    return false;
   4806  }
   4807 
   4808  if (filename) {
   4809    if (i.isWasm()) {
   4810      // For Wasm, copy out the filename, there is no script source.
   4811      UniqueChars copy = DuplicateString(i.filename() ? i.filename() : "");
   4812      if (!copy) {
   4813        filename->setUnowned("out of memory");
   4814      } else {
   4815        filename->setOwned(std::move(copy));
   4816      }
   4817    } else {
   4818      // All other frames have a script source to read the filename from.
   4819      filename->setScriptSource(i.scriptSource());
   4820    }
   4821  }
   4822 
   4823  if (lineno) {
   4824    JS::TaggedColumnNumberOneOrigin columnNumber;
   4825    *lineno = i.computeLine(&columnNumber);
   4826    if (column) {
   4827      *column = JS::ColumnNumberOneOrigin(columnNumber.oneOriginValue());
   4828    }
   4829  } else if (column) {
   4830    JS::TaggedColumnNumberOneOrigin columnNumber;
   4831    i.computeLine(&columnNumber);
   4832    *column = JS::ColumnNumberOneOrigin(columnNumber.oneOriginValue());
   4833  }
   4834 
   4835  return true;
   4836 }
   4837 
   4838 // Fast path to get the activation and realm to use for GetScriptedCallerGlobal.
   4839 // If this returns false, the fast path didn't work out and the caller has to
   4840 // use the (much slower) NonBuiltinFrameIter path.
   4841 //
   4842 // The optimization here is that we skip Ion-inlined frames and only look at
   4843 // 'outer' frames. That's fine because Ion doesn't inline cross-realm calls.
   4844 // However, GetScriptedCallerGlobal has to skip self-hosted frames and Ion
   4845 // can inline self-hosted scripts, so we have to be careful:
   4846 //
   4847 // * When we see a non-self-hosted outer script, it's possible we inlined
   4848 //   self-hosted scripts into it but that doesn't matter because these scripts
   4849 //   all have the same realm/global anyway.
   4850 //
   4851 // * When we see a self-hosted outer script, it's possible we inlined
   4852 //   non-self-hosted scripts into it, so we have to give up because in this
   4853 //   case, whether or not to skip the self-hosted frame (to the possibly
   4854 //   different-realm caller) requires the slow path to handle inlining. Baseline
   4855 //   and the interpreter don't inline so this only affects Ion.
   4856 static bool GetScriptedCallerActivationRealmFast(JSContext* cx,
   4857                                                 Activation** activation,
   4858                                                 Realm** realm) {
   4859  ActivationIterator activationIter(cx);
   4860 
   4861  if (activationIter.done()) {
   4862    *activation = nullptr;
   4863    *realm = nullptr;
   4864    return true;
   4865  }
   4866 
   4867  if (activationIter->isJit()) {
   4868    jit::JitActivation* act = activationIter->asJit();
   4869    JitFrameIter iter(act);
   4870    while (true) {
   4871      iter.skipNonScriptedJSFrames();
   4872      if (iter.done()) {
   4873        break;
   4874      }
   4875 
   4876      if (!iter.isSelfHostedIgnoringInlining()) {
   4877        *activation = act;
   4878        *realm = iter.realm();
   4879        return true;
   4880      }
   4881 
   4882      if (iter.isJSJit() && iter.asJSJit().isIonScripted()) {
   4883        // Ion might have inlined non-self-hosted scripts in this
   4884        // self-hosted script.
   4885        return false;
   4886      }
   4887 
   4888      ++iter;
   4889    }
   4890  } else if (activationIter->isInterpreter()) {
   4891    InterpreterActivation* act = activationIter->asInterpreter();
   4892    for (InterpreterFrameIterator iter(act); !iter.done(); ++iter) {
   4893      if (!iter.frame()->script()->selfHosted()) {
   4894        *activation = act;
   4895        *realm = iter.frame()->script()->realm();
   4896        return true;
   4897      }
   4898    }
   4899  }
   4900 
   4901  return false;
   4902 }
   4903 
   4904 JS_PUBLIC_API JSObject* GetScriptedCallerGlobal(JSContext* cx) {
   4905  Activation* activation;
   4906  Realm* realm;
   4907  if (GetScriptedCallerActivationRealmFast(cx, &activation, &realm)) {
   4908    if (!activation) {
   4909      return nullptr;
   4910    }
   4911  } else {
   4912    NonBuiltinFrameIter i(cx);
   4913    if (i.done()) {
   4914      return nullptr;
   4915    }
   4916    activation = i.activation();
   4917    realm = i.realm();
   4918  }
   4919 
   4920  MOZ_ASSERT(realm->compartment() == activation->compartment());
   4921 
   4922  // If the caller is hidden, the embedding wants us to return null here so
   4923  // that it can check its own stack (see HideScriptedCaller).
   4924  if (activation->scriptedCallerIsHidden()) {
   4925    return nullptr;
   4926  }
   4927 
   4928  GlobalObject* global = realm->maybeGlobal();
   4929 
   4930  // No one should be running code in a realm without any live objects, so
   4931  // there should definitely be a live global.
   4932  MOZ_ASSERT(global);
   4933 
   4934  return global;
   4935 }
   4936 
   4937 JS_PUBLIC_API void HideScriptedCaller(JSContext* cx) {
   4938  MOZ_ASSERT(cx);
   4939 
   4940  // If there's no accessible activation on the stack, we'll return null from
   4941  // DescribeScriptedCaller anyway, so there's no need to annotate anything.
   4942  Activation* act = cx->activation();
   4943  if (!act) {
   4944    return;
   4945  }
   4946  act->hideScriptedCaller();
   4947 }
   4948 
   4949 JS_PUBLIC_API void UnhideScriptedCaller(JSContext* cx) {
   4950  Activation* act = cx->activation();
   4951  if (!act) {
   4952    return;
   4953  }
   4954  act->unhideScriptedCaller();
   4955 }
   4956 
   4957 } /* namespace JS */
   4958 
   4959 #ifdef JS_DEBUG
   4960 JS_PUBLIC_API void JS::detail::AssertArgumentsAreSane(JSContext* cx,
   4961                                                      HandleValue value) {
   4962  AssertHeapIsIdle();
   4963  CHECK_THREAD(cx);
   4964  cx->check(value);
   4965 }
   4966 #endif /* JS_DEBUG */
   4967 
   4968 bool JS::IsWasmModuleObject(HandleObject obj) {
   4969  return obj->canUnwrapAs<WasmModuleObject>();
   4970 }
   4971 
   4972 JS_PUBLIC_API RefPtr<JS::WasmModule> JS::GetWasmModule(HandleObject obj) {
   4973  MOZ_ASSERT(JS::IsWasmModuleObject(obj));
   4974  WasmModuleObject& mobj = obj->unwrapAs<WasmModuleObject>();
   4975  return const_cast<wasm::Module*>(&mobj.module());
   4976 }
   4977 
   4978 JS_PUBLIC_API void JS::SetProcessLargeAllocationFailureCallback(
   4979    JS::LargeAllocationFailureCallback lafc) {
   4980  MOZ_ASSERT(!OnLargeAllocationFailure);
   4981  OnLargeAllocationFailure = lafc;
   4982 }
   4983 
   4984 JS_PUBLIC_API void JS::SetOutOfMemoryCallback(JSContext* cx,
   4985                                              OutOfMemoryCallback cb,
   4986                                              void* data) {
   4987  cx->runtime()->oomCallback = cb;
   4988  cx->runtime()->oomCallbackData = data;
   4989 }
   4990 
   4991 JS_PUBLIC_API void JS::SetShadowRealmInitializeGlobalCallback(
   4992    JSContext* cx, JS::GlobalInitializeCallback callback) {
   4993  cx->runtime()->shadowRealmInitializeGlobalCallback = callback;
   4994 }
   4995 
   4996 JS_PUBLIC_API void JS::SetShadowRealmGlobalCreationCallback(
   4997    JSContext* cx, JS::GlobalCreationCallback callback) {
   4998  cx->runtime()->shadowRealmGlobalCreationCallback = callback;
   4999 }
   5000 
   5001 JS_PUBLIC_API bool JS::SetLoggingInterface(LoggingInterface& iface) {
   5002  return js::LogModule::initializeAll(iface);
   5003 }
   5004 
   5005 JS::FirstSubsumedFrame::FirstSubsumedFrame(
   5006    JSContext* cx, bool ignoreSelfHostedFrames /* = true */)
   5007    : JS::FirstSubsumedFrame(cx, cx->realm()->principals(),
   5008                             ignoreSelfHostedFrames) {}
   5009 
   5010 JS_PUBLIC_API bool JS::CaptureCurrentStack(
   5011    JSContext* cx, JS::MutableHandleObject stackp,
   5012    JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */,
   5013    JS::HandleObject startAt /* = nullptr*/) {
   5014  AssertHeapIsIdle();
   5015  CHECK_THREAD(cx);
   5016  MOZ_RELEASE_ASSERT(cx->realm());
   5017 
   5018  Realm* realm = cx->realm();
   5019  Rooted<SavedFrame*> frame(cx);
   5020  if (!realm->savedStacks().saveCurrentStack(cx, &frame, std::move(capture),
   5021                                             startAt)) {
   5022    return false;
   5023  }
   5024  stackp.set(frame.get());
   5025  return true;
   5026 }
   5027 
   5028 JS_PUBLIC_API bool JS::IsAsyncStackCaptureEnabledForRealm(JSContext* cx) {
   5029  if (!cx->options().asyncStack()) {
   5030    return false;
   5031  }
   5032 
   5033  if (!cx->options().asyncStackCaptureDebuggeeOnly() ||
   5034      cx->realm()->isDebuggee()) {
   5035    return true;
   5036  }
   5037 
   5038  return cx->realm()->isAsyncStackCapturingEnabled;
   5039 }
   5040 
   5041 JS_PUBLIC_API bool JS::CopyAsyncStack(JSContext* cx,
   5042                                      JS::HandleObject asyncStack,
   5043                                      JS::HandleString asyncCause,
   5044                                      JS::MutableHandleObject stackp,
   5045                                      const Maybe<size_t>& maxFrameCount) {
   5046  AssertHeapIsIdle();
   5047  CHECK_THREAD(cx);
   5048  MOZ_RELEASE_ASSERT(cx->realm());
   5049 
   5050  js::AssertObjectIsSavedFrameOrWrapper(cx, asyncStack);
   5051  Realm* realm = cx->realm();
   5052  Rooted<SavedFrame*> frame(cx);
   5053  if (!realm->savedStacks().copyAsyncStack(cx, asyncStack, asyncCause, &frame,
   5054                                           maxFrameCount)) {
   5055    return false;
   5056  }
   5057  stackp.set(frame.get());
   5058  return true;
   5059 }
   5060 
   5061 JS_PUBLIC_API Zone* JS::GetObjectZone(JSObject* obj) {
   5062  Zone* zone = obj->zone();
   5063 
   5064  // Check zone pointer is valid and not a poison value. See bug 1878421.
   5065  MOZ_RELEASE_ASSERT(zone->runtimeFromMainThread());
   5066 
   5067  return zone;
   5068 }
   5069 
   5070 JS_PUBLIC_API Zone* JS::GetTenuredGCThingZone(GCCellPtr thing) {
   5071  js::gc::Cell* cell = thing.asCell();
   5072  MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
   5073  Zone* zone = js::gc::detail::GetTenuredGCThingZone(cell);
   5074 
   5075  // Check zone pointer is valid and not a poison value. See bug 1878421.
   5076  MOZ_RELEASE_ASSERT(zone->runtimeFromMainThread());
   5077 
   5078  return zone;
   5079 }
   5080 
   5081 JS_PUBLIC_API Zone* JS::GetNurseryCellZone(gc::Cell* cell) {
   5082  return cell->nurseryZone();
   5083 }
   5084 
   5085 JS_PUBLIC_API JS::TraceKind JS::GCThingTraceKind(void* thing) {
   5086  MOZ_ASSERT(thing);
   5087  return static_cast<js::gc::Cell*>(thing)->getTraceKind();
   5088 }
   5089 
   5090 JS_PUBLIC_API void js::SetStackFormat(JSContext* cx, js::StackFormat format) {
   5091  cx->runtime()->setStackFormat(format);
   5092 }
   5093 
   5094 JS_PUBLIC_API js::StackFormat js::GetStackFormat(JSContext* cx) {
   5095  return cx->runtime()->stackFormat();
   5096 }
   5097 
   5098 JS_PUBLIC_API void JS::SetMeasuringExecutionTimeEnabled(JSContext* cx,
   5099                                                        bool value) {
   5100  cx->setMeasuringExecutionTimeEnabled(value);
   5101 }
   5102 
   5103 JS_PUBLIC_API JS::JSTimers JS::GetJSTimers(JSContext* cx) {
   5104  return cx->realm()->timers;
   5105 }
   5106 
   5107 namespace js {
   5108 
   5109 JS_PUBLIC_API void NoteIntentionalCrash() {
   5110 #ifdef __linux__
   5111  static bool* addr =
   5112      reinterpret_cast<bool*>(dlsym(RTLD_DEFAULT, "gBreakpadInjectorEnabled"));
   5113  if (addr) {
   5114    *addr = false;
   5115  }
   5116 #endif
   5117 }
   5118 
   5119 #ifdef DEBUG
   5120 bool gSupportDifferentialTesting = false;
   5121 #endif  // DEBUG
   5122 
   5123 }  // namespace js
   5124 
   5125 #ifdef DEBUG
   5126 
   5127 JS_PUBLIC_API void JS::SetSupportDifferentialTesting(bool value) {
   5128  js::gSupportDifferentialTesting = value;
   5129 }
   5130 
   5131 #endif  // DEBUG