void Statistics::endGC() { for (auto j : MakeRange(NumTimingArrays)) for (int i = 0; i < PHASE_LIMIT; i++) phaseTotals[j][i] += phaseTimes[j][i]; int64_t total, longest; gcDuration(&total, &longest); int64_t sccTotal, sccLongest; sccDurations(&sccTotal, &sccLongest); runtime->addTelemetry(JS_TELEMETRY_GC_IS_COMPARTMENTAL, !zoneStats.isCollectingAllZones()); runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total)); runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest)); int64_t markTotal = SumPhase(PHASE_MARK, phaseTimes); int64_t markRootsTotal = SumPhase(PHASE_MARK_ROOTS, phaseTimes); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, t(markTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP])); if (runtime->gc.isCompactingGc()) { runtime->addTelemetry(JS_TELEMETRY_GC_COMPACT_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_COMPACT])); } runtime->addTelemetry(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(markRootsTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP_MARK_GRAY])); runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL, !!nonincrementalReason_); runtime->addTelemetry(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.isIncrementalGCAllowed()); runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest)); if (!aborted) { double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC); runtime->addTelemetry(JS_TELEMETRY_GC_MMU_50, mmu50 * 100); } if (fp) printStats(); // Clear the timers at the end of a GC because we accumulate time in // between GCs for some (which come before PHASE_GC_BEGIN in the list.) PodZero(&phaseStartTimes[PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); for (size_t d = PHASE_DAG_NONE; d < NumTimingArrays; d++) PodZero(&phaseTimes[d][PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); // Clear the OOM flag but only if we are not in a nested GC. if (gcDepth == 1) aborted = false; }
bool js_ReportErrorVA(JSContext *cx, unsigned flags, const char *format, va_list ap) { char *message; jschar *ucmessage; size_t messagelen; JSErrorReport report; bool warning; if (checkReportFlags(cx, &flags)) return true; message = JS_vsmprintf(format, ap); if (!message) return false; messagelen = strlen(message); PodZero(&report); report.flags = flags; report.errorNumber = JSMSG_USER_DEFINED_ERROR; report.ucmessage = ucmessage = InflateString(cx, message, &messagelen); PopulateReportBlame(cx, &report); warning = JSREPORT_IS_WARNING(report.flags); ReportError(cx, message, &report, nullptr, nullptr); js_free(message); js_free(ucmessage); return warning; }
/* * Since memory has been exhausted, avoid the normal error-handling path which * allocates an error object, report and callstack. If code is running, simply * throw the static atom "out of memory". If code is not running, call the * error reporter directly. * * Furthermore, callers of js_ReportOutOfMemory (viz., malloc) assume a GC does * not occur, so GC must be avoided or suppressed. */ void js_ReportOutOfMemory(ThreadSafeContext *cxArg) { if (!cxArg->isJSContext()) return; JSContext *cx = cxArg->asJSContext(); cx->runtime()->hadOutOfMemory = true; if (JS_IsRunning(cx)) { cx->setPendingException(StringValue(cx->names().outOfMemory)); return; } /* Get the message for this error, but we don't expand any arguments. */ const JSErrorFormatString *efs = js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY); const char *msg = efs ? efs->format : "Out of memory"; /* Fill out the report, but don't do anything that requires allocation. */ JSErrorReport report; PodZero(&report); report.flags = JSREPORT_ERROR; report.errorNumber = JSMSG_OUT_OF_MEMORY; PopulateReportBlame(cx, &report); /* Report the error. */ if (JSErrorReporter onError = cx->errorReporter) { AutoSuppressGC suppressGC(cx); onError(cx, msg, &report); } }
/* * We don't post an exception in this case, since doing so runs into * complications of pre-allocating an exception object which required * running the Exception class initializer early etc. * Instead we just invoke the errorReporter with an "Out Of Memory" * type message, and then hope the process ends swiftly. */ void js_ReportOutOfMemory(JSContext *cx) { cx->runtime->hadOutOfMemory = true; JSErrorReport report; JSErrorReporter onError = cx->errorReporter; /* Get the message for this error, but we won't expand any arguments. */ const JSErrorFormatString *efs = js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY); const char *msg = efs ? efs->format : "Out of memory"; /* Fill out the report, but don't do anything that requires allocation. */ PodZero(&report); report.flags = JSREPORT_ERROR; report.errorNumber = JSMSG_OUT_OF_MEMORY; PopulateReportBlame(cx, &report); /* * We clear a pending exception, if any, now so the hook can replace the * out-of-memory error by a script-catchable exception. */ cx->clearPendingException(); if (onError) { AutoSuppressGC suppressGC(cx); onError(cx, msg, &report); } }
void Statistics::endGC() { for (size_t j = 0; j < MAX_MULTIPARENT_PHASES + 1; j++) for (int i = 0; i < PHASE_LIMIT; i++) phaseTotals[j][i] += phaseTimes[j][i]; int64_t total, longest; gcDuration(&total, &longest); int64_t sccTotal, sccLongest; sccDurations(&sccTotal, &sccLongest); runtime->addTelemetry(JS_TELEMETRY_GC_IS_COMPARTMENTAL, !zoneStats.isCollectingAllZones()); runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total)); runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest)); int64_t markTotal = SumPhase(PHASE_MARK, phaseTimes); int64_t markRootsTotal = SumPhase(PHASE_MARK_ROOTS, phaseTimes); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, t(markTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP])); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(markRootsTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP_MARK_GRAY])); runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL, !!nonincrementalReason_); runtime->addTelemetry(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.isIncrementalGCAllowed()); runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest)); if (!aborted) { double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC); runtime->addTelemetry(JS_TELEMETRY_GC_MMU_50, mmu50 * 100); } if (fp) printStats(); if (!aborted) Debugger::onGarbageCollection(runtime, *this); // Clear the timers at the end of a GC because we accumulate time in // between GCs for some (which come before PHASE_GC_BEGIN in the list.) PodZero(&phaseStartTimes[PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); for (size_t d = PHASE_DAG_NONE; d < MAX_MULTIPARENT_PHASES + 1; d++) PodZero(&phaseTimes[d][PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); aborted = false; }
/* * Since memory has been exhausted, avoid the normal error-handling path which * allocates an error object, report and callstack. If code is running, simply * throw the static atom "out of memory". If code is not running, call the * error reporter directly. * * Furthermore, callers of js_ReportOutOfMemory (viz., malloc) assume a GC does * not occur, so GC must be avoided or suppressed. */ void js_ReportOutOfMemory(ThreadSafeContext *cxArg) { #ifdef JS_MORE_DETERMINISTIC /* * OOMs are non-deterministic, especially across different execution modes * (e.g. interpreter vs JIT). In more-deterministic builds, print to stderr * so that the fuzzers can detect this. */ fprintf(stderr, "js_ReportOutOfMemory called\n"); #endif if (cxArg->isForkJoinSlice()) { cxArg->asForkJoinSlice()->setPendingAbortFatal(ParallelBailoutOutOfMemory); return; } if (!cxArg->isJSContext()) return; JSContext *cx = cxArg->asJSContext(); cx->runtime()->hadOutOfMemory = true; if (JS_IsRunning(cx)) { cx->setPendingException(StringValue(cx->names().outOfMemory)); return; } /* Get the message for this error, but we don't expand any arguments. */ const JSErrorFormatString *efs = js_GetLocalizedErrorMessage(cx, nullptr, nullptr, JSMSG_OUT_OF_MEMORY); const char *msg = efs ? efs->format : "Out of memory"; /* Fill out the report, but don't do anything that requires allocation. */ JSErrorReport report; PodZero(&report); report.flags = JSREPORT_ERROR; report.errorNumber = JSMSG_OUT_OF_MEMORY; PopulateReportBlame(cx, &report); /* Report the error. */ if (JSErrorReporter onError = cx->errorReporter) { AutoSuppressGC suppressGC(cx); onError(cx, msg, &report); } /* * We would like to enforce the invariant that any exception reported * during an OOM situation does not require wrapping. Besides avoiding * allocation when memory is low, this reduces the number of places where * we might need to GC. * * When JS code is running, we set the pending exception to an atom, which * does not need wrapping. If no JS code is running, no exception should be * set at all. */ JS_ASSERT(!cx->isExceptionPending()); }
NativeIterator* NativeIterator::allocateIterator(JSContext* cx, uint32_t numGuards, uint32_t plength) { JS_STATIC_ASSERT(sizeof(ReceiverGuard) == 2 * sizeof(void*)); size_t extraLength = plength + numGuards * 2; NativeIterator* ni = cx->zone()->pod_malloc_with_extra<NativeIterator, void*>(extraLength); if (!ni) { ReportOutOfMemory(cx); return nullptr; } void** extra = reinterpret_cast<void**>(ni + 1); PodZero(ni); PodZero(extra, extraLength); ni->props_array = ni->props_cursor = reinterpret_cast<GCPtrFlatString*>(extra); ni->props_end = ni->props_array + plength; return ni; }
Statistics::Statistics(JSRuntime* rt) : runtime(rt), startupTime(PRMJ_Now()), fp(nullptr), gcDepth(0), nonincrementalReason_(gc::AbortReason::None), timedGCStart(0), preBytes(0), maxPauseInInterval(0), phaseNestingDepth(0), activeDagSlot(PHASE_DAG_NONE), suspended(0), sliceCallback(nullptr), nurseryCollectionCallback(nullptr), aborted(false), enableProfiling_(false), sliceCount_(0) { PodArrayZero(phaseTotals); PodArrayZero(counts); PodArrayZero(phaseStartTimes); for (auto d : MakeRange(NumTimingArrays)) PodArrayZero(phaseTimes[d]); const char* env = getenv("MOZ_GCTIMER"); if (env) { if (strcmp(env, "none") == 0) { fp = nullptr; } else if (strcmp(env, "stdout") == 0) { fp = stdout; } else if (strcmp(env, "stderr") == 0) { fp = stderr; } else { fp = fopen(env, "a"); if (!fp) MOZ_CRASH("Failed to open MOZ_GCTIMER log file."); } } env = getenv("JS_GC_PROFILE"); if (env) { if (0 == strcmp(env, "help")) { fprintf(stderr, "JS_GC_PROFILE=N\n" "\tReport major GC's taking more than N milliseconds.\n"); exit(0); } enableProfiling_ = true; profileThreshold_ = atoi(env); } PodZero(&totalTimes_); }
CodeRange::CodeRange(Kind kind, Offsets offsets) : funcIndex_(0), funcLineOrBytecode_(0), begin_(offsets.begin), profilingReturn_(0), end_(offsets.end) { PodZero(&u); // zero padding for Valgrind u.kind_ = kind; MOZ_ASSERT(begin_ <= end_); MOZ_ASSERT(u.kind_ == Entry || u.kind_ == Inline); }
CodeRange::CodeRange(Kind kind, ProfilingOffsets offsets) : funcIndex_(0), funcLineOrBytecode_(0), begin_(offsets.begin), profilingReturn_(offsets.profilingReturn), end_(offsets.end) { PodZero(&u); // zero padding for Valgrind u.kind_ = kind; MOZ_ASSERT(begin_ < profilingReturn_); MOZ_ASSERT(profilingReturn_ < end_); MOZ_ASSERT(u.kind_ == ImportJitExit || u.kind_ == ImportInterpExit || u.kind_ == Interrupt); }
void NewObjectCache::clearNurseryObjects(JSRuntime* rt) { for (unsigned i = 0; i < mozilla::ArrayLength(entries); ++i) { Entry& e = entries[i]; NativeObject* obj = reinterpret_cast<NativeObject*>(&e.templateObject); if (IsInsideNursery(e.key) || rt->gc.nursery.isInside(obj->slots_) || rt->gc.nursery.isInside(obj->elements_)) { PodZero(&e); } } }
void Statistics::endGC() { crash::SnapshotGCStack(); for (int i = 0; i < PHASE_LIMIT; i++) phaseTotals[i] += phaseTimes[i]; int64_t total, longest; gcDuration(&total, &longest); int64_t sccTotal, sccLongest; sccDurations(&sccTotal, &sccLongest); runtime->addTelemetry(JS_TELEMETRY_GC_IS_COMPARTMENTAL, !zoneStats.isCollectingAllZones()); runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total)); runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest)); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, t(phaseTimes[PHASE_MARK])); runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_SWEEP])); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(phaseTimes[PHASE_MARK_ROOTS])); runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_SWEEP_MARK_GRAY])); runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL, !!nonincrementalReason); runtime->addTelemetry(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.isIncrementalGCAllowed()); runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal)); runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest)); double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC); runtime->addTelemetry(JS_TELEMETRY_GC_MMU_50, mmu50 * 100); if (fp) printStats(); // Clear the timers at the end of a GC because we accumulate time in // between GCs for some (which come before PHASE_GC_BEGIN in the list.) PodZero(&phaseStartTimes[PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); PodZero(&phaseTimes[PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); }
NativeIterator* NativeIterator::allocateSentinel(JSContext* maybecx) { NativeIterator* ni = js_pod_malloc<NativeIterator>(); if (!ni) { if (maybecx) ReportOutOfMemory(maybecx); return nullptr; } PodZero(ni); ni->next_ = ni; ni->prev_ = ni; return ni; }
void NewObjectCache::clearNurseryObjects(JSRuntime *rt) { #ifdef JSGC_GENERATIONAL for (unsigned i = 0; i < mozilla::ArrayLength(entries); ++i) { Entry &e = entries[i]; JSObject *obj = reinterpret_cast<JSObject *>(&e.templateObject); if (IsInsideNursery(e.key) || rt->gc.nursery.isInside(obj->slots) || rt->gc.nursery.isInside(obj->elements)) { PodZero(&e); } } #endif }
/* * Since memory has been exhausted, avoid the normal error-handling path which * allocates an error object, report and callstack. If code is running, simply * throw the static atom "out of memory". If code is not running, call the * error reporter directly. * * Furthermore, callers of js_ReportOutOfMemory (viz., malloc) assume a GC does * not occur, so GC must be avoided or suppressed. */ void js_ReportOutOfMemory(ThreadSafeContext *cxArg) { if (!cxArg->isJSContext()) return; JSContext *cx = cxArg->asJSContext(); cx->runtime()->hadOutOfMemory = true; if (JS_IsRunning(cx)) { cx->setPendingException(StringValue(cx->names().outOfMemory)); return; } /* Get the message for this error, but we don't expand any arguments. */ const JSErrorFormatString *efs = js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY); const char *msg = efs ? efs->format : "Out of memory"; /* Fill out the report, but don't do anything that requires allocation. */ JSErrorReport report; PodZero(&report); report.flags = JSREPORT_ERROR; report.errorNumber = JSMSG_OUT_OF_MEMORY; PopulateReportBlame(cx, &report); /* Report the error. */ if (JSErrorReporter onError = cx->errorReporter) { AutoSuppressGC suppressGC(cx); onError(cx, msg, &report); } /* * We would like to enforce the invariant that any exception reported * during an OOM situation does not require wrapping. Besides avoiding * allocation when memory is low, this reduces the number of places where * we might need to GC. * * When JS code is running, we set the pending exception to an atom, which * does not need wrapping. If no JS code is running, no exception should be * set at all. */ JS_ASSERT(!cx->isExceptionPending()); }
CodeRange::CodeRange(uint32_t funcIndex, uint32_t funcLineOrBytecode, FuncOffsets offsets) : funcIndex_(funcIndex), funcLineOrBytecode_(funcLineOrBytecode) { PodZero(&u); // zero padding for Valgrind u.kind_ = Function; MOZ_ASSERT(offsets.nonProfilingEntry - offsets.begin <= UINT8_MAX); begin_ = offsets.begin; u.func.beginToEntry_ = offsets.nonProfilingEntry - begin_; MOZ_ASSERT(offsets.nonProfilingEntry < offsets.profilingReturn); MOZ_ASSERT(offsets.profilingReturn - offsets.profilingJump <= UINT8_MAX); MOZ_ASSERT(offsets.profilingReturn - offsets.profilingEpilogue <= UINT8_MAX); profilingReturn_ = offsets.profilingReturn; u.func.profilingJumpToProfilingReturn_ = profilingReturn_ - offsets.profilingJump; u.func.profilingEpilogueToProfilingReturn_ = profilingReturn_ - offsets.profilingEpilogue; MOZ_ASSERT(offsets.nonProfilingEntry < offsets.end); end_ = offsets.end; }
JSRuntime::JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThreads) : JS::shadow::Runtime( #ifdef JSGC_GENERATIONAL &gc.storeBuffer #endif ), mainThread(this), parentRuntime(parentRuntime), interrupt(false), #if defined(JS_THREADSAFE) && defined(JS_ION) interruptPar(false), #endif handlingSignal(false), interruptCallback(nullptr), #ifdef JS_THREADSAFE interruptLock(nullptr), interruptLockOwner(nullptr), exclusiveAccessLock(nullptr), exclusiveAccessOwner(nullptr), mainThreadHasExclusiveAccess(false), numExclusiveThreads(0), #else interruptLockTaken(false), #endif numCompartments(0), localeCallbacks(nullptr), defaultLocale(nullptr), defaultVersion_(JSVERSION_DEFAULT), #ifdef JS_THREADSAFE ownerThread_(nullptr), #endif tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), freeLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), execAlloc_(nullptr), #ifdef JS_YARR bumpAlloc_(nullptr), #endif jitRuntime_(nullptr), selfHostingGlobal_(nullptr), nativeStackBase(0), cxCallback(nullptr), destroyCompartmentCallback(nullptr), destroyZoneCallback(nullptr), sweepZoneCallback(nullptr), compartmentNameCallback(nullptr), activityCallback(nullptr), activityCallbackArg(nullptr), #ifdef JS_THREADSAFE requestDepth(0), # ifdef DEBUG checkRequestDepth(0), # endif #endif #ifdef DEBUG activeContext(nullptr), #endif gc(thisFromCtor()), gcInitialized(false), #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR) simulatorRuntime_(nullptr), #endif NaNValue(DoubleNaNValue()), negativeInfinityValue(DoubleValue(NegativeInfinity<double>())), positiveInfinityValue(DoubleValue(PositiveInfinity<double>())), emptyString(nullptr), debugMode(false), spsProfiler(thisFromCtor()), profilingScripts(false), hadOutOfMemory(false), haveCreatedContext(false), data(nullptr), signalHandlersInstalled_(false), defaultFreeOp_(thisFromCtor(), false), debuggerMutations(0), securityCallbacks(const_cast<JSSecurityCallbacks *>(&NullSecurityCallbacks)), DOMcallbacks(nullptr), destroyPrincipals(nullptr), structuredCloneCallbacks(nullptr), telemetryCallback(nullptr), propertyRemovals(0), #if !EXPOSE_INTL_API thousandsSeparator(0), decimalSeparator(0), numGrouping(0), #endif mathCache_(nullptr), activeCompilations_(0), keepAtoms_(0), trustedPrincipals_(nullptr), beingDestroyed_(false), atoms_(nullptr), atomsCompartment_(nullptr), staticStrings(nullptr), commonNames(nullptr), permanentAtoms(nullptr), wrapObjectCallbacks(&DefaultWrapObjectCallbacks), preserveWrapperCallback(nullptr), jitSupportsFloatingPoint(false), ionPcScriptCache(nullptr), threadPool(this), defaultJSContextCallback(nullptr), ctypesActivityCallback(nullptr), forkJoinWarmup(0), useHelperThreads_(useHelperThreads), parallelIonCompilationEnabled_(true), parallelParsingEnabled_(true), isWorkerRuntime_(false), #ifdef DEBUG enteredPolicy(nullptr), #endif largeAllocationFailureCallback(nullptr), oomCallback(nullptr) { liveRuntimesCount++; setGCMode(JSGC_MODE_GLOBAL); /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ JS_INIT_CLIST(&onNewGlobalObjectWatchers); PodZero(&debugHooks); PodArrayZero(nativeStackQuota); PodZero(&asmJSCacheOps); }
JSRuntime::JSRuntime(JSRuntime* parentRuntime) : mainThread(this), jitTop(nullptr), jitJSContext(nullptr), jitActivation(nullptr), jitStackLimit_(0xbad), jitStackLimitNoInterrupt_(0xbad), activation_(nullptr), profilingActivation_(nullptr), profilerSampleBufferGen_(0), profilerSampleBufferLapCount_(1), wasmActivationStack_(nullptr), asyncStackForNewActivations(this), asyncCauseForNewActivations(nullptr), asyncCallIsExplicit(false), entryMonitor(nullptr), noExecuteDebuggerTop(nullptr), parentRuntime(parentRuntime), #ifdef DEBUG updateChildRuntimeCount(parentRuntime), #endif interrupt_(false), telemetryCallback(nullptr), handlingSegFault(false), handlingJitInterrupt_(false), interruptCallback(nullptr), enqueuePromiseJobCallback(nullptr), enqueuePromiseJobCallbackData(nullptr), #ifdef DEBUG exclusiveAccessOwner(nullptr), mainThreadHasExclusiveAccess(false), #endif numExclusiveThreads(0), numCompartments(0), localeCallbacks(nullptr), defaultLocale(nullptr), defaultVersion_(JSVERSION_DEFAULT), ownerThread_(nullptr), ownerThreadNative_(0), tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), jitRuntime_(nullptr), selfHostingGlobal_(nullptr), nativeStackBase(GetNativeStackBase()), cxCallback(nullptr), destroyCompartmentCallback(nullptr), sizeOfIncludingThisCompartmentCallback(nullptr), destroyZoneCallback(nullptr), sweepZoneCallback(nullptr), compartmentNameCallback(nullptr), activityCallback(nullptr), activityCallbackArg(nullptr), requestDepth(0), #ifdef DEBUG checkRequestDepth(0), activeContext(nullptr), #endif gc(thisFromCtor()), gcInitialized(false), #ifdef JS_SIMULATOR simulator_(nullptr), #endif scriptAndCountsVector(nullptr), lcovOutput(), NaNValue(DoubleNaNValue()), negativeInfinityValue(DoubleValue(NegativeInfinity<double>())), positiveInfinityValue(DoubleValue(PositiveInfinity<double>())), emptyString(nullptr), spsProfiler(thisFromCtor()), profilingScripts(false), suppressProfilerSampling(false), hadOutOfMemory(false), #ifdef DEBUG handlingInitFailure(false), #endif haveCreatedContext(false), allowRelazificationForTesting(false), data(nullptr), signalHandlersInstalled_(false), canUseSignalHandlers_(false), defaultFreeOp_(thisFromCtor()), debuggerMutations(0), securityCallbacks(&NullSecurityCallbacks), DOMcallbacks(nullptr), destroyPrincipals(nullptr), readPrincipals(nullptr), errorReporter(nullptr), buildIdOp(nullptr), propertyRemovals(0), #if !EXPOSE_INTL_API thousandsSeparator(0), decimalSeparator(0), numGrouping(0), #endif mathCache_(nullptr), activeCompilations_(0), keepAtoms_(0), trustedPrincipals_(nullptr), beingDestroyed_(false), atoms_(nullptr), atomsCompartment_(nullptr), staticStrings(nullptr), commonNames(nullptr), permanentAtoms(nullptr), wellKnownSymbols(nullptr), wrapObjectCallbacks(&DefaultWrapObjectCallbacks), preserveWrapperCallback(nullptr), jitSupportsFloatingPoint(false), jitSupportsSimd(false), ionPcScriptCache(nullptr), scriptEnvironmentPreparer(nullptr), ctypesActivityCallback(nullptr), windowProxyClass_(nullptr), offthreadIonCompilationEnabled_(true), parallelParsingEnabled_(true), autoWritableJitCodeActive_(false), #ifdef DEBUG enteredPolicy(nullptr), #endif largeAllocationFailureCallback(nullptr), oomCallback(nullptr), debuggerMallocSizeOf(ReturnZeroSize), lastAnimationTime(0), performanceMonitoring(thisFromCtor()) { setGCStoreBufferPtr(&gc.storeBuffer); liveRuntimesCount++; /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ JS_INIT_CLIST(&onNewGlobalObjectWatchers); PodArrayZero(nativeStackQuota); PodZero(&asmJSCacheOps); lcovOutput.init(); }
JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) : JS::shadow::Runtime( #ifdef JSGC_GENERATIONAL &gcStoreBuffer #endif ), mainThread(this), interrupt(0), handlingSignal(false), operationCallback(nullptr), #ifdef JS_THREADSAFE operationCallbackLock(nullptr), operationCallbackOwner(nullptr), #else operationCallbackLockTaken(false), #endif #ifdef JS_WORKER_THREADS workerThreadState(nullptr), exclusiveAccessLock(nullptr), exclusiveAccessOwner(nullptr), mainThreadHasExclusiveAccess(false), numExclusiveThreads(0), #endif systemZone(nullptr), numCompartments(0), localeCallbacks(nullptr), defaultLocale(nullptr), defaultVersion_(JSVERSION_DEFAULT), #ifdef JS_THREADSAFE ownerThread_(nullptr), #endif tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), freeLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), execAlloc_(nullptr), bumpAlloc_(nullptr), jitRuntime_(nullptr), selfHostingGlobal_(nullptr), nativeStackBase(0), cxCallback(nullptr), destroyCompartmentCallback(nullptr), destroyZoneCallback(nullptr), sweepZoneCallback(nullptr), compartmentNameCallback(nullptr), activityCallback(nullptr), activityCallbackArg(nullptr), #ifdef JS_THREADSAFE requestDepth(0), # ifdef DEBUG checkRequestDepth(0), # endif #endif gcSystemAvailableChunkListHead(nullptr), gcUserAvailableChunkListHead(nullptr), gcBytes(0), gcMaxBytes(0), gcMaxMallocBytes(0), gcNumArenasFreeCommitted(0), gcMarker(this), gcVerifyPreData(nullptr), gcVerifyPostData(nullptr), gcChunkAllocationSinceLastGC(false), gcNextFullGCTime(0), gcLastGCTime(0), gcJitReleaseTime(0), gcAllocationThreshold(30 * 1024 * 1024), gcHighFrequencyGC(false), gcHighFrequencyTimeThreshold(1000), gcHighFrequencyLowLimitBytes(100 * 1024 * 1024), gcHighFrequencyHighLimitBytes(500 * 1024 * 1024), gcHighFrequencyHeapGrowthMax(3.0), gcHighFrequencyHeapGrowthMin(1.5), gcLowFrequencyHeapGrowth(1.5), gcDynamicHeapGrowth(false), gcDynamicMarkSlice(false), gcDecommitThreshold(32 * 1024 * 1024), gcShouldCleanUpEverything(false), gcGrayBitsValid(false), gcIsNeeded(0), gcStats(thisFromCtor()), gcNumber(0), gcStartNumber(0), gcIsFull(false), gcTriggerReason(JS::gcreason::NO_REASON), gcStrictCompartmentChecking(false), #ifdef DEBUG gcDisableStrictProxyCheckingCount(0), #endif gcIncrementalState(gc::NO_INCREMENTAL), gcLastMarkSlice(false), gcSweepOnBackgroundThread(false), gcFoundBlackGrayEdges(false), gcSweepingZones(nullptr), gcZoneGroupIndex(0), gcZoneGroups(nullptr), gcCurrentZoneGroup(nullptr), gcSweepPhase(0), gcSweepZone(nullptr), gcSweepKindIndex(0), gcAbortSweepAfterCurrentGroup(false), gcArenasAllocatedDuringSweep(nullptr), #ifdef DEBUG gcMarkingValidator(nullptr), #endif gcInterFrameGC(0), gcSliceBudget(SliceBudget::Unlimited), gcIncrementalEnabled(true), gcGenerationalEnabled(true), gcManipulatingDeadZones(false), gcObjectsMarkedInDeadZones(0), gcPoke(false), heapState(Idle), #ifdef JSGC_GENERATIONAL gcNursery(thisFromCtor()), gcStoreBuffer(thisFromCtor(), gcNursery), #endif #ifdef JS_GC_ZEAL gcZeal_(0), gcZealFrequency(0), gcNextScheduled(0), gcDeterministicOnly(false), gcIncrementalLimit(0), #endif gcValidate(true), gcFullCompartmentChecks(false), gcCallback(nullptr), gcSliceCallback(nullptr), gcFinalizeCallback(nullptr), gcMallocBytes(0), gcMallocGCTriggered(false), scriptAndCountsVector(nullptr), NaNValue(DoubleNaNValue()), negativeInfinityValue(DoubleValue(NegativeInfinity())), positiveInfinityValue(DoubleValue(PositiveInfinity())), emptyString(nullptr), debugMode(false), spsProfiler(thisFromCtor()), profilingScripts(false), alwaysPreserveCode(false), hadOutOfMemory(false), haveCreatedContext(false), data(nullptr), gcLock(nullptr), gcLockOwner(nullptr), gcHelperThread(thisFromCtor()), signalHandlersInstalled_(false), defaultFreeOp_(thisFromCtor(), false), debuggerMutations(0), securityCallbacks(const_cast<JSSecurityCallbacks *>(&NullSecurityCallbacks)), DOMcallbacks(nullptr), destroyPrincipals(nullptr), structuredCloneCallbacks(nullptr), telemetryCallback(nullptr), propertyRemovals(0), #if !EXPOSE_INTL_API thousandsSeparator(0), decimalSeparator(0), numGrouping(0), #endif heapProtected_(false), mathCache_(nullptr), activeCompilations_(0), keepAtoms_(0), trustedPrincipals_(nullptr), atomsCompartment_(nullptr), beingDestroyed_(false), wrapObjectCallback(TransparentObjectWrapper), sameCompartmentWrapObjectCallback(nullptr), preWrapObjectCallback(nullptr), preserveWrapperCallback(nullptr), #ifdef DEBUG noGCOrAllocationCheck(0), #endif jitHardening(false), jitSupportsFloatingPoint(false), ionPcScriptCache(nullptr), threadPool(this), defaultJSContextCallback(nullptr), ctypesActivityCallback(nullptr), parallelWarmup(0), ionReturnOverride_(MagicValue(JS_ARG_POISON)), useHelperThreads_(useHelperThreads), #ifdef JS_THREADSAFE cpuCount_(GetCPUCount()), #else cpuCount_(1), #endif parallelIonCompilationEnabled_(true), parallelParsingEnabled_(true), isWorkerRuntime_(false) #ifdef DEBUG , enteredPolicy(nullptr) #endif { MOZ_ASSERT(cpuCount_ > 0, "GetCPUCount() seems broken"); liveRuntimesCount++; setGCMode(JSGC_MODE_GLOBAL); /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ JS_INIT_CLIST(&onNewGlobalObjectWatchers); PodZero(&debugHooks); PodZero(&atomState); PodArrayZero(nativeStackQuota); PodZero(&asmJSCacheOps); #if JS_STACK_GROWTH_DIRECTION > 0 nativeStackLimit = UINTPTR_MAX; #endif }
void Statistics::endSlice() { if (!aborted) { slices.back().end = PRMJ_Now(); slices.back().endTimestamp = JS_GetCurrentEmbedderTime(); slices.back().endFaults = GetPageFaultCount(); slices.back().finalState = runtime->gc.state(); int64_t sliceTime = slices.back().end - slices.back().start; runtime->addTelemetry(JS_TELEMETRY_GC_SLICE_MS, t(sliceTime)); runtime->addTelemetry(JS_TELEMETRY_GC_RESET, slices.back().wasReset()); if (slices.back().wasReset()) runtime->addTelemetry(JS_TELEMETRY_GC_RESET_REASON, uint32_t(slices.back().resetReason)); if (slices.back().budget.isTimeBudget()) { int64_t budget_ms = slices.back().budget.timeBudget.budget; runtime->addTelemetry(JS_TELEMETRY_GC_BUDGET_MS, budget_ms); if (budget_ms == runtime->gc.defaultSliceBudget()) runtime->addTelemetry(JS_TELEMETRY_GC_ANIMATION_MS, t(sliceTime)); // Record any phase that goes more than 2x over its budget. if (sliceTime > 2 * budget_ms * 1000) { Phase longest = LongestPhase(slices.back().phaseTimes); runtime->addTelemetry(JS_TELEMETRY_GC_SLOW_PHASE, phases[longest].telemetryBucket); } } sliceCount_++; } bool last = !runtime->gc.isIncrementalGCInProgress(); if (last) endGC(); if (enableProfiling_ && !aborted && slices.back().duration() >= profileThreshold_) printSliceProfile(); // Slice callbacks should only fire for the outermost level. if (gcDepth == 1 && !aborted) { bool wasFullGC = zoneStats.isCollectingAllZones(); if (sliceCallback) (*sliceCallback)(runtime->contextFromMainThread(), last ? JS::GC_CYCLE_END : JS::GC_SLICE_END, JS::GCDescription(!wasFullGC, gckind, slices.back().reason)); } /* Do this after the slice callback since it uses these values. */ if (last) { PodArrayZero(counts); // Clear the timers at the end of a GC because we accumulate time in // between GCs for some (which come before PHASE_GC_BEGIN in the list.) PodZero(&phaseStartTimes[PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); for (size_t d = PHASE_DAG_NONE; d < NumTimingArrays; d++) PodZero(&phaseTimes[d][PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN); } gcDepth--; MOZ_ASSERT(gcDepth >= 0); }
AutoPropertyDescArray(JSContext *cx) : cx_(cx) { PodZero(&descArray_); }