LCOV - code coverage report
Current view: top level - js/src/vm - Runtime.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 162 406 39.9 %
Date: 2017-07-14 16:53:18 Functions: 26 48 54.2 %
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             : 
      20             : #include <locale.h>
      21             : #include <string.h>
      22             : 
      23             : #ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
      24             : # include <sys/mman.h>
      25             : #endif
      26             : 
      27             : #include "jsatom.h"
      28             : #include "jsgc.h"
      29             : #include "jsmath.h"
      30             : #include "jsobj.h"
      31             : #include "jsscript.h"
      32             : #include "jswatchpoint.h"
      33             : #include "jswin.h"
      34             : #include "jswrapper.h"
      35             : 
      36             : #include "builtin/Promise.h"
      37             : #include "gc/GCInternals.h"
      38             : #include "jit/arm/Simulator-arm.h"
      39             : #include "jit/arm64/vixl/Simulator-vixl.h"
      40             : #include "jit/JitCompartment.h"
      41             : #include "jit/mips32/Simulator-mips32.h"
      42             : #include "jit/mips64/Simulator-mips64.h"
      43             : #include "js/Date.h"
      44             : #include "js/MemoryMetrics.h"
      45             : #include "js/SliceBudget.h"
      46             : #include "vm/Debugger.h"
      47             : #include "vm/TraceLogging.h"
      48             : #include "vm/TraceLoggingGraph.h"
      49             : #include "wasm/WasmSignalHandlers.h"
      50             : 
      51             : #include "jscntxtinlines.h"
      52             : #include "jsgcinlines.h"
      53             : 
      54             : using namespace js;
      55             : using namespace js::gc;
      56             : 
      57             : using mozilla::Atomic;
      58             : using mozilla::DebugOnly;
      59             : using mozilla::NegativeInfinity;
      60             : using mozilla::PodZero;
      61             : using mozilla::PodArrayZero;
      62             : using mozilla::PositiveInfinity;
      63             : using JS::GenericNaN;
      64             : using JS::DoubleNaNValue;
      65             : 
      66             : /* static */ MOZ_THREAD_LOCAL(JSContext*) js::TlsContext;
      67             : /* static */ Atomic<size_t> JSRuntime::liveRuntimesCount;
      68             : Atomic<JS::LargeAllocationFailureCallback> js::OnLargeAllocationFailure;
      69             : 
      70             : namespace js {
      71             :     bool gCanUseExtraThreads = true;
      72             : } // namespace js
      73             : 
      74             : void
      75           0 : js::DisableExtraThreads()
      76             : {
      77           0 :     gCanUseExtraThreads = false;
      78           0 : }
      79             : 
      80             : const JSSecurityCallbacks js::NullSecurityCallbacks = { };
      81             : 
      82             : static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
      83             :     TransparentObjectWrapper,
      84             :     nullptr
      85             : };
      86             : 
      87             : static size_t
      88           0 : ReturnZeroSize(const void* p)
      89             : {
      90           0 :     return 0;
      91             : }
      92             : 
      93           4 : JSRuntime::JSRuntime(JSRuntime* parentRuntime)
      94             :   : parentRuntime(parentRuntime),
      95             : #ifdef DEBUG
      96             :     updateChildRuntimeCount(parentRuntime),
      97             :     initialized_(false),
      98             : #endif
      99             :     activeContext_(nullptr),
     100             :     activeContextChangeProhibited_(0),
     101             :     singleThreadedExecutionRequired_(0),
     102             :     startingSingleThreadedExecution_(false),
     103             :     beginSingleThreadedExecutionCallback(nullptr),
     104             :     endSingleThreadedExecutionCallback(nullptr),
     105             :     profilerSampleBufferGen_(0),
     106             :     profilerSampleBufferLapCount_(1),
     107             :     telemetryCallback(nullptr),
     108             :     startAsyncTaskCallback(nullptr),
     109             :     finishAsyncTaskCallback(nullptr),
     110             :     promiseTasksToDestroy(mutexid::PromiseTaskPtrVector),
     111             :     hadOutOfMemory(false),
     112             :     allowRelazificationForTesting(false),
     113             :     destroyCompartmentCallback(nullptr),
     114             :     sizeOfIncludingThisCompartmentCallback(nullptr),
     115             :     compartmentNameCallback(nullptr),
     116             :     externalStringSizeofCallback(nullptr),
     117           8 :     securityCallbacks(&NullSecurityCallbacks),
     118             :     DOMcallbacks(nullptr),
     119             :     destroyPrincipals(nullptr),
     120             :     readPrincipals(nullptr),
     121             :     warningReporter(nullptr),
     122           8 :     geckoProfiler_(thisFromCtor()),
     123             :     buildIdOp(nullptr),
     124             :     trustedPrincipals_(nullptr),
     125           8 :     wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
     126             :     preserveWrapperCallback(nullptr),
     127             :     scriptEnvironmentPreparer(nullptr),
     128             :     ctypesActivityCallback(nullptr),
     129             :     windowProxyClass_(nullptr),
     130             :     exclusiveAccessLock(mutexid::RuntimeExclusiveAccess),
     131             : #ifdef DEBUG
     132             :     activeThreadHasExclusiveAccess(false),
     133             : #endif
     134             :     numHelperThreadZones(0),
     135             :     numCompartments(0),
     136             :     localeCallbacks(nullptr),
     137             :     defaultLocale(nullptr),
     138             :     defaultVersion_(JSVERSION_DEFAULT),
     139             :     profilingScripts(false),
     140             :     scriptAndCountsVector(nullptr),
     141             :     lcovOutput_(),
     142             :     jitRuntime_(nullptr),
     143             :     selfHostingGlobal_(nullptr),
     144             :     gc(thisFromCtor()),
     145             :     gcInitialized(false),
     146             :     NaNValue(DoubleNaNValue()),
     147           4 :     negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
     148           4 :     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             :     atomsCompartment_(nullptr),
     161             :     staticStrings(nullptr),
     162             :     commonNames(nullptr),
     163             :     permanentAtoms(nullptr),
     164             :     wellKnownSymbols(nullptr),
     165             :     jitSupportsFloatingPoint(false),
     166             :     jitSupportsUnalignedAccesses(false),
     167             :     jitSupportsSimd(false),
     168             :     offthreadIonCompilationEnabled_(true),
     169             :     parallelParsingEnabled_(true),
     170             :     autoWritableJitCodeActive_(false),
     171             :     oomCallback(nullptr),
     172             :     debuggerMallocSizeOf(ReturnZeroSize),
     173             :     lastAnimationTime(0),
     174           8 :     performanceMonitoring_(thisFromCtor()),
     175             :     stackFormat_(parentRuntime ? js::StackFormat::Default
     176          44 :                                : js::StackFormat::SpiderMonkey)
     177             : {
     178           4 :     liveRuntimesCount++;
     179             : 
     180             :     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
     181             : 
     182           4 :     PodZero(&asmJSCacheOps);
     183           4 :     lcovOutput().init();
     184           4 : }
     185             : 
     186           0 : JSRuntime::~JSRuntime()
     187             : {
     188           0 :     MOZ_ASSERT(!initialized_);
     189             : 
     190           0 :     DebugOnly<size_t> oldCount = liveRuntimesCount--;
     191           0 :     MOZ_ASSERT(oldCount > 0);
     192           0 : }
     193             : 
     194             : bool
     195           4 : JSRuntime::init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes)
     196             : {
     197             : #ifdef DEBUG
     198           4 :     MOZ_ASSERT(!initialized_);
     199           4 :     initialized_ = true;
     200             : #endif
     201             : 
     202           4 :     if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized())
     203           0 :         return false;
     204             : 
     205           4 :     activeContext_ = cx;
     206           4 :     if (!cooperatingContexts().append(cx))
     207           0 :         return false;
     208             : 
     209           4 :     defaultFreeOp_ = js_new<js::FreeOp>(this);
     210           4 :     if (!defaultFreeOp_)
     211           0 :         return false;
     212             : 
     213           4 :     if (!gc.init(maxbytes, maxNurseryBytes))
     214           0 :         return false;
     215             : 
     216           8 :     ScopedJSDeletePtr<Zone> atomsZone(new_<Zone>(this, nullptr));
     217           4 :     if (!atomsZone || !atomsZone->init(true))
     218           0 :         return false;
     219             : 
     220           4 :     JS::CompartmentOptions options;
     221           8 :     ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get(), options));
     222           4 :     if (!atomsCompartment || !atomsCompartment->init(nullptr))
     223           0 :         return false;
     224             : 
     225           4 :     gc.atomsZone = atomsZone.get();
     226           4 :     if (!atomsZone->compartments().append(atomsCompartment.get()))
     227           0 :         return false;
     228             : 
     229           4 :     atomsCompartment->setIsSystem(true);
     230           4 :     atomsCompartment->setIsAtomsCompartment();
     231             : 
     232           4 :     atomsZone.forget();
     233           4 :     this->atomsCompartment_ = atomsCompartment.forget();
     234             : 
     235           4 :     if (!symbolRegistry_.ref().init())
     236           0 :         return false;
     237             : 
     238           4 :     if (!scriptDataTable_.ref().init())
     239           0 :         return false;
     240             : 
     241             :     /* The garbage collector depends on everything before this point being initialized. */
     242           4 :     gcInitialized = true;
     243             : 
     244           4 :     if (!InitRuntimeNumberState(this))
     245           0 :         return false;
     246             : 
     247           4 :     JS::ResetTimeZone();
     248             : 
     249           4 :     jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint();
     250           4 :     jitSupportsUnalignedAccesses = js::jit::JitSupportsUnalignedAccesses();
     251           4 :     jitSupportsSimd = js::jit::JitSupportsSimd();
     252             : 
     253           4 :     if (!geckoProfiler().init())
     254           0 :         return false;
     255             : 
     256           4 :     if (!parentRuntime) {
     257           3 :         sharedImmutableStrings_ = js::SharedImmutableStringsCache::Create();
     258           3 :         if (!sharedImmutableStrings_)
     259           0 :             return false;
     260             :     }
     261             : 
     262           4 :     if (!caches().init())
     263           0 :         return false;
     264             : 
     265           4 :     return true;
     266             : }
     267             : 
     268             : void
     269           0 : JSRuntime::destroyRuntime()
     270             : {
     271           0 :     MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
     272           0 :     MOZ_ASSERT(childRuntimeCount == 0);
     273           0 :     MOZ_ASSERT(initialized_);
     274             : 
     275           0 :     sharedIntlData.ref().destroyInstance();
     276             : 
     277           0 :     if (gcInitialized) {
     278             :         /*
     279             :          * Finish any in-progress GCs first. This ensures the parseWaitingOnGC
     280             :          * list is empty in CancelOffThreadParses.
     281             :          */
     282           0 :         JSContext* cx = TlsContext.get();
     283           0 :         if (JS::IsIncrementalGCInProgress(cx))
     284           0 :             FinishGC(cx);
     285             : 
     286             :         /* Free source hook early, as its destructor may want to delete roots. */
     287           0 :         sourceHook = nullptr;
     288             : 
     289             :         /*
     290             :          * Cancel any pending, in progress or completed Ion compilations and
     291             :          * parse tasks. Waiting for wasm and compression tasks is done
     292             :          * synchronously (on the active thread or during parse tasks), so no
     293             :          * explicit canceling is needed for these.
     294             :          */
     295           0 :         CancelOffThreadIonCompile(this);
     296           0 :         CancelOffThreadParses(this);
     297           0 :         CancelOffThreadCompressions(this);
     298             : 
     299             :         /* Remove persistent GC roots. */
     300           0 :         gc.finishRoots();
     301             : 
     302             :         /*
     303             :          * Flag us as being destroyed. This allows the GC to free things like
     304             :          * interned atoms and Ion trampolines.
     305             :          */
     306           0 :         beingDestroyed_ = true;
     307             : 
     308             :         /* Allow the GC to release scripts that were being profiled. */
     309           0 :         profilingScripts = false;
     310             : 
     311             :         /* Set the profiler sampler buffer generation to invalid. */
     312           0 :         profilerSampleBufferGen_ = UINT32_MAX;
     313             : 
     314           0 :         JS::PrepareForFullGC(cx);
     315           0 :         gc.gc(GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
     316             :     }
     317             : 
     318           0 :     AutoNoteSingleThreadedRegion anstr;
     319             : 
     320           0 :     MOZ_ASSERT_IF(!geckoProfiler().enabled(), !singleThreadedExecutionRequired_);
     321             : 
     322           0 :     MOZ_ASSERT(!hasHelperThreadZones());
     323           0 :     AutoLockForExclusiveAccess lock(this);
     324             : 
     325             :     /*
     326             :      * Even though all objects in the compartment are dead, we may have keep
     327             :      * some filenames around because of gcKeepAtoms.
     328             :      */
     329           0 :     FreeScriptData(this, lock);
     330             : 
     331             : #if !EXPOSE_INTL_API
     332             :     FinishRuntimeNumberState(this);
     333             : #endif
     334             : 
     335           0 :     gc.finish();
     336           0 :     atomsCompartment_ = nullptr;
     337             : 
     338           0 :     js_delete(defaultFreeOp_.ref());
     339             : 
     340           0 :     js_free(defaultLocale);
     341           0 :     js_delete(jitRuntime_.ref());
     342             : 
     343             : #ifdef DEBUG
     344           0 :     initialized_ = false;
     345             : #endif
     346           0 : }
     347             : 
     348             : static void
     349           0 : CheckCanChangeActiveContext(JSRuntime* rt)
     350             : {
     351             :     // The runtime might not currently have an active context, in which case
     352             :     // the accesses below to ActiveThreadData data would not normally be
     353             :     // allowed. Suppress protected data checks so these accesses will be
     354             :     // tolerated --- if the active context is null then we're about to set it
     355             :     // to the current thread.
     356           0 :     AutoNoteSingleThreadedRegion anstr;
     357             : 
     358           0 :     MOZ_RELEASE_ASSERT(!rt->activeContextChangeProhibited());
     359           0 :     MOZ_RELEASE_ASSERT(!rt->activeContext() || rt->gc.canChangeActiveContext(rt->activeContext()));
     360             : 
     361           0 :     if (rt->singleThreadedExecutionRequired()) {
     362           0 :         for (ZoneGroupsIter group(rt); !group.done(); group.next())
     363           0 :             MOZ_RELEASE_ASSERT(group->ownerContext().context() == nullptr);
     364             :     }
     365           0 : }
     366             : 
     367             : void
     368           0 : JSRuntime::setActiveContext(JSContext* cx)
     369             : {
     370           0 :     CheckCanChangeActiveContext(this);
     371           0 :     MOZ_ASSERT_IF(cx, cx->isCooperativelyScheduled());
     372             : 
     373           0 :     activeContext_ = cx;
     374           0 : }
     375             : 
     376             : void
     377           0 : JSRuntime::setNewbornActiveContext(JSContext* cx)
     378             : {
     379           0 :     CheckCanChangeActiveContext(this);
     380             : 
     381           0 :     activeContext_ = cx;
     382             : 
     383           0 :     AutoEnterOOMUnsafeRegion oomUnsafe;
     384           0 :     if (!cooperatingContexts().append(cx))
     385           0 :         oomUnsafe.crash("Add cooperating context");
     386           0 : }
     387             : 
     388             : void
     389           0 : JSRuntime::deleteActiveContext(JSContext* cx)
     390             : {
     391           0 :     CheckCanChangeActiveContext(this);
     392           0 :     MOZ_ASSERT(cx == activeContext());
     393             : 
     394           0 :     js_delete_poison(cx);
     395           0 :     activeContext_ = nullptr;
     396           0 : }
     397             : 
     398             : bool
     399           0 : JSRuntime::beginSingleThreadedExecution(JSContext* cx)
     400             : {
     401           0 :     if (singleThreadedExecutionRequired_ == 0) {
     402           0 :         if (startingSingleThreadedExecution_)
     403           0 :             return false;
     404           0 :         startingSingleThreadedExecution_ = true;
     405           0 :         if (beginSingleThreadedExecutionCallback)
     406           0 :             beginSingleThreadedExecutionCallback(cx);
     407           0 :         MOZ_ASSERT(startingSingleThreadedExecution_);
     408           0 :         startingSingleThreadedExecution_ = false;
     409             :     }
     410             : 
     411           0 :     singleThreadedExecutionRequired_++;
     412             : 
     413           0 :     for (ZoneGroupsIter group(this); !group.done(); group.next()) {
     414           0 :         MOZ_RELEASE_ASSERT(group->ownedByCurrentThread() ||
     415             :                            group->ownerContext().context() == nullptr);
     416             :     }
     417             : 
     418           0 :     return true;
     419             : }
     420             : 
     421             : void
     422           0 : JSRuntime::endSingleThreadedExecution(JSContext* cx)
     423             : {
     424           0 :     MOZ_ASSERT(singleThreadedExecutionRequired_);
     425           0 :     if (--singleThreadedExecutionRequired_ == 0) {
     426           0 :         if (endSingleThreadedExecutionCallback)
     427           0 :             endSingleThreadedExecutionCallback(cx);
     428             :     }
     429           0 : }
     430             : 
     431             : void
     432         769 : JSRuntime::addTelemetry(int id, uint32_t sample, const char* key)
     433             : {
     434         769 :     if (telemetryCallback)
     435         757 :         (*telemetryCallback)(id, sample, key);
     436         769 : }
     437             : 
     438             : void
     439           3 : JSRuntime::setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback)
     440             : {
     441           3 :     rt->telemetryCallback = callback;
     442           3 : }
     443             : 
     444             : void
     445           0 : JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes)
     446             : {
     447             :     // Several tables in the runtime enumerated below can be used off thread.
     448           0 :     AutoLockForExclusiveAccess lock(this);
     449             : 
     450           0 :     rtSizes->object += mallocSizeOf(this);
     451           0 :     rtSizes->atomsTable += atoms(lock).sizeOfIncludingThis(mallocSizeOf);
     452             : 
     453           0 :     if (!parentRuntime) {
     454           0 :         rtSizes->atomsTable += mallocSizeOf(staticStrings);
     455           0 :         rtSizes->atomsTable += mallocSizeOf(commonNames);
     456           0 :         rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
     457             :     }
     458             : 
     459           0 :     for (const CooperatingContext& target : cooperatingContexts()) {
     460           0 :         JSContext* cx = target.context();
     461           0 :         rtSizes->contexts += mallocSizeOf(cx);
     462           0 :         rtSizes->contexts += cx->sizeOfExcludingThis(mallocSizeOf);
     463           0 :         rtSizes->temporary += cx->tempLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
     464           0 :         rtSizes->interpreterStack += cx->interpreterStack().sizeOfExcludingThis(mallocSizeOf);
     465             : #ifdef JS_TRACE_LOGGING
     466           0 :         if (cx->traceLogger)
     467           0 :             rtSizes->tracelogger += cx->traceLogger->sizeOfIncludingThis(mallocSizeOf);
     468             : #endif
     469             :     }
     470             : 
     471           0 :     if (MathCache* cache = caches().maybeGetMathCache())
     472           0 :         rtSizes->mathCache += cache->sizeOfIncludingThis(mallocSizeOf);
     473             : 
     474           0 :     rtSizes->uncompressedSourceCache +=
     475           0 :         caches().uncompressedSourceCache.sizeOfExcludingThis(mallocSizeOf);
     476             : 
     477           0 :     rtSizes->gc.nurseryCommitted += gc.nursery().sizeOfHeapCommitted();
     478           0 :     rtSizes->gc.nurseryMallocedBuffers += gc.nursery().sizeOfMallocedBuffers(mallocSizeOf);
     479           0 :     gc.storeBuffer().addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc);
     480             : 
     481           0 :     if (sharedImmutableStrings_) {
     482           0 :         rtSizes->sharedImmutableStringsCache +=
     483           0 :             sharedImmutableStrings_->sizeOfExcludingThis(mallocSizeOf);
     484             :     }
     485             : 
     486           0 :     rtSizes->sharedIntlData += sharedIntlData.ref().sizeOfExcludingThis(mallocSizeOf);
     487             : 
     488           0 :     rtSizes->scriptData += scriptDataTable(lock).sizeOfExcludingThis(mallocSizeOf);
     489           0 :     for (ScriptDataTable::Range r = scriptDataTable(lock).all(); !r.empty(); r.popFront())
     490           0 :         rtSizes->scriptData += mallocSizeOf(r.front());
     491             : 
     492           0 :     if (jitRuntime_) {
     493           0 :         jitRuntime_->execAlloc().addSizeOfCode(&rtSizes->code);
     494           0 :         jitRuntime_->backedgeExecAlloc().addSizeOfCode(&rtSizes->code);
     495             :     }
     496             : 
     497           0 :     rtSizes->gc.marker += gc.marker.sizeOfExcludingThis(mallocSizeOf);
     498           0 : }
     499             : 
     500             : static bool
     501          27 : InvokeInterruptCallback(JSContext* cx)
     502             : {
     503          27 :     MOZ_ASSERT(cx->requestDepth >= 1);
     504          27 :     MOZ_ASSERT(!cx->compartment()->isAtomsCompartment());
     505             : 
     506          27 :     cx->runtime()->gc.gcIfRequested();
     507             : 
     508             :     // A worker thread may have requested an interrupt after finishing an Ion
     509             :     // compilation.
     510          27 :     jit::AttachFinishedCompilations(cx->zone()->group(), cx);
     511             : 
     512             :     // Important: Additional callbacks can occur inside the callback handler
     513             :     // if it re-enters the JS engine. The embedding must ensure that the
     514             :     // callback is disconnected before attempting such re-entry.
     515          27 :     if (cx->interruptCallbackDisabled)
     516           0 :         return true;
     517             : 
     518          27 :     bool stop = false;
     519          56 :     for (JSInterruptCallback cb : cx->interruptCallbacks()) {
     520          29 :         if (!cb(cx))
     521           0 :             stop = true;
     522             :     }
     523             : 
     524          27 :     if (!stop) {
     525             :         // Debugger treats invoking the interrupt callback as a "step", so
     526             :         // invoke the onStep handler.
     527          27 :         if (cx->compartment()->isDebuggee()) {
     528           0 :             ScriptFrameIter iter(cx);
     529           0 :             if (!iter.done() &&
     530           0 :                 cx->compartment() == iter.compartment() &&
     531           0 :                 iter.script()->stepModeEnabled())
     532             :             {
     533           0 :                 RootedValue rval(cx);
     534           0 :                 switch (Debugger::onSingleStep(cx, &rval)) {
     535             :                   case JSTRAP_ERROR:
     536           0 :                     return false;
     537             :                   case JSTRAP_CONTINUE:
     538           0 :                     return true;
     539             :                   case JSTRAP_RETURN:
     540             :                     // See note in Debugger::propagateForcedReturn.
     541           0 :                     Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
     542           0 :                     return false;
     543             :                   case JSTRAP_THROW:
     544           0 :                     cx->setPendingException(rval);
     545           0 :                     return false;
     546             :                   default:;
     547             :                 }
     548             :             }
     549             :         }
     550             : 
     551          27 :         return true;
     552             :     }
     553             : 
     554             :     // No need to set aside any pending exception here: ComputeStackString
     555             :     // already does that.
     556           0 :     JSString* stack = ComputeStackString(cx);
     557           0 :     JSFlatString* flat = stack ? stack->ensureFlat(cx) : nullptr;
     558             : 
     559             :     const char16_t* chars;
     560           0 :     AutoStableStringChars stableChars(cx);
     561           0 :     if (flat && stableChars.initTwoByte(cx, flat))
     562           0 :         chars = stableChars.twoByteRange().begin().get();
     563             :     else
     564           0 :         chars = u"(stack not available)";
     565             :     JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
     566           0 :                                    JSMSG_TERMINATED, chars);
     567             : 
     568           0 :     return false;
     569             : }
     570             : 
     571             : void
     572          28 : JSContext::requestInterrupt(InterruptMode mode)
     573             : {
     574          28 :     interrupt_ = true;
     575          28 :     jitStackLimit = UINTPTR_MAX;
     576             : 
     577          28 :     if (mode == JSContext::RequestInterruptUrgent) {
     578             :         // If this interrupt is urgent (slow script dialog and garbage
     579             :         // collection among others), take additional steps to
     580             :         // interrupt corner cases where the above fields are not
     581             :         // regularly polled.  Wake both ilooping JIT code and
     582             :         // Atomics.wait().
     583           2 :         fx.lock();
     584           2 :         if (fx.isWaiting())
     585           0 :             fx.wake(FutexThread::WakeForJSInterrupt);
     586           2 :         fx.unlock();
     587           2 :         InterruptRunningJitCode(this);
     588             :     }
     589          28 : }
     590             : 
     591             : bool
     592          27 : JSContext::handleInterrupt()
     593             : {
     594          27 :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
     595          27 :     if (interrupt_ || jitStackLimit == UINTPTR_MAX) {
     596          27 :         interrupt_ = false;
     597          27 :         resetJitStackLimit();
     598          27 :         return InvokeInterruptCallback(this);
     599             :     }
     600           0 :     return true;
     601             : }
     602             : 
     603             : bool
     604           6 : JSRuntime::setDefaultLocale(const char* locale)
     605             : {
     606           6 :     if (!locale)
     607           0 :         return false;
     608           6 :     resetDefaultLocale();
     609           6 :     defaultLocale = JS_strdup(activeContextFromOwnThread(), locale);
     610           6 :     return defaultLocale != nullptr;
     611             : }
     612             : 
     613             : void
     614           6 : JSRuntime::resetDefaultLocale()
     615             : {
     616           6 :     js_free(defaultLocale);
     617           6 :     defaultLocale = nullptr;
     618           6 : }
     619             : 
     620             : const char*
     621           1 : JSRuntime::getDefaultLocale()
     622             : {
     623           1 :     if (defaultLocale)
     624           1 :         return defaultLocale;
     625             : 
     626             :     const char* locale;
     627             : #ifdef HAVE_SETLOCALE
     628           0 :     locale = setlocale(LC_ALL, nullptr);
     629             : #else
     630             :     locale = getenv("LANG");
     631             : #endif
     632             :     // convert to a well-formed BCP 47 language tag
     633           0 :     if (!locale || !strcmp(locale, "C"))
     634           0 :         locale = "und";
     635             : 
     636           0 :     char* lang = JS_strdup(activeContextFromOwnThread(), locale);
     637           0 :     if (!lang)
     638           0 :         return nullptr;
     639             : 
     640             :     char* p;
     641           0 :     if ((p = strchr(lang, '.')))
     642           0 :         *p = '\0';
     643           0 :     while ((p = strchr(lang, '_')))
     644           0 :         *p = '-';
     645             : 
     646           0 :     defaultLocale = lang;
     647           0 :     return defaultLocale;
     648             : }
     649             : 
     650             : void
     651          22 : JSRuntime::traceSharedIntlData(JSTracer* trc)
     652             : {
     653          22 :     sharedIntlData.ref().trace(trc);
     654          22 : }
     655             : 
     656             : void
     657        3422 : JSContext::triggerActivityCallback(bool active)
     658             : {
     659        3422 :     if (!activityCallback)
     660           3 :         return;
     661             : 
     662             :     /*
     663             :      * The activity callback must not trigger a GC: it would create a cirular
     664             :      * dependency between entering a request and Rooted's requirement of being
     665             :      * in a request. In practice this callback already cannot trigger GC. The
     666             :      * suppression serves to inform the exact rooting hazard analysis of this
     667             :      * property and ensures that it remains true in the future.
     668             :      */
     669        6838 :     AutoSuppressGC suppress(this);
     670             : 
     671        3419 :     activityCallback(activityCallbackArg, active);
     672             : }
     673             : 
     674           4 : FreeOp::FreeOp(JSRuntime* maybeRuntime)
     675           4 :   : JSFreeOp(maybeRuntime)
     676             : {
     677           4 :     MOZ_ASSERT_IF(maybeRuntime, CurrentThreadCanAccessRuntime(maybeRuntime));
     678           4 : }
     679             : 
     680           0 : FreeOp::~FreeOp()
     681             : {
     682           0 :     for (size_t i = 0; i < freeLaterList.length(); i++)
     683           0 :         free_(freeLaterList[i]);
     684             : 
     685           0 :     if (!jitPoisonRanges.empty())
     686           0 :         jit::ExecutableAllocator::poisonCode(runtime(), jitPoisonRanges);
     687           0 : }
     688             : 
     689             : bool
     690           0 : FreeOp::isDefaultFreeOp() const
     691             : {
     692           0 :     return runtime_ && runtime_->defaultFreeOp() == this;
     693             : }
     694             : 
     695             : JSObject*
     696         427 : JSRuntime::getIncumbentGlobal(JSContext* cx)
     697             : {
     698             :     // If the embedding didn't set a callback for getting the incumbent
     699             :     // global, the currently active global is used.
     700         427 :     if (!cx->getIncumbentGlobalCallback) {
     701           0 :         if (!cx->compartment())
     702           0 :             return nullptr;
     703           0 :         return cx->global();
     704             :     }
     705             : 
     706         427 :     return cx->getIncumbentGlobalCallback(cx);
     707             : }
     708             : 
     709             : bool
     710         235 : JSRuntime::enqueuePromiseJob(JSContext* cx, HandleFunction job, HandleObject promise,
     711             :                              HandleObject incumbentGlobal)
     712             : {
     713         235 :     MOZ_ASSERT(cx->enqueuePromiseJobCallback,
     714             :                "Must set a callback using JS_SetEnqeueuPromiseJobCallback before using Promises");
     715         235 :     MOZ_ASSERT_IF(incumbentGlobal, !IsWrapper(incumbentGlobal) && !IsWindowProxy(incumbentGlobal));
     716             : 
     717         235 :     void* data = cx->enqueuePromiseJobCallbackData;
     718         470 :     RootedObject allocationSite(cx);
     719         235 :     if (promise) {
     720         470 :         RootedObject unwrappedPromise(cx, promise);
     721             :         // While the job object is guaranteed to be unwrapped, the promise
     722             :         // might be wrapped. See the comments in
     723             :         // intrinsic_EnqueuePromiseReactionJob for details.
     724         235 :         if (IsWrapper(promise))
     725          57 :             unwrappedPromise = UncheckedUnwrap(promise);
     726         235 :         if (unwrappedPromise->is<PromiseObject>())
     727         235 :             allocationSite = JS::GetPromiseAllocationSite(unwrappedPromise);
     728             :     }
     729         470 :     return cx->enqueuePromiseJobCallback(cx, job, allocationSite, incumbentGlobal, data);
     730             : }
     731             : 
     732             : void
     733           0 : JSRuntime::addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise)
     734             : {
     735           0 :     MOZ_ASSERT(promise->is<PromiseObject>());
     736           0 :     if (!cx->promiseRejectionTrackerCallback)
     737           0 :         return;
     738             : 
     739           0 :     void* data = cx->promiseRejectionTrackerCallbackData;
     740             :     cx->promiseRejectionTrackerCallback(cx, promise,
     741           0 :                                         PromiseRejectionHandlingState::Unhandled, data);
     742             : }
     743             : 
     744             : void
     745           0 : JSRuntime::removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise)
     746             : {
     747           0 :     MOZ_ASSERT(promise->is<PromiseObject>());
     748           0 :     if (!cx->promiseRejectionTrackerCallback)
     749           0 :         return;
     750             : 
     751           0 :     void* data = cx->promiseRejectionTrackerCallbackData;
     752             :     cx->promiseRejectionTrackerCallback(cx, promise,
     753           0 :                                         PromiseRejectionHandlingState::Handled, data);
     754             : }
     755             : 
     756             : mozilla::non_crypto::XorShift128PlusRNG&
     757         346 : JSRuntime::randomKeyGenerator()
     758             : {
     759         346 :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
     760         346 :     if (randomKeyGenerator_.isNothing()) {
     761           4 :         mozilla::Array<uint64_t, 2> seed;
     762           4 :         GenerateXorShift128PlusSeed(seed);
     763           4 :         randomKeyGenerator_.emplace(seed[0], seed[1]);
     764             :     }
     765         346 :     return randomKeyGenerator_.ref();
     766             : }
     767             : 
     768             : mozilla::HashCodeScrambler
     769          31 : JSRuntime::randomHashCodeScrambler()
     770             : {
     771          31 :     auto& rng = randomKeyGenerator();
     772          31 :     return mozilla::HashCodeScrambler(rng.next(), rng.next());
     773             : }
     774             : 
     775             : mozilla::non_crypto::XorShift128PlusRNG
     776         315 : JSRuntime::forkRandomKeyGenerator()
     777             : {
     778         315 :     auto& rng = randomKeyGenerator();
     779         315 :     return mozilla::non_crypto::XorShift128PlusRNG(rng.next(), rng.next());
     780             : }
     781             : 
     782             : void
     783        1529 : JSRuntime::updateMallocCounter(size_t nbytes)
     784             : {
     785        1529 :     updateMallocCounter(nullptr, nbytes);
     786        1529 : }
     787             : 
     788             : void
     789       49450 : JSRuntime::updateMallocCounter(JS::Zone* zone, size_t nbytes)
     790             : {
     791       49450 :     gc.updateMallocCounter(zone, nbytes);
     792       49450 : }
     793             : 
     794             : JS_FRIEND_API(void*)
     795           0 : JSRuntime::onOutOfMemory(AllocFunction allocFunc, size_t nbytes, void* reallocPtr, JSContext* maybecx)
     796             : {
     797           0 :     MOZ_ASSERT_IF(allocFunc != AllocFunction::Realloc, !reallocPtr);
     798             : 
     799           0 :     if (JS::CurrentThreadIsHeapBusy())
     800           0 :         return nullptr;
     801             : 
     802           0 :     if (!oom::IsSimulatedOOMAllocation()) {
     803             :         /*
     804             :          * Retry when we are done with the background sweeping and have stopped
     805             :          * all the allocations and released the empty GC chunks.
     806             :          */
     807           0 :         gc.onOutOfMallocMemory();
     808             :         void* p;
     809           0 :         switch (allocFunc) {
     810             :           case AllocFunction::Malloc:
     811           0 :             p = js_malloc(nbytes);
     812           0 :             break;
     813             :           case AllocFunction::Calloc:
     814           0 :             p = js_calloc(nbytes);
     815           0 :             break;
     816             :           case AllocFunction::Realloc:
     817           0 :             p = js_realloc(reallocPtr, nbytes);
     818           0 :             break;
     819             :           default:
     820           0 :             MOZ_CRASH();
     821             :         }
     822           0 :         if (p)
     823           0 :             return p;
     824             :     }
     825             : 
     826           0 :     if (maybecx)
     827           0 :         ReportOutOfMemory(maybecx);
     828           0 :     return nullptr;
     829             : }
     830             : 
     831             : void*
     832           0 : JSRuntime::onOutOfMemoryCanGC(AllocFunction allocFunc, size_t bytes, void* reallocPtr)
     833             : {
     834           0 :     if (OnLargeAllocationFailure && bytes >= LARGE_ALLOCATION)
     835           0 :         OnLargeAllocationFailure();
     836           0 :     return onOutOfMemory(allocFunc, bytes, reallocPtr);
     837             : }
     838             : 
     839             : bool
     840          54 : JSRuntime::activeGCInAtomsZone()
     841             : {
     842          54 :     Zone* zone = atomsCompartment_->zone();
     843         103 :     return (zone->needsIncrementalBarrier() && !gc.isVerifyPreBarriersEnabled()) ||
     844         103 :            zone->wasGCStarted();
     845             : }
     846             : 
     847             : bool
     848           0 : JSRuntime::createAtomsAddedWhileSweepingTable()
     849             : {
     850           0 :     MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
     851           0 :     MOZ_ASSERT(!atomsAddedWhileSweeping_);
     852             : 
     853           0 :     atomsAddedWhileSweeping_ = js_new<AtomSet>();
     854           0 :     if (!atomsAddedWhileSweeping_)
     855           0 :         return false;
     856             : 
     857           0 :     if (!atomsAddedWhileSweeping_->init()) {
     858           0 :         destroyAtomsAddedWhileSweepingTable();
     859           0 :         return false;
     860             :     }
     861             : 
     862           0 :     return true;
     863             : }
     864             : 
     865             : void
     866           0 : JSRuntime::destroyAtomsAddedWhileSweepingTable()
     867             : {
     868           0 :     MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
     869           0 :     MOZ_ASSERT(atomsAddedWhileSweeping_);
     870             : 
     871           0 :     js_delete(atomsAddedWhileSweeping_.ref());
     872           0 :     atomsAddedWhileSweeping_ = nullptr;
     873           0 : }
     874             : 
     875             : void
     876          16 : JSRuntime::setUsedByHelperThread(Zone* zone)
     877             : {
     878          16 :     MOZ_ASSERT(!zone->group()->usedByHelperThread);
     879          16 :     MOZ_ASSERT(!zone->wasGCStarted());
     880          16 :     zone->group()->usedByHelperThread = true;
     881          16 :     numHelperThreadZones++;
     882          16 : }
     883             : 
     884             : void
     885          15 : JSRuntime::clearUsedByHelperThread(Zone* zone)
     886             : {
     887          15 :     MOZ_ASSERT(zone->group()->usedByHelperThread);
     888          15 :     zone->group()->usedByHelperThread = false;
     889          15 :     numHelperThreadZones--;
     890          15 :     if (gc.fullGCForAtomsRequested() && !TlsContext.get())
     891           0 :         gc.triggerFullGCForAtoms();
     892          15 : }
     893             : 
     894             : bool
     895    49011618 : js::CurrentThreadCanAccessRuntime(const JSRuntime* rt)
     896             : {
     897    49011618 :     return rt->activeContext() == TlsContext.get();
     898             : }
     899             : 
     900             : bool
     901     3815329 : js::CurrentThreadCanAccessZone(Zone* zone)
     902             : {
     903     3815329 :     if (CurrentThreadCanAccessRuntime(zone->runtime_))
     904     3668500 :         return true;
     905             : 
     906             :     // Only zones marked for use by a helper thread can be used off thread.
     907      148031 :     return zone->usedByHelperThread() && zone->group()->ownedByCurrentThread();
     908             : }
     909             : 
     910             : #ifdef DEBUG
     911             : bool
     912          18 : js::CurrentThreadIsPerformingGC()
     913             : {
     914          18 :     return TlsContext.get()->performingGC;
     915             : }
     916             : #endif
     917             : 
     918             : JS_FRIEND_API(void)
     919           0 : JS::UpdateJSContextProfilerSampleBufferGen(JSContext* cx, uint32_t generation,
     920             :                                            uint32_t lapCount)
     921             : {
     922           0 :     cx->runtime()->setProfilerSampleBufferGen(generation);
     923           0 :     cx->runtime()->updateProfilerSampleBufferLapCount(lapCount);
     924           0 : }
     925             : 
     926             : JS_FRIEND_API(bool)
     927           0 : JS::IsProfilingEnabledForContext(JSContext* cx)
     928             : {
     929           0 :     MOZ_ASSERT(cx);
     930           0 :     return cx->runtime()->geckoProfiler().enabled();
     931             : }
     932             : 
     933             : JS_PUBLIC_API(void)
     934           0 : JS::shadow::RegisterWeakCache(JSRuntime* rt, detail::WeakCacheBase* cachep)
     935             : {
     936           0 :     rt->registerWeakCache(cachep);
     937           0 : }

Generated by: LCOV version 1.13