LCOV - code coverage report
Current view: top level - js/src/vm - Runtime.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 103 335 30.7 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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 "mozilla/ArrayUtils.h"
       8             : #include "mozilla/Atomics.h"
       9             : #include "mozilla/DebugOnly.h"
      10             : #include "mozilla/MemoryReporting.h"
      11             : #include "mozilla/ThreadLocal.h"
      12             : #include "mozilla/Unused.h"
      13             : 
      14             : #if defined(XP_DARWIN)
      15             : # include <mach/mach.h>
      16             : #elif defined(XP_UNIX)
      17             : # include <sys/resource.h>
      18             : #endif // defined(XP_DARWIN) || defined(XP_UNIX) || defined(XP_WIN)
      19             : #include <locale.h>
      20             : #include <string.h>
      21             : #ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
      22             : # include <sys/mman.h>
      23             : #endif
      24             : 
      25             : #include "jsfriendapi.h"
      26             : #include "jsmath.h"
      27             : 
      28             : #include "builtin/Promise.h"
      29             : #include "gc/FreeOp.h"
      30             : #include "gc/GCInternals.h"
      31             : #include "gc/PublicIterators.h"
      32             : #include "jit/arm/Simulator-arm.h"
      33             : #include "jit/arm64/vixl/Simulator-vixl.h"
      34             : #include "jit/IonBuilder.h"
      35             : #include "jit/JitRealm.h"
      36             : #include "jit/mips32/Simulator-mips32.h"
      37             : #include "jit/mips64/Simulator-mips64.h"
      38             : #include "js/Date.h"
      39             : #include "js/MemoryMetrics.h"
      40             : #include "js/SliceBudget.h"
      41             : #include "js/Wrapper.h"
      42             : #include "util/Windows.h"
      43             : #include "vm/Debugger.h"
      44             : #include "vm/JSAtom.h"
      45             : #include "vm/JSObject.h"
      46             : #include "vm/JSScript.h"
      47             : #include "vm/TraceLogging.h"
      48             : #include "vm/TraceLoggingGraph.h"
      49             : 
      50             : #include "gc/GC-inl.h"
      51             : #include "vm/JSContext-inl.h"
      52             : 
      53             : using namespace js;
      54             : using namespace js::gc;
      55             : 
      56             : using mozilla::Atomic;
      57             : using mozilla::DebugOnly;
      58             : using mozilla::NegativeInfinity;
      59             : using mozilla::PodZero;
      60             : using mozilla::PositiveInfinity;
      61             : using JS::DoubleNaNValue;
      62             : 
      63             : /* static */ MOZ_THREAD_LOCAL(JSContext*) js::TlsContext;
      64             : /* static */ Atomic<size_t> JSRuntime::liveRuntimesCount;
      65             : Atomic<JS::LargeAllocationFailureCallback> js::OnLargeAllocationFailure;
      66             : 
      67             : namespace js {
      68             :     bool gCanUseExtraThreads = true;
      69             : } // namespace js
      70             : 
      71             : void
      72           0 : js::DisableExtraThreads()
      73             : {
      74           0 :     gCanUseExtraThreads = false;
      75           0 : }
      76             : 
      77             : const JSSecurityCallbacks js::NullSecurityCallbacks = { };
      78             : 
      79             : static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
      80             :     TransparentObjectWrapper,
      81             :     nullptr
      82             : };
      83             : 
      84             : static size_t
      85           0 : ReturnZeroSize(const void* p)
      86             : {
      87           0 :     return 0;
      88             : }
      89             : 
      90           0 : JSRuntime::JSRuntime(JSRuntime* parentRuntime)
      91             :   : parentRuntime(parentRuntime),
      92             : #ifdef DEBUG
      93             :     updateChildRuntimeCount(parentRuntime),
      94             :     initialized_(false),
      95             : #endif
      96             :     mainContext_(nullptr),
      97             :     profilerSampleBufferRangeStart_(0),
      98             :     telemetryCallback(nullptr),
      99             :     consumeStreamCallback(nullptr),
     100             :     readableStreamDataRequestCallback(nullptr),
     101             :     readableStreamWriteIntoReadRequestCallback(nullptr),
     102             :     readableStreamCancelCallback(nullptr),
     103             :     readableStreamClosedCallback(nullptr),
     104             :     readableStreamErroredCallback(nullptr),
     105             :     readableStreamFinalizeCallback(nullptr),
     106             :     hadOutOfMemory(false),
     107             :     allowRelazificationForTesting(false),
     108             :     destroyCompartmentCallback(nullptr),
     109             :     sizeOfIncludingThisCompartmentCallback(nullptr),
     110             :     destroyRealmCallback(nullptr),
     111             :     realmNameCallback(nullptr),
     112             :     externalStringSizeofCallback(nullptr),
     113             :     securityCallbacks(&NullSecurityCallbacks),
     114             :     DOMcallbacks(nullptr),
     115             :     destroyPrincipals(nullptr),
     116             :     readPrincipals(nullptr),
     117             :     warningReporter(nullptr),
     118           4 :     geckoProfiler_(thisFromCtor()),
     119             :     buildIdOp(nullptr),
     120             :     trustedPrincipals_(nullptr),
     121             :     wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
     122             :     preserveWrapperCallback(nullptr),
     123             :     scriptEnvironmentPreparer(nullptr),
     124             :     ctypesActivityCallback(nullptr),
     125             :     windowProxyClass_(nullptr),
     126             :     exclusiveAccessLock(mutexid::RuntimeExclusiveAccess),
     127             : #ifdef DEBUG
     128             :     activeThreadHasExclusiveAccess(false),
     129             : #endif
     130             :     scriptDataLock(mutexid::RuntimeScriptData),
     131             : #ifdef DEBUG
     132             :     activeThreadHasScriptDataAccess(false),
     133             : #endif
     134             :     numActiveHelperThreadZones(0),
     135             :     heapState_(JS::HeapState::Idle),
     136             :     numRealms(0),
     137             :     localeCallbacks(nullptr),
     138             :     defaultLocale(nullptr),
     139             :     profilingScripts(false),
     140             :     scriptAndCountsVector(nullptr),
     141             :     lcovOutput_(),
     142             :     jitRuntime_(nullptr),
     143             :     selfHostingGlobal_(nullptr),
     144             :     gc(thisFromCtor()),
     145             :     gcInitialized(false),
     146           4 :     NaNValue(DoubleNaNValue()),
     147           0 :     negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
     148             :     positiveInfinityValue(DoubleValue(PositiveInfinity<double>())),
     149             :     emptyString(nullptr),
     150             :     defaultFreeOp_(nullptr),
     151             : #if !EXPOSE_INTL_API
     152             :     thousandsSeparator(nullptr),
     153             :     decimalSeparator(nullptr),
     154             :     numGrouping(nullptr),
     155             : #endif
     156             :     beingDestroyed_(false),
     157             :     allowContentJS_(true),
     158             :     atoms_(nullptr),
     159             :     atomsAddedWhileSweeping_(nullptr),
     160             :     staticStrings(nullptr),
     161             :     commonNames(nullptr),
     162             :     permanentAtoms(nullptr),
     163             :     wellKnownSymbols(nullptr),
     164             :     jitSupportsFloatingPoint(false),
     165             :     jitSupportsUnalignedAccesses(false),
     166             :     jitSupportsSimd(false),
     167             :     offthreadIonCompilationEnabled_(true),
     168             :     parallelParsingEnabled_(true),
     169             :     autoWritableJitCodeActive_(false),
     170             :     oomCallback(nullptr),
     171             :     debuggerMallocSizeOf(ReturnZeroSize),
     172             :     lastAnimationTime(0),
     173             :     performanceMonitoring_(),
     174             :     stackFormat_(parentRuntime ? js::StackFormat::Default
     175             :                                : js::StackFormat::SpiderMonkey),
     176             :     wasmInstances(mutexid::WasmRuntimeInstances),
     177         352 :     moduleResolveHook(),
     178             :     moduleMetadataHook()
     179           4 : {
     180           0 :     JS_COUNT_CTOR(JSRuntime);
     181             :     liveRuntimesCount++;
     182           4 : 
     183           0 :     lcovOutput().init();
     184             : }
     185           0 : 
     186             : JSRuntime::~JSRuntime()
     187           0 : {
     188           0 :     JS_COUNT_DTOR(JSRuntime);
     189             :     MOZ_ASSERT(!initialized_);
     190           0 : 
     191           0 :     DebugOnly<size_t> oldCount = liveRuntimesCount--;
     192             :     MOZ_ASSERT(oldCount > 0);
     193           0 : 
     194           0 :     MOZ_ASSERT(wasmInstances.lock()->empty());
     195             : }
     196             : 
     197           4 : bool
     198             : JSRuntime::init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes)
     199             : {
     200           8 : #ifdef DEBUG
     201           0 :     MOZ_ASSERT(!initialized_);
     202             :     initialized_ = true;
     203             : #endif
     204           4 : 
     205             :     if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized())
     206             :         return false;
     207           4 : 
     208             :     mainContext_ = cx;
     209           8 : 
     210           0 :     defaultFreeOp_ = js_new<js::FreeOp>(this);
     211             :     if (!defaultFreeOp_)
     212             :         return false;
     213           4 : 
     214             :     if (!gc.init(maxbytes, maxNurseryBytes))
     215             :         return false;
     216          12 : 
     217           0 :     UniquePtr<Zone> atomsZone = MakeUnique<Zone>(this);
     218             :     if (!atomsZone || !atomsZone->init(true))
     219             :         return false;
     220           8 : 
     221             :     gc.atomsZone = atomsZone.release();
     222           8 : 
     223             :     if (!symbolRegistry_.ref().init())
     224             :         return false;
     225           8 : 
     226             :     if (!scriptDataTable_.ref().init())
     227             :         return false;
     228             : 
     229           8 :     /* The garbage collector depends on everything before this point being initialized. */
     230             :     gcInitialized = true;
     231           4 : 
     232             :     if (!InitRuntimeNumberState(this))
     233             :         return false;
     234           4 : 
     235             :     JS::ResetTimeZone();
     236           8 : 
     237           0 :     jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint();
     238           0 :     jitSupportsUnalignedAccesses = js::jit::JitSupportsUnalignedAccesses();
     239             :     jitSupportsSimd = js::jit::JitSupportsSimd();
     240           4 : 
     241             :     if (!geckoProfiler().init())
     242             :         return false;
     243           4 : 
     244           0 :     if (!parentRuntime) {
     245           0 :         sharedImmutableStrings_ = js::SharedImmutableStringsCache::Create();
     246             :         if (!sharedImmutableStrings_)
     247             :             return false;
     248             :     }
     249           4 : 
     250             :     if (!caches().init())
     251             :         return false;
     252           4 : 
     253             :     return true;
     254             : }
     255             : 
     256           0 : void
     257             : JSRuntime::destroyRuntime()
     258           0 : {
     259           0 :     MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
     260           0 :     MOZ_ASSERT(childRuntimeCount == 0);
     261             :     MOZ_ASSERT(initialized_);
     262           0 : 
     263             :     sharedIntlData.ref().destroyInstance();
     264           0 : 
     265             :     if (gcInitialized) {
     266             :         /*
     267             :          * Finish any in-progress GCs first. This ensures the parseWaitingOnGC
     268             :          * list is empty in CancelOffThreadParses.
     269           0 :          */
     270           0 :         JSContext* cx = mainContextFromOwnThread();
     271           0 :         if (JS::IsIncrementalGCInProgress(cx))
     272             :             FinishGC(cx);
     273             : 
     274           0 :         /* Free source hook early, as its destructor may want to delete roots. */
     275             :         sourceHook = nullptr;
     276             : 
     277             :         /*
     278             :          * Cancel any pending, in progress or completed Ion compilations and
     279             :          * parse tasks. Waiting for wasm and compression tasks is done
     280             :          * synchronously (on the main thread or during parse tasks), so no
     281             :          * explicit canceling is needed for these.
     282           0 :          */
     283           0 :         CancelOffThreadIonCompile(this);
     284           0 :         CancelOffThreadParses(this);
     285             :         CancelOffThreadCompressions(this);
     286             : 
     287           0 :         /* Remove persistent GC roots. */
     288             :         gc.finishRoots();
     289             : 
     290             :         /*
     291             :          * Flag us as being destroyed. This allows the GC to free things like
     292             :          * interned atoms and Ion trampolines.
     293           0 :          */
     294             :         beingDestroyed_ = true;
     295             : 
     296           0 :         /* Allow the GC to release scripts that were being profiled. */
     297             :         profilingScripts = false;
     298           0 : 
     299           0 :         JS::PrepareForFullGC(cx);
     300             :         gc.gc(GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
     301             :     }
     302           0 : 
     303             :     AutoNoteSingleThreadedRegion anstr;
     304           0 : 
     305             :     MOZ_ASSERT(!hasHelperThreadZones());
     306             : 
     307             :     /*
     308             :      * Even though all objects in the compartment are dead, we may have keep
     309             :      * some filenames around because of gcKeepAtoms.
     310           0 :      */
     311             :     FreeScriptData(this);
     312             : 
     313             : #if !EXPOSE_INTL_API
     314             :     FinishRuntimeNumberState(this);
     315             : #endif
     316           0 : 
     317             :     gc.finish();
     318           0 : 
     319             :     js_delete(defaultFreeOp_.ref());
     320           0 : 
     321           0 :     js_free(defaultLocale);
     322             :     js_delete(jitRuntime_.ref());
     323             : 
     324           0 : #ifdef DEBUG
     325             :     initialized_ = false;
     326           0 : #endif
     327             : }
     328             : 
     329          24 : void
     330             : JSRuntime::addTelemetry(int id, uint32_t sample, const char* key)
     331          48 : {
     332           0 :     if (telemetryCallback)
     333           0 :         (*telemetryCallback)(id, sample, key);
     334             : }
     335             : 
     336           1 : void
     337             : JSRuntime::setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback)
     338           2 : {
     339           0 :     rt->telemetryCallback = callback;
     340             : }
     341             : 
     342           0 : void
     343             : JSRuntime::setUseCounter(JSObject* obj, JSUseCounter counter)
     344           0 : {
     345           0 :     if (useCounterCallback)
     346           0 :         (*useCounterCallback)(obj, counter);
     347             : }
     348             : 
     349           1 : void
     350             : JSRuntime::setUseCounterCallback(JSRuntime* rt, JSSetUseCounterCallback callback)
     351           2 : {
     352           0 :     rt->useCounterCallback = callback;
     353             : }
     354             : 
     355           0 : void
     356             : JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes)
     357           0 : {
     358             :     rtSizes->object += mallocSizeOf(this);
     359             : 
     360           0 :     {
     361           0 :         AutoLockForExclusiveAccess lock(this);
     362           0 :         rtSizes->atomsTable += atoms(lock).sizeOfIncludingThis(mallocSizeOf);
     363             :         rtSizes->gc.marker += gc.marker.sizeOfExcludingThis(mallocSizeOf, lock);
     364             :     }
     365           0 : 
     366           0 :     if (!parentRuntime) {
     367           0 :         rtSizes->atomsTable += mallocSizeOf(staticStrings);
     368           0 :         rtSizes->atomsTable += mallocSizeOf(commonNames);
     369             :         rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
     370             :     }
     371           0 : 
     372           0 :     JSContext* cx = mainContextFromAnyThread();
     373           0 :     rtSizes->contexts += mallocSizeOf(cx);
     374           0 :     rtSizes->contexts += cx->sizeOfExcludingThis(mallocSizeOf);
     375           0 :     rtSizes->temporary += cx->tempLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
     376             :     rtSizes->interpreterStack += cx->interpreterStack().sizeOfExcludingThis(mallocSizeOf);
     377           0 : #ifdef JS_TRACE_LOGGING
     378           0 :     if (cx->traceLogger)
     379             :         rtSizes->tracelogger += cx->traceLogger->sizeOfIncludingThis(mallocSizeOf);
     380             : #endif
     381           0 : 
     382           0 :     if (MathCache* cache = caches().maybeGetMathCache())
     383             :         rtSizes->mathCache += cache->sizeOfIncludingThis(mallocSizeOf);
     384           0 : 
     385           0 :     rtSizes->uncompressedSourceCache +=
     386             :         caches().uncompressedSourceCache.sizeOfExcludingThis(mallocSizeOf);
     387           0 : 
     388           0 :     rtSizes->gc.nurseryCommitted += gc.nursery().sizeOfHeapCommitted();
     389           0 :     rtSizes->gc.nurseryMallocedBuffers += gc.nursery().sizeOfMallocedBuffers(mallocSizeOf);
     390             :     gc.storeBuffer().addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc);
     391           0 : 
     392           0 :     if (sharedImmutableStrings_) {
     393           0 :         rtSizes->sharedImmutableStringsCache +=
     394             :             sharedImmutableStrings_->sizeOfExcludingThis(mallocSizeOf);
     395             :     }
     396           0 : 
     397             :     rtSizes->sharedIntlData += sharedIntlData.ref().sizeOfExcludingThis(mallocSizeOf);
     398             : 
     399           0 :     {
     400           0 :         AutoLockScriptData lock(this);
     401           0 :         rtSizes->scriptData += scriptDataTable(lock).sizeOfExcludingThis(mallocSizeOf);
     402           0 :         for (ScriptDataTable::Range r = scriptDataTable(lock).all(); !r.empty(); r.popFront())
     403             :             rtSizes->scriptData += mallocSizeOf(r.front());
     404             :     }
     405           0 : 
     406           0 :     if (jitRuntime_) {
     407             :         jitRuntime_->execAlloc().addSizeOfCode(&rtSizes->code);
     408             : 
     409           0 :         // Sizes of the IonBuilders we are holding for lazy linking
     410           0 :         for (auto builder : jitRuntime_->ionLazyLinkList(this))
     411             :             rtSizes->jitLazyLink += builder->sizeOfExcludingThis(mallocSizeOf);
     412             :     }
     413           0 : 
     414           0 :     rtSizes->wasmRuntime += wasmInstances.lock()->sizeOfExcludingThis(mallocSizeOf);
     415             : }
     416             : 
     417          51 : static bool
     418             : HandleInterrupt(JSContext* cx, bool invokeCallback)
     419         102 : {
     420           0 :     MOZ_ASSERT(cx->requestDepth >= 1);
     421             :     MOZ_ASSERT(!cx->zone()->isAtomsZone());
     422         102 : 
     423             :     cx->runtime()->gc.gcIfRequested();
     424             : 
     425             :     // A worker thread may have requested an interrupt after finishing an Ion
     426          51 :     // compilation.
     427             :     jit::AttachFinishedCompilations(cx);
     428             : 
     429          51 :     // Don't call the interrupt callback if we only interrupted for GC or Ion.
     430             :     if (!invokeCallback)
     431             :         return true;
     432             : 
     433             :     // Important: Additional callbacks can occur inside the callback handler
     434             :     // if it re-enters the JS engine. The embedding must ensure that the
     435           2 :     // callback is disconnected before attempting such re-entry.
     436             :     if (cx->interruptCallbackDisabled)
     437             :         return true;
     438           1 : 
     439           0 :     bool stop = false;
     440           0 :     for (JSInterruptCallback cb : cx->interruptCallbacks()) {
     441           0 :         if (!cb(cx))
     442             :             stop = true;
     443             :     }
     444           1 : 
     445             :     if (!stop) {
     446             :         // Debugger treats invoking the interrupt callback as a "step", so
     447           3 :         // invoke the onStep handler.
     448           0 :         if (cx->realm()->isDebuggee()) {
     449           0 :             ScriptFrameIter iter(cx);
     450           0 :             if (!iter.done() &&
     451           0 :                 cx->compartment() == iter.compartment() &&
     452             :                 iter.script()->stepModeEnabled())
     453           0 :             {
     454           0 :                 RootedValue rval(cx);
     455             :                 switch (Debugger::onSingleStep(cx, &rval)) {
     456           0 :                   case ResumeMode::Terminate:
     457             :                     return false;
     458           0 :                   case ResumeMode::Continue:
     459             :                     return true;
     460             :                   case ResumeMode::Return:
     461           0 :                     // See note in Debugger::propagateForcedReturn.
     462           0 :                     Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
     463             :                     return false;
     464           0 :                   case ResumeMode::Throw:
     465           0 :                     cx->setPendingException(rval);
     466             :                     return false;
     467             :                   default:;
     468             :                 }
     469             :             }
     470             :         }
     471             : 
     472             :         return true;
     473             :     }
     474             : 
     475             :     // No need to set aside any pending exception here: ComputeStackString
     476           0 :     // already does that.
     477           0 :     JSString* stack = ComputeStackString(cx);
     478             :     JSFlatString* flat = stack ? stack->ensureFlat(cx) : nullptr;
     479             : 
     480           0 :     const char16_t* chars;
     481           0 :     AutoStableStringChars stableChars(cx);
     482           0 :     if (flat && stableChars.initTwoByte(cx, flat))
     483             :         chars = stableChars.twoByteRange().begin().get();
     484             :     else
     485             :         chars = u"(stack not available)";
     486           0 :     JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
     487             :                                    JSMSG_TERMINATED, chars);
     488           0 : 
     489             :     return false;
     490             : }
     491             : 
     492          52 : void
     493             : JSContext::requestInterrupt(InterruptReason reason)
     494         104 : {
     495           0 :     interruptBits_ |= uint32_t(reason);
     496             :     jitStackLimit = UINTPTR_MAX;
     497          52 : 
     498             :     if (reason == InterruptReason::CallbackUrgent) {
     499             :         // If this interrupt is urgent (slow script dialog for instance), take
     500             :         // additional steps to interrupt corner cases where the above fields are
     501           1 :         // not regularly polled.
     502           0 :         FutexThread::lock();
     503           0 :         if (fx.isWaiting())
     504           1 :             fx.wake(FutexThread::WakeForJSInterrupt);
     505           0 :         fx.unlock();
     506             :         wasm::InterruptRunningCode(this);
     507          52 :     }
     508             : }
     509             : 
     510          51 : bool
     511             : JSContext::handleInterrupt()
     512         102 : {
     513           0 :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
     514             :     if (hasAnyPendingInterrupt() || jitStackLimit == UINTPTR_MAX) {
     515         101 :         bool invokeCallback =
     516           0 :             hasPendingInterrupt(InterruptReason::CallbackUrgent) ||
     517           0 :             hasPendingInterrupt(InterruptReason::CallbackCanWait);
     518           0 :         interruptBits_ = 0;
     519           0 :         resetJitStackLimit();
     520             :         return HandleInterrupt(this, invokeCallback);
     521             :     }
     522             :     return true;
     523             : }
     524             : 
     525           4 : bool
     526             : JSRuntime::setDefaultLocale(const char* locale)
     527           4 : {
     528             :     if (!locale)
     529             :         return false;
     530           0 : 
     531           0 :     char* newLocale = DuplicateString(mainContextFromOwnThread(), locale).release();
     532             :     if (!newLocale)
     533             :         return false;
     534           4 : 
     535           8 :     resetDefaultLocale();
     536           0 :     defaultLocale = newLocale;
     537             :     return true;
     538             : }
     539             : 
     540           0 : void
     541             : JSRuntime::resetDefaultLocale()
     542          12 : {
     543           0 :     js_free(defaultLocale);
     544           4 :     defaultLocale = nullptr;
     545             : }
     546             : 
     547           3 : const char*
     548             : JSRuntime::getDefaultLocale()
     549           6 : {
     550           6 :     if (defaultLocale)
     551             :         return defaultLocale;
     552           0 : 
     553             :     const char* locale = setlocale(LC_ALL, nullptr);
     554             : 
     555           0 :     // convert to a well-formed BCP 47 language tag
     556           0 :     if (!locale || !strcmp(locale, "C"))
     557             :         locale = "und";
     558           0 : 
     559           0 :     char* lang = DuplicateString(mainContextFromOwnThread(), locale).release();
     560             :     if (!lang)
     561             :         return nullptr;
     562             : 
     563           0 :     char* p;
     564           0 :     if ((p = strchr(lang, '.')))
     565           0 :         *p = '\0';
     566           0 :     while ((p = strchr(lang, '_')))
     567             :         *p = '-';
     568           0 : 
     569           0 :     defaultLocale = lang;
     570             :     return defaultLocale;
     571             : }
     572             : 
     573           4 : void
     574             : JSRuntime::traceSharedIntlData(JSTracer* trc)
     575           0 : {
     576           4 :     sharedIntlData.ref().trace(trc);
     577             : }
     578             : 
     579        2343 : void
     580             : JSContext::triggerActivityCallback(bool active)
     581        4686 : {
     582           9 :     if (!activityCallback)
     583             :         return;
     584             : 
     585             :     /*
     586             :      * The activity callback must not trigger a GC: it would create a cirular
     587             :      * dependency between entering a request and Rooted's requirement of being
     588             :      * in a request. In practice this callback already cannot trigger GC. The
     589             :      * suppression serves to inform the exact rooting hazard analysis of this
     590             :      * property and ensures that it remains true in the future.
     591        4668 :      */
     592             :     AutoSuppressGC suppress(this);
     593           0 : 
     594             :     activityCallback(activityCallbackArg, active);
     595             : }
     596           0 : 
     597          16 : FreeOp::FreeOp(JSRuntime* maybeRuntime)
     598             :   : JSFreeOp(maybeRuntime)
     599           8 : {
     600           0 :     MOZ_ASSERT_IF(maybeRuntime, CurrentThreadCanAccessRuntime(maybeRuntime));
     601             : }
     602           0 : 
     603             : FreeOp::~FreeOp()
     604           0 : {
     605           0 :     for (size_t i = 0; i < freeLaterList.length(); i++)
     606             :         free_(freeLaterList[i]);
     607           0 : 
     608           0 :     if (!jitPoisonRanges.empty())
     609           0 :         jit::ExecutableAllocator::poisonCode(runtime(), jitPoisonRanges);
     610             : }
     611             : 
     612           0 : bool
     613             : FreeOp::isDefaultFreeOp() const
     614           0 : {
     615             :     return runtime_ && runtime_->defaultFreeOp() == this;
     616             : }
     617             : 
     618           0 : JSObject*
     619             : JSRuntime::getIncumbentGlobal(JSContext* cx)
     620             : {
     621             :     // If the embedding didn't set a callback for getting the incumbent
     622        8790 :     // global, the currently active global is used.
     623           0 :     if (!cx->getIncumbentGlobalCallback) {
     624             :         if (!cx->compartment())
     625           0 :             return nullptr;
     626             :         return cx->global();
     627             :     }
     628           0 : 
     629             :     return cx->getIncumbentGlobalCallback(cx);
     630             : }
     631             : 
     632        4170 : bool
     633             : JSRuntime::enqueuePromiseJob(JSContext* cx, HandleFunction job, HandleObject promise,
     634             :                              HandleObject incumbentGlobal)
     635           0 : {
     636             :     MOZ_ASSERT(cx->enqueuePromiseJobCallback,
     637           0 :                "Must set a callback using JS::SetEnqueuePromiseJobCallback before using Promises");
     638             :     MOZ_ASSERT_IF(incumbentGlobal, !IsWrapper(incumbentGlobal) && !IsWindowProxy(incumbentGlobal));
     639        8340 : 
     640        8340 :     void* data = cx->enqueuePromiseJobCallbackData;
     641        4170 :     RootedObject allocationSite(cx);
     642           0 :     if (promise) {
     643             :         RootedObject unwrappedPromise(cx, promise);
     644             :         // While the job object is guaranteed to be unwrapped, the promise
     645             :         // might be wrapped. See the comments in
     646        4075 :         // intrinsic_EnqueuePromiseReactionJob for details.
     647           0 :         if (IsWrapper(promise))
     648        8150 :             unwrappedPromise = UncheckedUnwrap(promise);
     649        8150 :         if (unwrappedPromise->is<PromiseObject>())
     650             :             allocationSite = JS::GetPromiseAllocationSite(unwrappedPromise);
     651           0 :     }
     652             :     return cx->enqueuePromiseJobCallback(cx, job, allocationSite, incumbentGlobal, data);
     653             : }
     654             : 
     655           2 : void
     656             : JSRuntime::addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise)
     657           0 : {
     658           4 :     MOZ_ASSERT(promise->is<PromiseObject>());
     659             :     if (!cx->promiseRejectionTrackerCallback)
     660             :         return;
     661           4 : 
     662             :     void* data = cx->promiseRejectionTrackerCallbackData;
     663           0 :     cx->promiseRejectionTrackerCallback(cx, promise,
     664             :                                         JS::PromiseRejectionHandlingState::Unhandled, data);
     665             : }
     666             : 
     667           1 : void
     668             : JSRuntime::removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise)
     669           0 : {
     670           2 :     MOZ_ASSERT(promise->is<PromiseObject>());
     671             :     if (!cx->promiseRejectionTrackerCallback)
     672             :         return;
     673           2 : 
     674             :     void* data = cx->promiseRejectionTrackerCallbackData;
     675           0 :     cx->promiseRejectionTrackerCallback(cx, promise,
     676             :                                         JS::PromiseRejectionHandlingState::Handled, data);
     677             : }
     678             : 
     679           0 : mozilla::non_crypto::XorShift128PlusRNG&
     680             : JSRuntime::randomKeyGenerator()
     681           0 : {
     682          68 :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
     683           0 :     if (randomKeyGenerator_.isNothing()) {
     684           4 :         mozilla::Array<uint64_t, 2> seed;
     685           4 :         GenerateXorShift128PlusSeed(seed);
     686             :         randomKeyGenerator_.emplace(seed[0], seed[1]);
     687           0 :     }
     688             :     return randomKeyGenerator_.ref();
     689             : }
     690             : 
     691          21 : mozilla::HashCodeScrambler
     692             : JSRuntime::randomHashCodeScrambler()
     693          21 : {
     694           0 :     auto& rng = randomKeyGenerator();
     695             :     return mozilla::HashCodeScrambler(rng.next(), rng.next());
     696             : }
     697             : 
     698          47 : mozilla::non_crypto::XorShift128PlusRNG
     699             : JSRuntime::forkRandomKeyGenerator()
     700          47 : {
     701           0 :     auto& rng = randomKeyGenerator();
     702             :     return mozilla::non_crypto::XorShift128PlusRNG(rng.next(), rng.next());
     703             : }
     704             : 
     705           0 : js::HashNumber
     706             : JSRuntime::randomHashCode()
     707           0 : {
     708             :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
     709          24 : 
     710           1 :     if (randomHashCodeGenerator_.isNothing()) {
     711           0 :         mozilla::Array<uint64_t, 2> seed;
     712           1 :         GenerateXorShift128PlusSeed(seed);
     713             :         randomHashCodeGenerator_.emplace(seed[0], seed[1]);
     714             :     }
     715           0 : 
     716             :     return HashNumber(randomHashCodeGenerator_->next());
     717             : }
     718             : 
     719          66 : void
     720             : JSRuntime::updateMallocCounter(size_t nbytes)
     721           0 : {
     722          66 :     gc.updateMallocCounter(nbytes);
     723             : }
     724             : 
     725           0 : JS_FRIEND_API(void*)
     726             : JSRuntime::onOutOfMemory(AllocFunction allocFunc, size_t nbytes, void* reallocPtr, JSContext* maybecx)
     727           0 : {
     728             :     MOZ_ASSERT_IF(allocFunc != AllocFunction::Realloc, !reallocPtr);
     729           0 : 
     730             :     if (JS::RuntimeHeapIsBusy())
     731             :         return nullptr;
     732           0 : 
     733             :     if (!oom::IsSimulatedOOMAllocation()) {
     734             :         /*
     735             :          * Retry when we are done with the background sweeping and have stopped
     736             :          * all the allocations and released the empty GC chunks.
     737           0 :          */
     738             :         gc.onOutOfMallocMemory();
     739           0 :         void* p;
     740             :         switch (allocFunc) {
     741           0 :           case AllocFunction::Malloc:
     742           0 :             p = js_malloc(nbytes);
     743             :             break;
     744           0 :           case AllocFunction::Calloc:
     745           0 :             p = js_calloc(nbytes);
     746             :             break;
     747           0 :           case AllocFunction::Realloc:
     748           0 :             p = js_realloc(reallocPtr, nbytes);
     749             :             break;
     750           0 :           default:
     751             :             MOZ_CRASH();
     752           0 :         }
     753             :         if (p)
     754             :             return p;
     755             :     }
     756           0 : 
     757           0 :     if (maybecx)
     758             :         ReportOutOfMemory(maybecx);
     759             :     return nullptr;
     760             : }
     761             : 
     762           0 : void*
     763             : JSRuntime::onOutOfMemoryCanGC(AllocFunction allocFunc, size_t bytes, void* reallocPtr)
     764           0 : {
     765           0 :     if (OnLargeAllocationFailure && bytes >= LARGE_ALLOCATION)
     766           0 :         OnLargeAllocationFailure();
     767             :     return onOutOfMemory(allocFunc, bytes, reallocPtr);
     768             : }
     769             : 
     770           0 : bool
     771             : JSRuntime::activeGCInAtomsZone()
     772          15 : {
     773          30 :     Zone* zone = unsafeAtomsZone();
     774           0 :     return (zone->needsIncrementalBarrier() && !gc.isVerifyPreBarriersEnabled()) ||
     775             :            zone->wasGCStarted();
     776             : }
     777             : 
     778           0 : bool
     779             : JSRuntime::createAtomsAddedWhileSweepingTable()
     780           0 : {
     781           0 :     MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
     782             :     MOZ_ASSERT(!atomsAddedWhileSweeping_);
     783           0 : 
     784           0 :     atomsAddedWhileSweeping_ = js_new<AtomSet>();
     785             :     if (!atomsAddedWhileSweeping_)
     786             :         return false;
     787           0 : 
     788           0 :     if (!atomsAddedWhileSweeping_->init()) {
     789           0 :         destroyAtomsAddedWhileSweepingTable();
     790             :         return false;
     791             :     }
     792             : 
     793             :     return true;
     794             : }
     795             : 
     796           0 : void
     797             : JSRuntime::destroyAtomsAddedWhileSweepingTable()
     798           0 : {
     799           0 :     MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
     800             :     MOZ_ASSERT(atomsAddedWhileSweeping_);
     801           0 : 
     802           0 :     js_delete(atomsAddedWhileSweeping_.ref());
     803           0 :     atomsAddedWhileSweeping_ = nullptr;
     804             : }
     805             : 
     806           0 : void
     807             : JSRuntime::setUsedByHelperThread(Zone* zone)
     808           0 : {
     809          10 :     MOZ_ASSERT(!zone->usedByHelperThread());
     810           5 :     MOZ_ASSERT(!zone->wasGCStarted());
     811           0 :     zone->setUsedByHelperThread();
     812           5 :     numActiveHelperThreadZones++;
     813             : }
     814             : 
     815           0 : void
     816             : JSRuntime::clearUsedByHelperThread(Zone* zone)
     817           0 : {
     818           0 :     MOZ_ASSERT(zone->usedByHelperThread());
     819           0 :     zone->clearUsedByHelperThread();
     820           5 :     numActiveHelperThreadZones--;
     821          10 :     JSContext* cx = mainContextFromOwnThread();
     822           0 :     if (gc.fullGCForAtomsRequested() && cx->canCollectAtoms())
     823           5 :         gc.triggerFullGCForAtoms(cx);
     824             : }
     825             : 
     826    55022313 : bool
     827             : js::CurrentThreadCanAccessRuntime(const JSRuntime* rt)
     828           0 : {
     829             :     return rt->mainContextFromAnyThread() == TlsContext.get();
     830             : }
     831             : 
     832           0 : bool
     833             : js::CurrentThreadCanAccessZone(Zone* zone)
     834             : {
     835           0 :     // Helper thread zones can only be used by their owning thread.
     836        6817 :     if (zone->usedByHelperThread())
     837             :         return zone->ownedByCurrentHelperThread();
     838             : 
     839     9476538 :     // Other zones can only be accessed by the runtime's active context.
     840             :     return CurrentThreadCanAccessRuntime(zone->runtime_);
     841             : }
     842             : 
     843             : #ifdef DEBUG
     844           1 : bool
     845             : js::CurrentThreadIsPerformingGC()
     846           2 : {
     847             :     return TlsContext.get()->performingGC;
     848             : }
     849             : #endif
     850             : 
     851           0 : JS_FRIEND_API(void)
     852             : JS::SetJSContextProfilerSampleBufferRangeStart(JSContext* cx, uint64_t rangeStart)
     853           0 : {
     854           0 :     cx->runtime()->setProfilerSampleBufferRangeStart(rangeStart);
     855             : }
     856             : 
     857           0 : JS_FRIEND_API(bool)
     858             : JS::IsProfilingEnabledForContext(JSContext* cx)
     859           0 : {
     860           0 :     MOZ_ASSERT(cx);
     861             :     return cx->runtime()->geckoProfiler().enabled();
     862             : }
     863             : 
     864             : JS_PUBLIC_API(void)
     865             : JS::shadow::RegisterWeakCache(JSRuntime* rt, detail::WeakCacheBase* cachep)
     866             : {
     867             :     rt->registerWeakCache(cachep);
     868             : }

Generated by: LCOV version 1.13-14-ga5dd952