tor-browser

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

Runtime.cpp (28109B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "vm/Runtime.h"
      8 
      9 #include "mozilla/Atomics.h"
     10 #include "mozilla/DebugOnly.h"
     11 #if JS_HAS_INTL_API
     12 #  include "mozilla/intl/Locale.h"
     13 #endif
     14 #include "mozilla/MemoryReporting.h"
     15 #include "mozilla/ThreadLocal.h"
     16 
     17 #include <locale.h>
     18 #include <string.h>
     19 
     20 #include "jsfriendapi.h"
     21 #include "jsmath.h"
     22 
     23 #include "builtin/String.h"
     24 #include "frontend/CompilationStencil.h"
     25 #include "frontend/ParserAtom.h"  // frontend::WellKnownParserAtoms
     26 #include "gc/GC.h"
     27 #include "gc/PublicIterators.h"
     28 #include "jit/IonCompileTask.h"
     29 #include "jit/JitRuntime.h"
     30 #include "jit/Simulator.h"
     31 #include "js/AllocationLogging.h"  // JS_COUNT_CTOR, JS_COUNT_DTOR
     32 #include "js/experimental/JSStencil.h"
     33 #include "js/experimental/SourceHook.h"
     34 #include "js/friend/ErrorMessages.h"  // JSMSG_*
     35 #include "js/Interrupt.h"
     36 #include "js/MemoryMetrics.h"
     37 #include "js/Stack.h"  // JS::NativeStackLimitMin
     38 #include "js/Wrapper.h"
     39 #include "js/WrapperCallbacks.h"
     40 #include "vm/DateTime.h"
     41 #include "vm/JSFunction.h"
     42 #include "vm/JSObject.h"
     43 #include "vm/JSScript.h"
     44 #include "vm/PromiseObject.h"  // js::PromiseObject
     45 #include "vm/SharedImmutableStringsCache.h"
     46 #include "vm/Warnings.h"  // js::WarnNumberUC
     47 #include "wasm/WasmPI.h"
     48 #include "wasm/WasmSignalHandlers.h"
     49 
     50 #include "debugger/DebugAPI-inl.h"
     51 #include "gc/ArenaList-inl.h"
     52 #include "vm/JSContext-inl.h"
     53 #include "vm/Realm-inl.h"
     54 
     55 using namespace js;
     56 
     57 using mozilla::Atomic;
     58 using mozilla::DebugOnly;
     59 
     60 /* static */ MOZ_THREAD_LOCAL(JSContext*) js::TlsContext;
     61 /* static */
     62 Atomic<size_t> JSRuntime::liveRuntimesCount;
     63 Atomic<JS::LargeAllocationFailureCallback> js::OnLargeAllocationFailure;
     64 
     65 JS::FilenameValidationCallback js::gFilenameValidationCallback = nullptr;
     66 
     67 namespace js {
     68 
     69 #ifndef __wasi__
     70 bool gCanUseExtraThreads = true;
     71 #else
     72 bool gCanUseExtraThreads = false;
     73 #endif
     74 }  // namespace js
     75 
     76 void js::DisableExtraThreads() { gCanUseExtraThreads = false; }
     77 
     78 const JSSecurityCallbacks js::NullSecurityCallbacks = {};
     79 
     80 static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
     81    TransparentObjectWrapper, nullptr};
     82 
     83 extern bool DefaultHostEnsureCanAddPrivateElementCallback(JSContext* cx,
     84                                                          HandleValue val);
     85 
     86 static size_t ReturnZeroSize(const void* p) { return 0; }
     87 
     88 JSRuntime::JSRuntime(JSRuntime* parentRuntime)
     89    : parentRuntime(parentRuntime),
     90 #ifdef DEBUG
     91      updateChildRuntimeCount(parentRuntime),
     92      initialized_(false),
     93 #endif
     94      mainContext_(nullptr),
     95      profilerSampleBufferRangeStart_(0),
     96      telemetryCallback(nullptr),
     97      consumeStreamCallback(nullptr),
     98      reportStreamErrorCallback(nullptr),
     99      hadOutOfMemory(false),
    100      allowRelazificationForTesting(false),
    101      destroyCompartmentCallback(nullptr),
    102      sizeOfIncludingThisCompartmentCallback(nullptr),
    103      destroyRealmCallback(nullptr),
    104      realmNameCallback(nullptr),
    105      securityCallbacks(&NullSecurityCallbacks),
    106      DOMcallbacks(nullptr),
    107      destroyPrincipals(nullptr),
    108      readPrincipals(nullptr),
    109      canAddPrivateElement(&DefaultHostEnsureCanAddPrivateElementCallback),
    110      warningReporter(nullptr),
    111      geckoProfiler_(thisFromCtor()),
    112      trustedPrincipals_(nullptr),
    113      wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
    114      preserveWrapperCallback(nullptr),
    115      scriptEnvironmentPreparer(nullptr),
    116      ctypesActivityCallback(nullptr),
    117      windowProxyClass_(nullptr),
    118      numRealms(0),
    119      numDebuggeeRealms_(0),
    120      numDebuggeeRealmsObservingCoverage_(0),
    121      localeCallbacks(nullptr),
    122      defaultLocale(nullptr),
    123      profilingScripts(false),
    124      scriptAndCountsVector(nullptr),
    125      watchtowerTestingLog(nullptr),
    126      jitRuntime_(nullptr),
    127      gc(thisFromCtor()),
    128      emptyString(nullptr),
    129 #if !JS_HAS_INTL_API
    130      thousandsSeparator(nullptr),
    131      decimalSeparator(nullptr),
    132      numGrouping(nullptr),
    133 #endif
    134      beingDestroyed_(false),
    135      allowContentJS_(true),
    136      atoms_(nullptr),
    137      permanentAtoms_(nullptr),
    138      staticStrings(nullptr),
    139      commonNames(nullptr),
    140      wellKnownSymbols(nullptr),
    141      scriptDataTableHolder_(SharedScriptDataTableHolder::NeedsLock::No),
    142      liveSABs(0),
    143      beforeWaitCallback(nullptr),
    144      afterWaitCallback(nullptr),
    145      offthreadBaselineCompilationEnabled_(false),
    146      offthreadIonCompilationEnabled_(true),
    147      autoWritableJitCodeActive_(false),
    148      oomCallback(nullptr),
    149      debuggerMallocSizeOf(ReturnZeroSize),
    150      stackFormat_(parentRuntime ? js::StackFormat::Default
    151                                 : js::StackFormat::SpiderMonkey),
    152      wasmInstances(mutexid::WasmRuntimeInstances),
    153      moduleAsyncEvaluatingPostOrder(0),
    154      pendingAsyncModuleEvaluations(0) {
    155  JS_COUNT_CTOR(JSRuntime);
    156  liveRuntimesCount++;
    157 
    158 #ifndef __wasi__
    159  // See function comment for why we call this now, not in JS_Init().
    160  wasm::EnsureEagerProcessSignalHandlers();
    161 #endif  // __wasi__
    162 }
    163 
    164 JSRuntime::~JSRuntime() {
    165  JS_COUNT_DTOR(JSRuntime);
    166  MOZ_ASSERT(!initialized_);
    167 
    168  DebugOnly<size_t> oldCount = liveRuntimesCount--;
    169  MOZ_ASSERT(oldCount > 0);
    170 
    171  MOZ_ASSERT(wasmInstances.lock()->empty());
    172 
    173  MOZ_ASSERT(numRealms == 0);
    174  MOZ_ASSERT(numDebuggeeRealms_ == 0);
    175  MOZ_ASSERT(numDebuggeeRealmsObservingCoverage_ == 0);
    176 }
    177 
    178 bool JSRuntime::init(JSContext* cx, uint32_t maxbytes) {
    179 #ifdef DEBUG
    180  MOZ_ASSERT(!initialized_);
    181  initialized_ = true;
    182 #endif
    183 
    184  if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized()) {
    185    return false;
    186  }
    187 
    188  mainContext_ = cx;
    189 
    190  if (!gc.init(maxbytes)) {
    191    return false;
    192  }
    193 
    194  if (!InitRuntimeNumberState(this)) {
    195    return false;
    196  }
    197 
    198  // As a hack, we clear our timezone cache every time we create a new runtime.
    199  // Also see the comment in JS::Realm::init().
    200  js::ResetTimeZoneInternal(ResetTimeZoneMode::DontResetIfOffsetUnchanged);
    201 
    202  caches().megamorphicSetPropCache = MakeUnique<MegamorphicSetPropCache>();
    203  if (!caches().megamorphicSetPropCache) {
    204    return false;
    205  }
    206 
    207  return true;
    208 }
    209 
    210 void JSRuntime::destroyRuntime() {
    211  MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
    212  MOZ_ASSERT(childRuntimeCount == 0);
    213  MOZ_ASSERT(initialized_);
    214 
    215 #ifdef JS_HAS_INTL_API
    216  sharedIntlData.ref().destroyInstance();
    217 #endif
    218 
    219  watchtowerTestingLog.ref().reset();
    220 
    221  if (gc.wasInitialized()) {
    222    /*
    223     * Finish any in-progress GCs first.
    224     */
    225    JSContext* cx = mainContextFromOwnThread();
    226    if (JS::IsIncrementalGCInProgress(cx)) {
    227      gc::FinishGC(cx);
    228    }
    229 
    230    /* Free source hook early, as its destructor may want to delete roots. */
    231    sourceHook = nullptr;
    232 
    233    /*
    234     * Cancel any pending, in progress or completed baseline/Ion compilations
    235     * and parse tasks. Waiting for wasm and compression tasks is done
    236     * synchronously (on the main thread or during parse tasks), so no
    237     * explicit canceling is needed for these.
    238     */
    239    CancelOffThreadCompile(this);
    240    CancelOffThreadDelazify(this);
    241    CancelOffThreadCompressions(this);
    242 
    243    /*
    244     * Flag us as being destroyed. This allows the GC to free things like
    245     * interned atoms and Ion trampolines.
    246     */
    247    beingDestroyed_ = true;
    248 
    249    /* Remove persistent GC roots. */
    250    gc.finishRoots();
    251 
    252    /* Allow the GC to release scripts that were being profiled. */
    253    profilingScripts = false;
    254 
    255    JS::PrepareForFullGC(cx);
    256    gc.gc(JS::GCOptions::Shutdown, JS::GCReason::DESTROY_RUNTIME);
    257  }
    258 
    259  AutoNoteSingleThreadedRegion anstr;
    260 
    261  MOZ_ASSERT(scriptDataTableHolder().getWithoutLock().empty());
    262 
    263 #if !JS_HAS_INTL_API
    264  FinishRuntimeNumberState(this);
    265 #endif
    266 
    267  gc.finish();
    268 
    269  for (auto [f, data] : cleanupClosures.ref()) {
    270    f(data);
    271  }
    272  cleanupClosures.ref().clear();
    273 
    274  defaultLocale = nullptr;
    275  js_delete(jitRuntime_.ref());
    276 
    277 #ifdef DEBUG
    278  initialized_ = false;
    279 #endif
    280 }
    281 
    282 void JSRuntime::addTelemetry(JSMetric id, uint32_t sample) {
    283  if (telemetryCallback) {
    284    (*telemetryCallback)(id, sample);
    285  }
    286 }
    287 
    288 void JSRuntime::setTelemetryCallback(
    289    JSRuntime* rt, JSAccumulateTelemetryDataCallback callback) {
    290  rt->telemetryCallback = callback;
    291 }
    292 
    293 void JSRuntime::setUseCounter(JSObject* obj, JSUseCounter counter) {
    294  if (useCounterCallback) {
    295    // A use counter callback cannot GC.
    296    JS::AutoSuppressGCAnalysis suppress;
    297    (*useCounterCallback)(obj, counter);
    298  }
    299 }
    300 
    301 void JSRuntime::setUseCounterCallback(JSRuntime* rt,
    302                                      JSSetUseCounterCallback callback) {
    303  rt->useCounterCallback = callback;
    304 }
    305 
    306 void JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
    307                                       JS::RuntimeSizes* rtSizes) {
    308  rtSizes->object += mallocSizeOf(this);
    309 
    310  rtSizes->atomsTable += atoms().sizeOfIncludingThis(mallocSizeOf);
    311  rtSizes->gc.marker += gc.markers.sizeOfExcludingThis(mallocSizeOf);
    312  for (auto& marker : gc.markers) {
    313    rtSizes->gc.marker += marker->sizeOfIncludingThis(mallocSizeOf);
    314  }
    315 
    316  if (!parentRuntime) {
    317    rtSizes->atomsTable += mallocSizeOf(staticStrings);
    318    rtSizes->atomsTable += mallocSizeOf(commonNames);
    319    rtSizes->atomsTable += permanentAtoms()->sizeOfIncludingThis(mallocSizeOf);
    320 
    321    rtSizes->selfHostStencil =
    322        selfHostStencilInput_->sizeOfIncludingThis(mallocSizeOf) +
    323        selfHostStencil_->sizeOfIncludingThis(mallocSizeOf) +
    324        selfHostScriptMap.ref().shallowSizeOfExcludingThis(mallocSizeOf);
    325  }
    326 
    327  JSContext* cx = mainContextFromAnyThread();
    328  rtSizes->contexts += cx->sizeOfIncludingThis(mallocSizeOf);
    329  rtSizes->temporary += cx->tempLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
    330  rtSizes->interpreterStack +=
    331      cx->interpreterStack().sizeOfExcludingThis(mallocSizeOf);
    332  rtSizes->uncompressedSourceCache +=
    333      caches().uncompressedSourceCache.sizeOfExcludingThis(mallocSizeOf);
    334 
    335  rtSizes->gc.nurseryCommitted += gc.nursery().totalCommitted();
    336  rtSizes->gc.nurseryMallocedBuffers +=
    337      gc.nursery().sizeOfMallocedBuffers(mallocSizeOf);
    338  gc.storeBuffer().addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc);
    339 
    340  if (isMainRuntime()) {
    341    rtSizes->sharedImmutableStringsCache +=
    342        js::SharedImmutableStringsCache::getSingleton().sizeOfExcludingThis(
    343            mallocSizeOf);
    344    rtSizes->atomsTable +=
    345        js::frontend::WellKnownParserAtoms::getSingleton().sizeOfExcludingThis(
    346            mallocSizeOf);
    347  }
    348 
    349 #ifdef JS_HAS_INTL_API
    350  rtSizes->sharedIntlData +=
    351      sharedIntlData.ref().sizeOfExcludingThis(mallocSizeOf);
    352 #endif
    353 
    354  {
    355    auto& table = scriptDataTableHolder().getWithoutLock();
    356 
    357    rtSizes->scriptData += table.shallowSizeOfExcludingThis(mallocSizeOf);
    358    for (SharedImmutableScriptDataTable::Range r = table.all(); !r.empty();
    359         r.popFront()) {
    360      rtSizes->scriptData += r.front()->sizeOfIncludingThis(mallocSizeOf);
    361    }
    362  }
    363 
    364  if (isMainRuntime()) {
    365    AutoLockGlobalScriptData lock;
    366 
    367    auto& table = js::globalSharedScriptDataTableHolder.get(lock);
    368 
    369    rtSizes->scriptData += table.shallowSizeOfExcludingThis(mallocSizeOf);
    370    for (SharedImmutableScriptDataTable::Range r = table.all(); !r.empty();
    371         r.popFront()) {
    372      rtSizes->scriptData += r.front()->sizeOfIncludingThis(mallocSizeOf);
    373    }
    374  }
    375 
    376  if (jitRuntime_) {
    377    // Sizes of the IonCompileTasks we are holding for lazy linking
    378    for (auto* task : jitRuntime_->ionLazyLinkList(this)) {
    379      rtSizes->jitLazyLink += task->sizeOfExcludingThis(mallocSizeOf);
    380    }
    381  }
    382 
    383  rtSizes->wasmRuntime +=
    384      wasmInstances.lock()->sizeOfExcludingThis(mallocSizeOf);
    385 }
    386 
    387 static bool InvokeInterruptCallbacks(JSContext* cx) {
    388  bool stop = false;
    389  for (JSInterruptCallback cb : cx->interruptCallbacks()) {
    390    if (!cb(cx)) {
    391      stop = true;
    392    }
    393  }
    394  return stop;
    395 }
    396 
    397 static bool HandleInterrupt(JSContext* cx, bool invokeCallback,
    398                            bool oomStackTrace) {
    399  MOZ_ASSERT(!cx->zone()->isAtomsZone());
    400 
    401  cx->runtime()->gc.gcIfRequested();
    402 
    403  if (oomStackTrace) {
    404    // Capture OOM stack trace this way because we don't have memory to handle
    405    // it the way ComputeStackString does.
    406    cx->captureOOMStackTrace();
    407  } else {
    408    // We can handle OOM interrupts while handling exceptions, when it isn't
    409    // safe to attach finished compilations
    410 
    411    // A worker thread may have requested an interrupt after finishing an
    412    // offthread compilation.
    413    jit::AttachFinishedCompilations(cx);
    414  }
    415 
    416  // Don't call the interrupt callback if we only interrupted for GC, Ion, or
    417  // OOM.
    418  if (!invokeCallback) {
    419    return true;
    420  }
    421 
    422  // Important: Additional callbacks can occur inside the callback handler
    423  // if it re-enters the JS engine. The embedding must ensure that the
    424  // callback is disconnected before attempting such re-entry.
    425  if (cx->interruptCallbackDisabled) {
    426    return true;
    427  }
    428 
    429  if (!InvokeInterruptCallbacks(cx)) {
    430    // Debugger treats invoking the interrupt callback as a "step", so
    431    // invoke the onStep handler.
    432    if (cx->realm()->isDebuggee()) {
    433      ScriptFrameIter iter(cx);
    434      if (!iter.done() && cx->compartment() == iter.compartment() &&
    435          DebugAPI::stepModeEnabled(iter.script())) {
    436        if (!DebugAPI::onSingleStep(cx)) {
    437          return false;
    438        }
    439      }
    440    }
    441 
    442    return true;
    443  }
    444 
    445  // No need to set aside any pending exception here: ComputeStackString
    446  // already does that.
    447  JSString* stack = ComputeStackString(cx);
    448 
    449  UniqueTwoByteChars stringChars;
    450  if (stack) {
    451    stringChars = JS_CopyStringCharsZ(cx, stack);
    452    if (!stringChars) {
    453      cx->recoverFromOutOfMemory();
    454    }
    455  }
    456 
    457  const char16_t* chars;
    458  if (stringChars) {
    459    chars = stringChars.get();
    460  } else {
    461    chars = u"(stack not available)";
    462  }
    463  WarnNumberUC(cx, JSMSG_TERMINATED, chars);
    464  cx->reportUncatchableException();
    465  return false;
    466 }
    467 
    468 void JSContext::requestInterrupt(InterruptReason reason) {
    469  interruptBits_ |= uint32_t(reason);
    470  jitStackLimit = JS::NativeStackLimitMin;
    471 
    472  if (reason == InterruptReason::CallbackUrgent) {
    473    // If this interrupt is urgent (slow script dialog for instance), take
    474    // additional steps to interrupt corner cases where the above fields are
    475    // not regularly polled.
    476    FutexThread::lock();
    477    if (fx.isWaiting()) {
    478      fx.notify(FutexThread::NotifyForJSInterrupt);
    479    }
    480    fx.unlock();
    481  }
    482 
    483  if (reason == InterruptReason::CallbackUrgent ||
    484      reason == InterruptReason::MajorGC ||
    485      reason == InterruptReason::MinorGC) {
    486    wasm::InterruptRunningCode(this);
    487  }
    488 }
    489 
    490 bool JSContext::handleInterrupt() {
    491  MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
    492  if (hasAnyPendingInterrupt() || jitStackLimit == JS::NativeStackLimitMin) {
    493    bool invokeCallback =
    494        hasPendingInterrupt(InterruptReason::CallbackUrgent) ||
    495        hasPendingInterrupt(InterruptReason::CallbackCanWait);
    496    bool oomStackTrace = hasPendingInterrupt(InterruptReason::OOMStackTrace);
    497    interruptBits_ = 0;
    498    resetJitStackLimit();
    499    return HandleInterrupt(this, invokeCallback, oomStackTrace);
    500  }
    501  return true;
    502 }
    503 
    504 bool JSContext::handleInterruptNoCallbacks() {
    505  MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
    506  if (hasAnyPendingInterrupt() || jitStackLimit == JS::NativeStackLimitMin) {
    507    bool oomStackTrace = hasPendingInterrupt(InterruptReason::OOMStackTrace);
    508    clearPendingInterrupt(js::InterruptReason::OOMStackTrace);
    509    if (!hasAnyPendingInterrupt()) {
    510      resetJitStackLimit();
    511    }
    512    return HandleInterrupt(this, false, oomStackTrace);
    513  }
    514  return true;
    515 }
    516 
    517 void JSContext::clearPendingInterrupt(js::InterruptReason reason) {
    518  // Interrupt bit have already been cleared.
    519  interruptBits_ &= ~uint32_t(reason);
    520 }
    521 
    522 bool JSRuntime::setDefaultLocale(const char* locale) {
    523  if (!locale) {
    524    return false;
    525  }
    526 
    527  UniqueChars newLocale = DuplicateString(mainContextFromOwnThread(), locale);
    528  if (!newLocale) {
    529    return false;
    530  }
    531 
    532 #if JS_HAS_INTL_API
    533  if (!LocaleHasDefaultCaseMapping(newLocale.get())) {
    534    runtimeFuses.ref().defaultLocaleHasDefaultCaseMappingFuse.popFuse(
    535        mainContextFromOwnThread());
    536  }
    537 #endif
    538 
    539  defaultLocale.ref() = std::move(newLocale);
    540  return true;
    541 }
    542 
    543 void JSRuntime::resetDefaultLocale() { defaultLocale = nullptr; }
    544 
    545 const char* JSRuntime::getDefaultLocale() {
    546  if (defaultLocale.ref()) {
    547    return defaultLocale.ref().get();
    548  }
    549 
    550  // Use ICU if available to retrieve the default locale, this ensures ICU's
    551  // default locale matches our default locale.
    552 #if JS_HAS_INTL_API
    553  const char* locale = mozilla::intl::Locale::GetDefaultLocale();
    554 #else
    555  const char* locale = setlocale(LC_ALL, nullptr);
    556 #endif
    557 
    558  // convert to a well-formed BCP 47 language tag
    559  if (!locale || !strcmp(locale, "C")) {
    560    locale = "und";
    561  }
    562 
    563  UniqueChars lang = DuplicateString(mainContextFromOwnThread(), locale);
    564  if (!lang) {
    565    return nullptr;
    566  }
    567 
    568  char* p;
    569  if ((p = strchr(lang.get(), '.'))) {
    570    *p = '\0';
    571  }
    572  while ((p = strchr(lang.get(), '_'))) {
    573    *p = '-';
    574  }
    575 
    576 #if JS_HAS_INTL_API
    577  if (!LocaleHasDefaultCaseMapping(lang.get())) {
    578    runtimeFuses.ref().defaultLocaleHasDefaultCaseMappingFuse.popFuse(
    579        mainContextFromOwnThread());
    580  }
    581 #endif
    582 
    583  defaultLocale.ref() = std::move(lang);
    584  return defaultLocale.ref().get();
    585 }
    586 
    587 #ifdef JS_HAS_INTL_API
    588 void JSRuntime::traceSharedIntlData(JSTracer* trc) {
    589  sharedIntlData.ref().trace(trc);
    590 }
    591 #endif
    592 
    593 SharedScriptDataTableHolder& JSRuntime::scriptDataTableHolder() {
    594  return scriptDataTableHolder_;
    595 }
    596 
    597 bool JSRuntime::getHostDefinedData(JSContext* cx,
    598                                   JS::MutableHandle<JSObject*> data) const {
    599  MOZ_ASSERT(cx->jobQueue);
    600 
    601  return cx->jobQueue->getHostDefinedData(cx, data);
    602 }
    603 
    604 JS_PUBLIC_API JSObject*
    605 JS::MaybeGetPromiseAllocationSiteFromPossiblyWrappedPromise(
    606    HandleObject promise) {
    607  if (!promise) {
    608    return nullptr;
    609  }
    610 
    611  JSObject* unwrappedPromise = promise;
    612  // While the job object is guaranteed to be unwrapped, the promise
    613  // might be wrapped. See the comments in EnqueuePromiseReactionJob in
    614  // builtin/Promise.cpp for details.
    615  if (IsWrapper(promise)) {
    616    unwrappedPromise = UncheckedUnwrap(promise);
    617  }
    618  if (unwrappedPromise->is<PromiseObject>()) {
    619    return unwrappedPromise->as<PromiseObject>().allocationSite();
    620  }
    621  return nullptr;
    622 }
    623 
    624 bool JSRuntime::enqueuePromiseJob(JSContext* cx, HandleFunction job,
    625                                  HandleObject promise,
    626                                  HandleObject hostDefinedData) {
    627  MOZ_ASSERT(cx->jobQueue,
    628             "Must select a JobQueue implementation using JS::JobQueue "
    629             "or js::UseInternalJobQueues before using Promises");
    630 
    631  if (promise) {
    632 #ifdef DEBUG
    633    AssertSameCompartment(job, promise);
    634 #endif
    635  }
    636 
    637  RootedObject allocationSite(
    638      cx, JS::MaybeGetPromiseAllocationSiteFromPossiblyWrappedPromise(promise));
    639  return cx->jobQueue->enqueuePromiseJob(cx, promise, job, allocationSite,
    640                                         hostDefinedData);
    641 }
    642 
    643 void JSRuntime::addUnhandledRejectedPromise(JSContext* cx,
    644                                            js::HandleObject promise) {
    645  MOZ_ASSERT(promise->is<PromiseObject>());
    646  if (!cx->promiseRejectionTrackerCallback) {
    647    return;
    648  }
    649 
    650  bool mutedErrors = false;
    651  if (JSScript* script = cx->currentScript()) {
    652    mutedErrors = script->mutedErrors();
    653  }
    654 
    655  void* data = cx->promiseRejectionTrackerCallbackData;
    656  cx->promiseRejectionTrackerCallback(
    657      cx, mutedErrors, promise, JS::PromiseRejectionHandlingState::Unhandled,
    658      data);
    659 }
    660 
    661 void JSRuntime::removeUnhandledRejectedPromise(JSContext* cx,
    662                                               js::HandleObject promise) {
    663  MOZ_ASSERT(promise->is<PromiseObject>());
    664  if (!cx->promiseRejectionTrackerCallback) {
    665    return;
    666  }
    667 
    668  bool mutedErrors = false;
    669  if (JSScript* script = cx->currentScript()) {
    670    mutedErrors = script->mutedErrors();
    671  }
    672 
    673  void* data = cx->promiseRejectionTrackerCallbackData;
    674  cx->promiseRejectionTrackerCallback(
    675      cx, mutedErrors, promise, JS::PromiseRejectionHandlingState::Handled,
    676      data);
    677 }
    678 
    679 mozilla::non_crypto::XorShift128PlusRNG& JSRuntime::randomKeyGenerator() {
    680  MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
    681  if (randomKeyGenerator_.isNothing()) {
    682    mozilla::Array<uint64_t, 2> seed;
    683    GenerateXorShift128PlusSeed(seed);
    684    randomKeyGenerator_.emplace(seed[0], seed[1]);
    685  }
    686  return randomKeyGenerator_.ref();
    687 }
    688 
    689 mozilla::HashCodeScrambler JSRuntime::randomHashCodeScrambler() {
    690  auto& rng = randomKeyGenerator();
    691  return mozilla::HashCodeScrambler(rng.next(), rng.next());
    692 }
    693 
    694 mozilla::non_crypto::XorShift128PlusRNG JSRuntime::forkRandomKeyGenerator() {
    695  auto& rng = randomKeyGenerator();
    696  return mozilla::non_crypto::XorShift128PlusRNG(rng.next(), rng.next());
    697 }
    698 
    699 js::HashNumber JSRuntime::randomHashCode() {
    700  MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
    701 
    702  if (randomHashCodeGenerator_.isNothing()) {
    703    mozilla::Array<uint64_t, 2> seed;
    704    GenerateXorShift128PlusSeed(seed);
    705    randomHashCodeGenerator_.emplace(seed[0], seed[1]);
    706  }
    707 
    708  return HashNumber(randomHashCodeGenerator_->next());
    709 }
    710 
    711 JS_PUBLIC_API void* JSRuntime::onOutOfMemory(AllocFunction allocFunc,
    712                                             arena_id_t arena, size_t nbytes,
    713                                             void* reallocPtr,
    714                                             JSContext* maybecx) {
    715  MOZ_ASSERT_IF(allocFunc != AllocFunction::Realloc, !reallocPtr);
    716 
    717  if (JS::RuntimeHeapIsBusy()) {
    718    return nullptr;
    719  }
    720 
    721  if (!oom::IsSimulatedOOMAllocation()) {
    722    /*
    723     * Retry when we are done with the background sweeping and have stopped
    724     * all the allocations and released the empty GC chunks.
    725     */
    726    gc.onOutOfMallocMemory();
    727    void* p;
    728    switch (allocFunc) {
    729      case AllocFunction::Malloc:
    730        p = js_arena_malloc(arena, nbytes);
    731        break;
    732      case AllocFunction::Calloc:
    733        p = js_arena_calloc(arena, nbytes, 1);
    734        break;
    735      case AllocFunction::Realloc:
    736        p = js_arena_realloc(arena, reallocPtr, nbytes);
    737        break;
    738      default:
    739        MOZ_CRASH();
    740    }
    741    if (p) {
    742      return p;
    743    }
    744  }
    745 
    746  if (maybecx) {
    747    ReportOutOfMemory(maybecx);
    748  }
    749  return nullptr;
    750 }
    751 
    752 void* JSRuntime::onOutOfMemoryCanGC(AllocFunction allocFunc, arena_id_t arena,
    753                                    size_t bytes, void* reallocPtr) {
    754  if (OnLargeAllocationFailure && bytes >= LARGE_ALLOCATION) {
    755    OnLargeAllocationFailure();
    756  }
    757  return onOutOfMemory(allocFunc, arena, bytes, reallocPtr);
    758 }
    759 
    760 bool JSRuntime::activeGCInAtomsZone() {
    761  Zone* zone = unsafeAtomsZone();
    762  return (zone->needsIncrementalBarrier() &&
    763          !gc.isVerifyPreBarriersEnabled()) ||
    764         zone->wasGCStarted();
    765 }
    766 
    767 void JSRuntime::commitPendingWrapperPreservations() {
    768  for (NonAtomZonesIter zone(this); !zone.done(); zone.next()) {
    769    commitPendingWrapperPreservations(zone);
    770  }
    771 }
    772 
    773 void JSRuntime::commitPendingWrapperPreservations(JS::Zone* zone) {
    774  for (JSObject* wrapper : zone->slurpPendingWrapperPreservations()) {
    775    JS::Value objectWrapperSlot =
    776        JS::GetReservedSlot(wrapper, JS_OBJECT_WRAPPER_SLOT);
    777    // This mirrors logic in MaybePreserveDOMWrapper, and should be kept in
    778    // sync with that.
    779    if (objectWrapperSlot.isUndefined() || !objectWrapperSlot.toPrivate()) {
    780      continue;
    781    }
    782 
    783    if (IsWrapper(wrapper)) {
    784      wrapper = UncheckedUnwrap(wrapper);
    785    }
    786 
    787    Rooted<JSObject*> rooted(mainContextFromOwnThread(), wrapper);
    788    bool success = preserveWrapperCallback(mainContextFromOwnThread(), rooted);
    789    MOZ_RELEASE_ASSERT(success);
    790  }
    791 }
    792 
    793 void JSRuntime::incrementNumDebuggeeRealms() {
    794  if (numDebuggeeRealms_ == 0) {
    795    jitRuntime()->baselineInterpreter().toggleDebuggerInstrumentation(true);
    796  }
    797 
    798  numDebuggeeRealms_++;
    799  MOZ_ASSERT(numDebuggeeRealms_ <= numRealms);
    800 }
    801 
    802 void JSRuntime::decrementNumDebuggeeRealms() {
    803  MOZ_ASSERT(numDebuggeeRealms_ > 0);
    804  numDebuggeeRealms_--;
    805 
    806  // Note: if we had shutdown leaks we can end up here while destroying the
    807  // runtime. It's not safe to access JitRuntime trampolines because they're no
    808  // longer traced.
    809  if (numDebuggeeRealms_ == 0 && !isBeingDestroyed()) {
    810    jitRuntime()->baselineInterpreter().toggleDebuggerInstrumentation(false);
    811  }
    812 }
    813 
    814 void JSRuntime::incrementNumDebuggeeRealmsObservingCoverage() {
    815  if (numDebuggeeRealmsObservingCoverage_ == 0) {
    816    jit::BaselineInterpreter& interp = jitRuntime()->baselineInterpreter();
    817    interp.toggleCodeCoverageInstrumentation(true);
    818  }
    819 
    820  numDebuggeeRealmsObservingCoverage_++;
    821  MOZ_ASSERT(numDebuggeeRealmsObservingCoverage_ <= numRealms);
    822 }
    823 
    824 void JSRuntime::decrementNumDebuggeeRealmsObservingCoverage() {
    825  MOZ_ASSERT(numDebuggeeRealmsObservingCoverage_ > 0);
    826  numDebuggeeRealmsObservingCoverage_--;
    827 
    828  // Note: if we had shutdown leaks we can end up here while destroying the
    829  // runtime. It's not safe to access JitRuntime trampolines because they're no
    830  // longer traced.
    831  if (numDebuggeeRealmsObservingCoverage_ == 0 && !isBeingDestroyed()) {
    832    jit::BaselineInterpreter& interp = jitRuntime()->baselineInterpreter();
    833    interp.toggleCodeCoverageInstrumentation(false);
    834  }
    835 }
    836 
    837 bool js::CurrentThreadCanAccessRuntime(const JSRuntime* rt) {
    838  return rt->mainContextFromAnyThread() == TlsContext.get();
    839 }
    840 
    841 bool js::CurrentThreadCanAccessZone(Zone* zone) {
    842  return CurrentThreadCanAccessRuntime(zone->runtime_);
    843 }
    844 
    845 #ifdef DEBUG
    846 bool js::CurrentThreadIsMainThread() { return !!TlsContext.get(); }
    847 #endif
    848 
    849 JS_PUBLIC_API void JS::SetJSContextProfilerSampleBufferRangeStart(
    850    JSContext* cx, uint64_t rangeStart) {
    851  cx->runtime()->setProfilerSampleBufferRangeStart(rangeStart);
    852 }
    853 
    854 JS_PUBLIC_API bool JS::IsProfilingEnabledForContext(JSContext* cx) {
    855  MOZ_ASSERT(cx);
    856  return cx->runtime()->geckoProfiler().enabled();
    857 }
    858 
    859 JS_PUBLIC_API void JS::EnableRecordingAllocations(
    860    JSContext* cx, JS::RecordAllocationsCallback callback, double probability) {
    861  MOZ_ASSERT(cx);
    862  cx->runtime()->startRecordingAllocations(probability, callback);
    863 }
    864 
    865 JS_PUBLIC_API void JS::DisableRecordingAllocations(JSContext* cx) {
    866  MOZ_ASSERT(cx);
    867  cx->runtime()->stopRecordingAllocations();
    868 }
    869 
    870 JS_PUBLIC_API void JS::shadow::RegisterWeakCache(
    871    JSRuntime* rt, detail::WeakCacheBase* cachep) {
    872  rt->registerWeakCache(cachep);
    873 }
    874 
    875 void JSRuntime::startRecordingAllocations(
    876    double probability, JS::RecordAllocationsCallback callback) {
    877  allocationSamplingProbability = probability;
    878  recordAllocationCallback = callback;
    879 
    880  // Go through all of the existing realms, and turn on allocation tracking.
    881  for (RealmsIter realm(this); !realm.done(); realm.next()) {
    882    realm->setAllocationMetadataBuilder(&SavedStacks::metadataBuilder);
    883    realm->chooseAllocationSamplingProbability();
    884  }
    885 }
    886 
    887 void JSRuntime::stopRecordingAllocations() {
    888  recordAllocationCallback = nullptr;
    889  // Go through all of the existing realms, and turn on allocation tracking.
    890  for (RealmsIter realm(this); !realm.done(); realm.next()) {
    891    js::GlobalObject* global = realm->maybeGlobal();
    892    if (!realm->isDebuggee() || !global ||
    893        !DebugAPI::isObservedByDebuggerTrackingAllocations(*global)) {
    894      // Only remove the allocation metadata builder if no Debuggers are
    895      // tracking allocations.
    896      realm->forgetAllocationMetadataBuilder();
    897    }
    898  }
    899 }
    900 
    901 // This function can run to ensure that when new realms are created
    902 // they have allocation logging turned on.
    903 void JSRuntime::ensureRealmIsRecordingAllocations(
    904    Handle<GlobalObject*> global) {
    905  if (recordAllocationCallback) {
    906    if (!global->realm()->isRecordingAllocations()) {
    907      // This is a new realm, turn on allocations for it.
    908      global->realm()->setAllocationMetadataBuilder(
    909          &SavedStacks::metadataBuilder);
    910    }
    911    // Ensure the probability is up to date with the current combination of
    912    // debuggers and runtime profiling.
    913    global->realm()->chooseAllocationSamplingProbability();
    914  }
    915 }