js/src/vm/Runtime.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 #include "vm/Runtime-inl.h"
     9 #include "mozilla/ArrayUtils.h"
    10 #include "mozilla/Atomics.h"
    11 #include "mozilla/DebugOnly.h"
    12 #include "mozilla/MemoryReporting.h"
    13 #include "mozilla/ThreadLocal.h"
    15 #include <locale.h>
    16 #include <string.h>
    18 #ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
    19 # include <sys/mman.h>
    20 #endif
    22 #include "jsatom.h"
    23 #include "jsdtoa.h"
    24 #include "jsgc.h"
    25 #include "jsmath.h"
    26 #include "jsnativestack.h"
    27 #include "jsobj.h"
    28 #include "jsscript.h"
    29 #include "jswatchpoint.h"
    30 #include "jswrapper.h"
    32 #if defined(JS_ION)
    33 # include "assembler/assembler/MacroAssembler.h"
    34 #endif
    35 #include "jit/arm/Simulator-arm.h"
    36 #include "jit/AsmJSSignalHandlers.h"
    37 #include "jit/JitCompartment.h"
    38 #include "jit/PcScriptCache.h"
    39 #include "js/MemoryMetrics.h"
    40 #include "js/SliceBudget.h"
    41 #include "yarr/BumpPointerAllocator.h"
    43 #include "jscntxtinlines.h"
    44 #include "jsgcinlines.h"
    46 using namespace js;
    47 using namespace js::gc;
    49 using mozilla::Atomic;
    50 using mozilla::DebugOnly;
    51 using mozilla::NegativeInfinity;
    52 using mozilla::PodZero;
    53 using mozilla::PodArrayZero;
    54 using mozilla::PositiveInfinity;
    55 using mozilla::ThreadLocal;
    56 using JS::GenericNaN;
    57 using JS::DoubleNaNValue;
    59 /* static */ ThreadLocal<PerThreadData*> js::TlsPerThreadData;
    61 #ifdef JS_THREADSAFE
    62 /* static */ Atomic<size_t> JSRuntime::liveRuntimesCount;
    63 #else
    64 /* static */ size_t JSRuntime::liveRuntimesCount;
    65 #endif
    67 const JSSecurityCallbacks js::NullSecurityCallbacks = { };
    69 PerThreadData::PerThreadData(JSRuntime *runtime)
    70   : PerThreadDataFriendFields(),
    71     runtime_(runtime),
    72     ionTop(nullptr),
    73     jitJSContext(nullptr),
    74     jitStackLimit(0),
    75 #ifdef JS_TRACE_LOGGING
    76     traceLogger(nullptr),
    77 #endif
    78     activation_(nullptr),
    79     asmJSActivationStack_(nullptr),
    80     autoFlushICache_(nullptr),
    81 #ifdef JS_ARM_SIMULATOR
    82     simulator_(nullptr),
    83     simulatorStackLimit_(0),
    84 #endif
    85     dtoaState(nullptr),
    86     suppressGC(0),
    87     activeCompilations(0)
    88 {}
    90 PerThreadData::~PerThreadData()
    91 {
    92     if (dtoaState)
    93         js_DestroyDtoaState(dtoaState);
    95 #ifdef JS_ARM_SIMULATOR
    96     js_delete(simulator_);
    97 #endif
    98 }
   100 bool
   101 PerThreadData::init()
   102 {
   103     dtoaState = js_NewDtoaState();
   104     if (!dtoaState)
   105         return false;
   107     return true;
   108 }
   110 static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
   111     TransparentObjectWrapper,
   112     nullptr
   113 };
   115 JSRuntime::JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThreads)
   116   : JS::shadow::Runtime(
   117 #ifdef JSGC_GENERATIONAL
   118         &gcStoreBuffer
   119 #endif
   120     ),
   121     mainThread(this),
   122     parentRuntime(parentRuntime),
   123     interrupt(false),
   124 #if defined(JS_THREADSAFE) && defined(JS_ION)
   125     interruptPar(false),
   126 #endif
   127     handlingSignal(false),
   128     interruptCallback(nullptr),
   129 #ifdef JS_THREADSAFE
   130     interruptLock(nullptr),
   131     interruptLockOwner(nullptr),
   132     exclusiveAccessLock(nullptr),
   133     exclusiveAccessOwner(nullptr),
   134     mainThreadHasExclusiveAccess(false),
   135     numExclusiveThreads(0),
   136 #else
   137     interruptLockTaken(false),
   138 #endif
   139     systemZone(nullptr),
   140     numCompartments(0),
   141     localeCallbacks(nullptr),
   142     defaultLocale(nullptr),
   143     defaultVersion_(JSVERSION_DEFAULT),
   144 #ifdef JS_THREADSAFE
   145     ownerThread_(nullptr),
   146 #endif
   147     tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
   148     freeLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
   149     execAlloc_(nullptr),
   150     bumpAlloc_(nullptr),
   151     jitRuntime_(nullptr),
   152     selfHostingGlobal_(nullptr),
   153     nativeStackBase(0),
   154     cxCallback(nullptr),
   155     destroyCompartmentCallback(nullptr),
   156     destroyZoneCallback(nullptr),
   157     sweepZoneCallback(nullptr),
   158     compartmentNameCallback(nullptr),
   159     activityCallback(nullptr),
   160     activityCallbackArg(nullptr),
   161 #ifdef JS_THREADSAFE
   162     requestDepth(0),
   163 # ifdef DEBUG
   164     checkRequestDepth(0),
   165 # endif
   166 #endif
   167 #ifdef DEBUG
   168     activeContext(nullptr),
   169 #endif
   170     gcInitialized(false),
   171     gcSystemAvailableChunkListHead(nullptr),
   172     gcUserAvailableChunkListHead(nullptr),
   173     gcBytes(0),
   174     gcMaxBytes(0),
   175     gcMaxMallocBytes(0),
   176     gcNumArenasFreeCommitted(0),
   177     gcMarker(this),
   178     gcVerifyPreData(nullptr),
   179     gcVerifyPostData(nullptr),
   180     gcChunkAllocationSinceLastGC(false),
   181     gcNextFullGCTime(0),
   182     gcLastGCTime(0),
   183     gcJitReleaseTime(0),
   184     gcAllocationThreshold(30 * 1024 * 1024),
   185     gcHighFrequencyGC(false),
   186     gcHighFrequencyTimeThreshold(1000),
   187     gcHighFrequencyLowLimitBytes(100 * 1024 * 1024),
   188     gcHighFrequencyHighLimitBytes(500 * 1024 * 1024),
   189     gcHighFrequencyHeapGrowthMax(3.0),
   190     gcHighFrequencyHeapGrowthMin(1.5),
   191     gcLowFrequencyHeapGrowth(1.5),
   192     gcDynamicHeapGrowth(false),
   193     gcDynamicMarkSlice(false),
   194     gcDecommitThreshold(32 * 1024 * 1024),
   195     gcShouldCleanUpEverything(false),
   196     gcGrayBitsValid(false),
   197     gcIsNeeded(0),
   198     gcStats(thisFromCtor()),
   199     gcNumber(0),
   200     gcStartNumber(0),
   201     gcIsFull(false),
   202     gcTriggerReason(JS::gcreason::NO_REASON),
   203     gcStrictCompartmentChecking(false),
   204 #ifdef DEBUG
   205     gcDisableStrictProxyCheckingCount(0),
   206 #endif
   207     gcIncrementalState(gc::NO_INCREMENTAL),
   208     gcLastMarkSlice(false),
   209     gcSweepOnBackgroundThread(false),
   210     gcFoundBlackGrayEdges(false),
   211     gcSweepingZones(nullptr),
   212     gcZoneGroupIndex(0),
   213     gcZoneGroups(nullptr),
   214     gcCurrentZoneGroup(nullptr),
   215     gcSweepPhase(0),
   216     gcSweepZone(nullptr),
   217     gcSweepKindIndex(0),
   218     gcAbortSweepAfterCurrentGroup(false),
   219     gcArenasAllocatedDuringSweep(nullptr),
   220 #ifdef DEBUG
   221     gcMarkingValidator(nullptr),
   222 #endif
   223     gcInterFrameGC(0),
   224     gcSliceBudget(SliceBudget::Unlimited),
   225     gcIncrementalEnabled(true),
   226     gcGenerationalDisabled(0),
   227     gcManipulatingDeadZones(false),
   228     gcObjectsMarkedInDeadZones(0),
   229     gcPoke(false),
   230     heapState(Idle),
   231 #ifdef JSGC_GENERATIONAL
   232     gcNursery(thisFromCtor()),
   233     gcStoreBuffer(thisFromCtor(), gcNursery),
   234 #endif
   235 #ifdef JS_GC_ZEAL
   236     gcZeal_(0),
   237     gcZealFrequency(0),
   238     gcNextScheduled(0),
   239     gcDeterministicOnly(false),
   240     gcIncrementalLimit(0),
   241 #endif
   242     gcValidate(true),
   243     gcFullCompartmentChecks(false),
   244     gcCallback(nullptr),
   245     gcSliceCallback(nullptr),
   246     gcFinalizeCallback(nullptr),
   247     gcMallocBytes(0),
   248     gcMallocGCTriggered(false),
   249 #ifdef JS_ARM_SIMULATOR
   250     simulatorRuntime_(nullptr),
   251 #endif
   252     scriptAndCountsVector(nullptr),
   253     NaNValue(DoubleNaNValue()),
   254     negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
   255     positiveInfinityValue(DoubleValue(PositiveInfinity<double>())),
   256     emptyString(nullptr),
   257     debugMode(false),
   258     spsProfiler(thisFromCtor()),
   259     profilingScripts(false),
   260     alwaysPreserveCode(false),
   261     hadOutOfMemory(false),
   262     haveCreatedContext(false),
   263     data(nullptr),
   264     gcLock(nullptr),
   265     gcLockOwner(nullptr),
   266     gcHelperThread(thisFromCtor()),
   267     signalHandlersInstalled_(false),
   268     defaultFreeOp_(thisFromCtor(), false),
   269     debuggerMutations(0),
   270     securityCallbacks(const_cast<JSSecurityCallbacks *>(&NullSecurityCallbacks)),
   271     DOMcallbacks(nullptr),
   272     destroyPrincipals(nullptr),
   273     structuredCloneCallbacks(nullptr),
   274     telemetryCallback(nullptr),
   275     propertyRemovals(0),
   276 #if !EXPOSE_INTL_API
   277     thousandsSeparator(0),
   278     decimalSeparator(0),
   279     numGrouping(0),
   280 #endif
   281     mathCache_(nullptr),
   282     activeCompilations_(0),
   283     keepAtoms_(0),
   284     trustedPrincipals_(nullptr),
   285     beingDestroyed_(false),
   286     atoms_(nullptr),
   287     atomsCompartment_(nullptr),
   288     staticStrings(nullptr),
   289     commonNames(nullptr),
   290     permanentAtoms(nullptr),
   291     wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
   292     preserveWrapperCallback(nullptr),
   293 #ifdef DEBUG
   294     noGCOrAllocationCheck(0),
   295 #endif
   296     jitSupportsFloatingPoint(false),
   297     ionPcScriptCache(nullptr),
   298     threadPool(this),
   299     defaultJSContextCallback(nullptr),
   300     ctypesActivityCallback(nullptr),
   301     forkJoinWarmup(0),
   302     ionReturnOverride_(MagicValue(JS_ARG_POISON)),
   303     useHelperThreads_(useHelperThreads),
   304     parallelIonCompilationEnabled_(true),
   305     parallelParsingEnabled_(true),
   306     isWorkerRuntime_(false),
   307 #ifdef DEBUG
   308     enteredPolicy(nullptr),
   309 #endif
   310     largeAllocationFailureCallback(nullptr),
   311     oomCallback(nullptr)
   312 {
   313     liveRuntimesCount++;
   315     setGCMode(JSGC_MODE_GLOBAL);
   317     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
   318     JS_INIT_CLIST(&onNewGlobalObjectWatchers);
   320     PodZero(&debugHooks);
   321     PodArrayZero(nativeStackQuota);
   322     PodZero(&asmJSCacheOps);
   323 }
   325 static bool
   326 JitSupportsFloatingPoint()
   327 {
   328 #if defined(JS_ION)
   329     if (!JSC::MacroAssembler::supportsFloatingPoint())
   330         return false;
   332 #if defined(JS_ION) && WTF_ARM_ARCH_VERSION == 6
   333     if (!js::jit::hasVFP())
   334         return false;
   335 #endif
   337     return true;
   338 #else
   339     return false;
   340 #endif
   341 }
   343 bool
   344 JSRuntime::init(uint32_t maxbytes)
   345 {
   346 #ifdef JS_THREADSAFE
   347     ownerThread_ = PR_GetCurrentThread();
   349     interruptLock = PR_NewLock();
   350     if (!interruptLock)
   351         return false;
   353     gcLock = PR_NewLock();
   354     if (!gcLock)
   355         return false;
   357     exclusiveAccessLock = PR_NewLock();
   358     if (!exclusiveAccessLock)
   359         return false;
   360 #endif
   362     if (!mainThread.init())
   363         return false;
   365     js::TlsPerThreadData.set(&mainThread);
   367     if (!threadPool.init())
   368         return false;
   370     if (!js_InitGC(this, maxbytes))
   371         return false;
   373     if (!gcMarker.init(gcMode()))
   374         return false;
   376     const char *size = getenv("JSGC_MARK_STACK_LIMIT");
   377     if (size)
   378         SetMarkStackLimit(this, atoi(size));
   380     ScopedJSDeletePtr<Zone> atomsZone(new_<Zone>(this));
   381     if (!atomsZone)
   382         return false;
   384     JS::CompartmentOptions options;
   385     ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get(), options));
   386     if (!atomsCompartment || !atomsCompartment->init(nullptr))
   387         return false;
   389     zones.append(atomsZone.get());
   390     atomsZone->compartments.append(atomsCompartment.get());
   392     atomsCompartment->isSystem = true;
   393     atomsZone->isSystem = true;
   394     atomsZone->setGCLastBytes(8192, GC_NORMAL);
   396     atomsZone.forget();
   397     this->atomsCompartment_ = atomsCompartment.forget();
   399     if (!scriptDataTable_.init())
   400         return false;
   402     if (!evalCache.init())
   403         return false;
   405     /* The garbage collector depends on everything before this point being initialized. */
   406     gcInitialized = true;
   408     if (!InitRuntimeNumberState(this))
   409         return false;
   411     dateTimeInfo.updateTimeZoneAdjustment();
   413 #ifdef JS_ARM_SIMULATOR
   414     simulatorRuntime_ = js::jit::CreateSimulatorRuntime();
   415     if (!simulatorRuntime_)
   416         return false;
   417 #endif
   419     nativeStackBase = GetNativeStackBase();
   421     jitSupportsFloatingPoint = JitSupportsFloatingPoint();
   423 #ifdef JS_ION
   424     signalHandlersInstalled_ = EnsureAsmJSSignalHandlersInstalled(this);
   425 #endif
   427     if (!spsProfiler.init())
   428         return false;
   430     return true;
   431 }
   433 JSRuntime::~JSRuntime()
   434 {
   435     JS_ASSERT(!isHeapBusy());
   437     if (gcInitialized) {
   438         /* Free source hook early, as its destructor may want to delete roots. */
   439         sourceHook = nullptr;
   441         /*
   442          * Cancel any pending, in progress or completed Ion compilations and
   443          * parse tasks. Waiting for AsmJS and compression tasks is done
   444          * synchronously (on the main thread or during parse tasks), so no
   445          * explicit canceling is needed for these.
   446          */
   447         for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next())
   448             CancelOffThreadIonCompile(comp, nullptr);
   449         CancelOffThreadParses(this);
   451         /* Clear debugging state to remove GC roots. */
   452         for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next()) {
   453             comp->clearTraps(defaultFreeOp());
   454             if (WatchpointMap *wpmap = comp->watchpointMap)
   455                 wpmap->clear();
   456         }
   458         /* Clear atoms to remove GC roots and heap allocations. */
   459         finishAtoms();
   461         /*
   462          * Flag us as being destroyed. This allows the GC to free things like
   463          * interned atoms and Ion trampolines.
   464          */
   465         beingDestroyed_ = true;
   467         /* Allow the GC to release scripts that were being profiled. */
   468         profilingScripts = false;
   470         JS::PrepareForFullGC(this);
   471         GC(this, GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
   472     }
   474     /*
   475      * Clear the self-hosted global and delete self-hosted classes *after*
   476      * GC, as finalizers for objects check for clasp->finalize during GC.
   477      */
   478     finishSelfHosting();
   480 #ifdef JS_THREADSAFE
   481     JS_ASSERT(!exclusiveAccessOwner);
   482     if (exclusiveAccessLock)
   483         PR_DestroyLock(exclusiveAccessLock);
   485     // Avoid bogus asserts during teardown.
   486     JS_ASSERT(!numExclusiveThreads);
   487     mainThreadHasExclusiveAccess = true;
   489     JS_ASSERT(!interruptLockOwner);
   490     if (interruptLock)
   491         PR_DestroyLock(interruptLock);
   492 #endif
   494     /*
   495      * Even though all objects in the compartment are dead, we may have keep
   496      * some filenames around because of gcKeepAtoms.
   497      */
   498     FreeScriptData(this);
   500 #ifdef DEBUG
   501     /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
   502     if (hasContexts()) {
   503         unsigned cxcount = 0;
   504         for (ContextIter acx(this); !acx.done(); acx.next()) {
   505             fprintf(stderr,
   506 "JS API usage error: found live context at %p\n",
   507                     (void *) acx.get());
   508             cxcount++;
   509         }
   510         fprintf(stderr,
   511 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
   512                 cxcount, (cxcount == 1) ? "" : "s");
   513     }
   514 #endif
   516 #if !EXPOSE_INTL_API
   517     FinishRuntimeNumberState(this);
   518 #endif
   520     js_FinishGC(this);
   521     atomsCompartment_ = nullptr;
   523 #ifdef JS_THREADSAFE
   524     if (gcLock)
   525         PR_DestroyLock(gcLock);
   526 #endif
   528     js_free(defaultLocale);
   529     js_delete(bumpAlloc_);
   530     js_delete(mathCache_);
   531 #ifdef JS_ION
   532     js_delete(jitRuntime_);
   533 #endif
   534     js_delete(execAlloc_);  /* Delete after jitRuntime_. */
   536     js_delete(ionPcScriptCache);
   538 #ifdef JSGC_GENERATIONAL
   539     gcStoreBuffer.disable();
   540     gcNursery.disable();
   541 #endif
   543 #ifdef JS_ARM_SIMULATOR
   544     js::jit::DestroySimulatorRuntime(simulatorRuntime_);
   545 #endif
   547     DebugOnly<size_t> oldCount = liveRuntimesCount--;
   548     JS_ASSERT(oldCount > 0);
   550 #ifdef JS_THREADSAFE
   551     js::TlsPerThreadData.set(nullptr);
   552 #endif
   553 }
   555 void
   556 NewObjectCache::clearNurseryObjects(JSRuntime *rt)
   557 {
   558     for (unsigned i = 0; i < mozilla::ArrayLength(entries); ++i) {
   559         Entry &e = entries[i];
   560         JSObject *obj = reinterpret_cast<JSObject *>(&e.templateObject);
   561         if (IsInsideNursery(rt, e.key) ||
   562             IsInsideNursery(rt, obj->slots) ||
   563             IsInsideNursery(rt, obj->elements))
   564         {
   565             PodZero(&e);
   566         }
   567     }
   568 }
   570 void
   571 JSRuntime::resetJitStackLimit()
   572 {
   573     AutoLockForInterrupt lock(this);
   574     mainThread.setJitStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]);
   576 #ifdef JS_ARM_SIMULATOR
   577     mainThread.setJitStackLimit(js::jit::Simulator::StackLimit());
   578 #endif
   579  }
   581 void
   582 JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes)
   583 {
   584     // Several tables in the runtime enumerated below can be used off thread.
   585     AutoLockForExclusiveAccess lock(this);
   587     rtSizes->object += mallocSizeOf(this);
   589     rtSizes->atomsTable += atoms().sizeOfIncludingThis(mallocSizeOf);
   591     if (!parentRuntime) {
   592         rtSizes->atomsTable += mallocSizeOf(staticStrings);
   593         rtSizes->atomsTable += mallocSizeOf(commonNames);
   594         rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
   595     }
   597     for (ContextIter acx(this); !acx.done(); acx.next())
   598         rtSizes->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
   600     rtSizes->dtoa += mallocSizeOf(mainThread.dtoaState);
   602     rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
   604     rtSizes->regexpData += bumpAlloc_ ? bumpAlloc_->sizeOfNonHeapData() : 0;
   606     rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
   608     rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
   610     rtSizes->sourceDataCache += sourceDataCache.sizeOfExcludingThis(mallocSizeOf);
   612     rtSizes->scriptData += scriptDataTable().sizeOfExcludingThis(mallocSizeOf);
   613     for (ScriptDataTable::Range r = scriptDataTable().all(); !r.empty(); r.popFront())
   614         rtSizes->scriptData += mallocSizeOf(r.front());
   616     if (execAlloc_)
   617         execAlloc_->addSizeOfCode(&rtSizes->code);
   618 #ifdef JS_ION
   619     {
   620         AutoLockForInterrupt lock(this);
   621         if (jitRuntime()) {
   622             if (JSC::ExecutableAllocator *ionAlloc = jitRuntime()->ionAlloc(this))
   623                 ionAlloc->addSizeOfCode(&rtSizes->code);
   624         }
   625     }
   626 #endif
   628     rtSizes->gc.marker += gcMarker.sizeOfExcludingThis(mallocSizeOf);
   629 #ifdef JSGC_GENERATIONAL
   630     rtSizes->gc.nurseryCommitted += gcNursery.sizeOfHeapCommitted();
   631     rtSizes->gc.nurseryDecommitted += gcNursery.sizeOfHeapDecommitted();
   632     rtSizes->gc.nurseryHugeSlots += gcNursery.sizeOfHugeSlots(mallocSizeOf);
   633     gcStoreBuffer.addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc);
   634 #endif
   635 }
   637 static bool
   638 SignalBasedTriggersDisabled()
   639 {
   640   // Don't bother trying to cache the getenv lookup; this should be called
   641   // infrequently.
   642   return !!getenv("JS_DISABLE_SLOW_SCRIPT_SIGNALS");
   643 }
   645 void
   646 JSRuntime::requestInterrupt(InterruptMode mode)
   647 {
   648     AutoLockForInterrupt lock(this);
   650     /*
   651      * Invalidate ionTop to trigger its over-recursion check. Note this must be
   652      * set before interrupt, to avoid racing with js::InvokeInterruptCallback,
   653      * into a weird state where interrupt is stuck at 0 but jitStackLimit is
   654      * MAXADDR.
   655      */
   656     mainThread.setJitStackLimit(-1);
   658     interrupt = true;
   660 #ifdef JS_ION
   661 #ifdef JS_THREADSAFE
   662     RequestInterruptForForkJoin(this, mode);
   663 #endif
   665     /*
   666      * asm.js and, optionally, normal Ion code use memory protection and signal
   667      * handlers to halt running code.
   668      */
   669     if (!SignalBasedTriggersDisabled()) {
   670         RequestInterruptForAsmJSCode(this);
   671         jit::RequestInterruptForIonCode(this, mode);
   672     }
   673 #endif
   674 }
   676 JSC::ExecutableAllocator *
   677 JSRuntime::createExecutableAllocator(JSContext *cx)
   678 {
   679     JS_ASSERT(!execAlloc_);
   680     JS_ASSERT(cx->runtime() == this);
   682     execAlloc_ = js_new<JSC::ExecutableAllocator>();
   683     if (!execAlloc_)
   684         js_ReportOutOfMemory(cx);
   685     return execAlloc_;
   686 }
   688 WTF::BumpPointerAllocator *
   689 JSRuntime::createBumpPointerAllocator(JSContext *cx)
   690 {
   691     JS_ASSERT(!bumpAlloc_);
   692     JS_ASSERT(cx->runtime() == this);
   694     bumpAlloc_ = js_new<WTF::BumpPointerAllocator>();
   695     if (!bumpAlloc_)
   696         js_ReportOutOfMemory(cx);
   697     return bumpAlloc_;
   698 }
   700 MathCache *
   701 JSRuntime::createMathCache(JSContext *cx)
   702 {
   703     JS_ASSERT(!mathCache_);
   704     JS_ASSERT(cx->runtime() == this);
   706     MathCache *newMathCache = js_new<MathCache>();
   707     if (!newMathCache) {
   708         js_ReportOutOfMemory(cx);
   709         return nullptr;
   710     }
   712     mathCache_ = newMathCache;
   713     return mathCache_;
   714 }
   716 bool
   717 JSRuntime::setDefaultLocale(const char *locale)
   718 {
   719     if (!locale)
   720         return false;
   721     resetDefaultLocale();
   722     defaultLocale = JS_strdup(this, locale);
   723     return defaultLocale != nullptr;
   724 }
   726 void
   727 JSRuntime::resetDefaultLocale()
   728 {
   729     js_free(defaultLocale);
   730     defaultLocale = nullptr;
   731 }
   733 const char *
   734 JSRuntime::getDefaultLocale()
   735 {
   736     if (defaultLocale)
   737         return defaultLocale;
   739     char *locale, *lang, *p;
   740 #ifdef HAVE_SETLOCALE
   741     locale = setlocale(LC_ALL, nullptr);
   742 #else
   743     locale = getenv("LANG");
   744 #endif
   745     // convert to a well-formed BCP 47 language tag
   746     if (!locale || !strcmp(locale, "C"))
   747         locale = const_cast<char*>("und");
   748     lang = JS_strdup(this, locale);
   749     if (!lang)
   750         return nullptr;
   751     if ((p = strchr(lang, '.')))
   752         *p = '\0';
   753     while ((p = strchr(lang, '_')))
   754         *p = '-';
   756     defaultLocale = lang;
   757     return defaultLocale;
   758 }
   760 void
   761 JSRuntime::triggerActivityCallback(bool active)
   762 {
   763     if (!activityCallback)
   764         return;
   766     /*
   767      * The activity callback must not trigger a GC: it would create a cirular
   768      * dependency between entering a request and Rooted's requirement of being
   769      * in a request. In practice this callback already cannot trigger GC. The
   770      * suppression serves to inform the exact rooting hazard analysis of this
   771      * property and ensures that it remains true in the future.
   772      */
   773     AutoSuppressGC suppress(this);
   775     activityCallback(activityCallbackArg, active);
   776 }
   778 void
   779 JSRuntime::setGCMaxMallocBytes(size_t value)
   780 {
   781     /*
   782      * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
   783      * mean that value.
   784      */
   785     gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
   786     resetGCMallocBytes();
   787     for (ZonesIter zone(this, WithAtoms); !zone.done(); zone.next())
   788         zone->setGCMaxMallocBytes(value);
   789 }
   791 void
   792 JSRuntime::updateMallocCounter(size_t nbytes)
   793 {
   794     updateMallocCounter(nullptr, nbytes);
   795 }
   797 void
   798 JSRuntime::updateMallocCounter(JS::Zone *zone, size_t nbytes)
   799 {
   800     /* We tolerate any thread races when updating gcMallocBytes. */
   801     gcMallocBytes -= ptrdiff_t(nbytes);
   802     if (MOZ_UNLIKELY(gcMallocBytes <= 0))
   803         onTooMuchMalloc();
   804     else if (zone)
   805         zone->updateMallocCounter(nbytes);
   806 }
   808 JS_FRIEND_API(void)
   809 JSRuntime::onTooMuchMalloc()
   810 {
   811     if (!CurrentThreadCanAccessRuntime(this))
   812         return;
   814     if (!gcMallocGCTriggered)
   815         gcMallocGCTriggered = TriggerGC(this, JS::gcreason::TOO_MUCH_MALLOC);
   816 }
   818 JS_FRIEND_API(void *)
   819 JSRuntime::onOutOfMemory(void *p, size_t nbytes)
   820 {
   821     return onOutOfMemory(p, nbytes, nullptr);
   822 }
   824 JS_FRIEND_API(void *)
   825 JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
   826 {
   827     if (isHeapBusy())
   828         return nullptr;
   830     /*
   831      * Retry when we are done with the background sweeping and have stopped
   832      * all the allocations and released the empty GC chunks.
   833      */
   834     JS::ShrinkGCBuffers(this);
   835     gcHelperThread.waitBackgroundSweepOrAllocEnd();
   836     if (!p)
   837         p = js_malloc(nbytes);
   838     else if (p == reinterpret_cast<void *>(1))
   839         p = js_calloc(nbytes);
   840     else
   841       p = js_realloc(p, nbytes);
   842     if (p)
   843         return p;
   844     if (cx)
   845         js_ReportOutOfMemory(cx);
   846     return nullptr;
   847 }
   849 bool
   850 JSRuntime::activeGCInAtomsZone()
   851 {
   852     Zone *zone = atomsCompartment_->zone();
   853     return zone->needsBarrier() || zone->isGCScheduled() || zone->wasGCStarted();
   854 }
   856 #ifdef JS_THREADSAFE
   858 void
   859 JSRuntime::setUsedByExclusiveThread(Zone *zone)
   860 {
   861     JS_ASSERT(!zone->usedByExclusiveThread);
   862     zone->usedByExclusiveThread = true;
   863     numExclusiveThreads++;
   864 }
   866 void
   867 JSRuntime::clearUsedByExclusiveThread(Zone *zone)
   868 {
   869     JS_ASSERT(zone->usedByExclusiveThread);
   870     zone->usedByExclusiveThread = false;
   871     numExclusiveThreads--;
   872 }
   874 bool
   875 js::CurrentThreadCanAccessRuntime(JSRuntime *rt)
   876 {
   877     return rt->ownerThread_ == PR_GetCurrentThread() && !InParallelSection();
   878 }
   880 bool
   881 js::CurrentThreadCanAccessZone(Zone *zone)
   882 {
   883     if (CurrentThreadCanAccessRuntime(zone->runtime_))
   884         return true;
   885     if (InParallelSection()) {
   886         DebugOnly<PerThreadData *> pt = js::TlsPerThreadData.get();
   887         JS_ASSERT(pt && pt->associatedWith(zone->runtime_));
   888         return true;
   889     }
   891     // Only zones in use by an exclusive thread can be used off the main thread
   892     // or outside of PJS. We don't keep track of which thread owns such zones
   893     // though, so this check is imperfect.
   894     return zone->usedByExclusiveThread;
   895 }
   897 #else // JS_THREADSAFE
   899 bool
   900 js::CurrentThreadCanAccessRuntime(JSRuntime *rt)
   901 {
   902     return true;
   903 }
   905 bool
   906 js::CurrentThreadCanAccessZone(Zone *zone)
   907 {
   908     return true;
   909 }
   911 #endif // JS_THREADSAFE
   913 #ifdef DEBUG
   915 void
   916 JSRuntime::assertCanLock(RuntimeLock which)
   917 {
   918 #ifdef JS_THREADSAFE
   919     // In the switch below, each case falls through to the one below it. None
   920     // of the runtime locks are reentrant, and when multiple locks are acquired
   921     // it must be done in the order below.
   922     switch (which) {
   923       case ExclusiveAccessLock:
   924         JS_ASSERT(exclusiveAccessOwner != PR_GetCurrentThread());
   925       case WorkerThreadStateLock:
   926         JS_ASSERT(!WorkerThreadState().isLocked());
   927       case InterruptLock:
   928         JS_ASSERT(!currentThreadOwnsInterruptLock());
   929       case GCLock:
   930         JS_ASSERT(gcLockOwner != PR_GetCurrentThread());
   931         break;
   932       default:
   933         MOZ_CRASH();
   934     }
   935 #endif // JS_THREADSAFE
   936 }
   938 void
   939 js::AssertCurrentThreadCanLock(RuntimeLock which)
   940 {
   941 #ifdef JS_THREADSAFE
   942     PerThreadData *pt = TlsPerThreadData.get();
   943     if (pt && pt->runtime_)
   944         pt->runtime_->assertCanLock(which);
   945 #endif
   946 }
   948 #endif // DEBUG

mercurial