Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / vm / Runtime.cpp
bloba40381f9240f8fe212672a5f4eb7cef68ffb7d97
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "vm/Runtime.h"
9 #include "mozilla/Atomics.h"
10 #include "mozilla/DebugOnly.h"
11 #if JS_HAS_INTL_API
12 # include "mozilla/intl/Locale.h"
13 #endif
14 #include "mozilla/MemoryReporting.h"
15 #include "mozilla/ThreadLocal.h"
17 #include <locale.h>
18 #include <string.h>
20 #include "jsfriendapi.h"
21 #include "jsmath.h"
23 #include "frontend/CompilationStencil.h"
24 #include "frontend/ParserAtom.h" // frontend::WellKnownParserAtoms
25 #include "gc/GC.h"
26 #include "gc/PublicIterators.h"
27 #include "jit/IonCompileTask.h"
28 #include "jit/JitRuntime.h"
29 #include "jit/Simulator.h"
30 #include "js/AllocationLogging.h" // JS_COUNT_CTOR, JS_COUNT_DTOR
31 #include "js/experimental/JSStencil.h"
32 #include "js/experimental/SourceHook.h"
33 #include "js/friend/ErrorMessages.h" // JSMSG_*
34 #include "js/Interrupt.h"
35 #include "js/MemoryMetrics.h"
36 #include "js/Stack.h" // JS::NativeStackLimitMin
37 #include "js/Wrapper.h"
38 #include "js/WrapperCallbacks.h"
39 #include "vm/DateTime.h"
40 #include "vm/JSObject.h"
41 #include "vm/JSScript.h"
42 #include "vm/PromiseObject.h" // js::PromiseObject
43 #include "vm/SharedImmutableStringsCache.h"
44 #include "vm/Warnings.h" // js::WarnNumberUC
45 #include "wasm/WasmSignalHandlers.h"
47 #include "debugger/DebugAPI-inl.h"
48 #include "gc/ArenaList-inl.h"
49 #include "vm/JSContext-inl.h"
50 #include "vm/Realm-inl.h"
52 using namespace js;
54 using mozilla::Atomic;
55 using mozilla::DebugOnly;
56 using mozilla::NegativeInfinity;
57 using mozilla::PositiveInfinity;
59 /* static */ MOZ_THREAD_LOCAL(JSContext*) js::TlsContext;
60 /* static */
61 Atomic<size_t> JSRuntime::liveRuntimesCount;
62 Atomic<JS::LargeAllocationFailureCallback> js::OnLargeAllocationFailure;
64 JS::FilenameValidationCallback js::gFilenameValidationCallback = nullptr;
66 namespace js {
68 #ifndef __wasi__
69 bool gCanUseExtraThreads = true;
70 #else
71 bool gCanUseExtraThreads = false;
72 #endif
73 } // namespace js
75 void js::DisableExtraThreads() { gCanUseExtraThreads = false; }
77 const JSSecurityCallbacks js::NullSecurityCallbacks = {};
79 static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
80 TransparentObjectWrapper, nullptr};
82 extern bool DefaultHostEnsureCanAddPrivateElementCallback(JSContext* cx,
83 HandleValue val);
85 static size_t ReturnZeroSize(const void* p) { return 0; }
87 JSRuntime::JSRuntime(JSRuntime* parentRuntime)
88 : parentRuntime(parentRuntime),
89 #ifdef DEBUG
90 updateChildRuntimeCount(parentRuntime),
91 initialized_(false),
92 #endif
93 mainContext_(nullptr),
94 profilerSampleBufferRangeStart_(0),
95 telemetryCallback(nullptr),
96 consumeStreamCallback(nullptr),
97 reportStreamErrorCallback(nullptr),
98 hadOutOfMemory(false),
99 allowRelazificationForTesting(false),
100 destroyCompartmentCallback(nullptr),
101 sizeOfIncludingThisCompartmentCallback(nullptr),
102 destroyRealmCallback(nullptr),
103 realmNameCallback(nullptr),
104 securityCallbacks(&NullSecurityCallbacks),
105 DOMcallbacks(nullptr),
106 destroyPrincipals(nullptr),
107 readPrincipals(nullptr),
108 canAddPrivateElement(&DefaultHostEnsureCanAddPrivateElementCallback),
109 warningReporter(nullptr),
110 geckoProfiler_(thisFromCtor()),
111 trustedPrincipals_(nullptr),
112 wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
113 preserveWrapperCallback(nullptr),
114 scriptEnvironmentPreparer(nullptr),
115 ctypesActivityCallback(nullptr),
116 windowProxyClass_(nullptr),
117 numRealms(0),
118 numDebuggeeRealms_(0),
119 numDebuggeeRealmsObservingCoverage_(0),
120 localeCallbacks(nullptr),
121 defaultLocale(nullptr),
122 profilingScripts(false),
123 scriptAndCountsVector(nullptr),
124 watchtowerTestingLog(nullptr),
125 jitRuntime_(nullptr),
126 gc(thisFromCtor()),
127 emptyString(nullptr),
128 #if !JS_HAS_INTL_API
129 thousandsSeparator(nullptr),
130 decimalSeparator(nullptr),
131 numGrouping(nullptr),
132 #endif
133 beingDestroyed_(false),
134 allowContentJS_(true),
135 atoms_(nullptr),
136 permanentAtoms_(nullptr),
137 staticStrings(nullptr),
138 commonNames(nullptr),
139 wellKnownSymbols(nullptr),
140 scriptDataTableHolder_(SharedScriptDataTableHolder::NeedsLock::No),
141 liveSABs(0),
142 beforeWaitCallback(nullptr),
143 afterWaitCallback(nullptr),
144 offthreadIonCompilationEnabled_(true),
145 parallelParsingEnabled_(true),
146 autoWritableJitCodeActive_(false),
147 oomCallback(nullptr),
148 debuggerMallocSizeOf(ReturnZeroSize),
149 stackFormat_(parentRuntime ? js::StackFormat::Default
150 : js::StackFormat::SpiderMonkey),
151 wasmInstances(mutexid::WasmRuntimeInstances),
152 moduleAsyncEvaluatingPostOrder(ASYNC_EVALUATING_POST_ORDER_INIT) {
153 JS_COUNT_CTOR(JSRuntime);
154 liveRuntimesCount++;
156 #ifndef __wasi__
157 // See function comment for why we call this now, not in JS_Init().
158 wasm::EnsureEagerProcessSignalHandlers();
159 #endif // __wasi__
162 JSRuntime::~JSRuntime() {
163 JS_COUNT_DTOR(JSRuntime);
164 MOZ_ASSERT(!initialized_);
166 DebugOnly<size_t> oldCount = liveRuntimesCount--;
167 MOZ_ASSERT(oldCount > 0);
169 MOZ_ASSERT(wasmInstances.lock()->empty());
171 MOZ_ASSERT(numRealms == 0);
172 MOZ_ASSERT(numDebuggeeRealms_ == 0);
173 MOZ_ASSERT(numDebuggeeRealmsObservingCoverage_ == 0);
176 bool JSRuntime::init(JSContext* cx, uint32_t maxbytes) {
177 #ifdef DEBUG
178 MOZ_ASSERT(!initialized_);
179 initialized_ = true;
180 #endif
182 if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized()) {
183 return false;
186 mainContext_ = cx;
188 if (!gc.init(maxbytes)) {
189 return false;
192 if (!InitRuntimeNumberState(this)) {
193 return false;
196 // As a hack, we clear our timezone cache every time we create a new runtime.
197 // Also see the comment in JS::Realm::init().
198 js::ResetTimeZoneInternal(ResetTimeZoneMode::DontResetIfOffsetUnchanged);
200 caches().megamorphicSetPropCache = MakeUnique<MegamorphicSetPropCache>();
201 if (!caches().megamorphicSetPropCache) {
202 return false;
205 return true;
208 void JSRuntime::destroyRuntime() {
209 MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
210 MOZ_ASSERT(childRuntimeCount == 0);
211 MOZ_ASSERT(initialized_);
213 #ifdef JS_HAS_INTL_API
214 sharedIntlData.ref().destroyInstance();
215 #endif
217 watchtowerTestingLog.ref().reset();
219 // Caches might hold on ScriptData which are saved in the ScriptDataTable.
220 // Clear all stencils from caches to remove ScriptDataTable entries.
221 caches().purgeStencils();
223 if (gc.wasInitialized()) {
225 * Finish any in-progress GCs first.
227 JSContext* cx = mainContextFromOwnThread();
228 if (JS::IsIncrementalGCInProgress(cx)) {
229 gc::FinishGC(cx);
232 /* Free source hook early, as its destructor may want to delete roots. */
233 sourceHook = nullptr;
236 * Cancel any pending, in progress or completed Ion compilations and
237 * parse tasks. Waiting for wasm and compression tasks is done
238 * synchronously (on the main thread or during parse tasks), so no
239 * explicit canceling is needed for these.
241 CancelOffThreadIonCompile(this);
242 CancelOffThreadDelazify(this);
243 CancelOffThreadCompressions(this);
246 * Flag us as being destroyed. This allows the GC to free things like
247 * interned atoms and Ion trampolines.
249 beingDestroyed_ = true;
251 /* Remove persistent GC roots. */
252 gc.finishRoots();
254 /* Allow the GC to release scripts that were being profiled. */
255 profilingScripts = false;
257 JS::PrepareForFullGC(cx);
258 gc.gc(JS::GCOptions::Shutdown, JS::GCReason::DESTROY_RUNTIME);
261 AutoNoteSingleThreadedRegion anstr;
263 MOZ_ASSERT(scriptDataTableHolder().getWithoutLock().empty());
265 #if !JS_HAS_INTL_API
266 FinishRuntimeNumberState(this);
267 #endif
269 gc.finish();
271 defaultLocale = nullptr;
272 js_delete(jitRuntime_.ref());
274 #ifdef DEBUG
275 initialized_ = false;
276 #endif
279 void JSRuntime::addTelemetry(JSMetric id, uint32_t sample) {
280 if (telemetryCallback) {
281 (*telemetryCallback)(id, sample);
285 void JSRuntime::setTelemetryCallback(
286 JSRuntime* rt, JSAccumulateTelemetryDataCallback callback) {
287 rt->telemetryCallback = callback;
290 void JSRuntime::setUseCounter(JSObject* obj, JSUseCounter counter) {
291 if (useCounterCallback) {
292 (*useCounterCallback)(obj, counter);
296 void JSRuntime::setUseCounterCallback(JSRuntime* rt,
297 JSSetUseCounterCallback callback) {
298 rt->useCounterCallback = callback;
301 void JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
302 JS::RuntimeSizes* rtSizes) {
303 rtSizes->object += mallocSizeOf(this);
305 rtSizes->atomsTable += atoms().sizeOfIncludingThis(mallocSizeOf);
306 rtSizes->gc.marker += gc.markers.sizeOfExcludingThis(mallocSizeOf);
307 for (auto& marker : gc.markers) {
308 rtSizes->gc.marker += marker->sizeOfIncludingThis(mallocSizeOf);
311 if (!parentRuntime) {
312 rtSizes->atomsTable += mallocSizeOf(staticStrings);
313 rtSizes->atomsTable += mallocSizeOf(commonNames);
314 rtSizes->atomsTable += permanentAtoms()->sizeOfIncludingThis(mallocSizeOf);
316 rtSizes->selfHostStencil =
317 selfHostStencilInput_->sizeOfIncludingThis(mallocSizeOf) +
318 selfHostStencil_->sizeOfIncludingThis(mallocSizeOf) +
319 selfHostScriptMap.ref().shallowSizeOfExcludingThis(mallocSizeOf);
322 JSContext* cx = mainContextFromAnyThread();
323 rtSizes->contexts += cx->sizeOfIncludingThis(mallocSizeOf);
324 rtSizes->temporary += cx->tempLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
325 rtSizes->interpreterStack +=
326 cx->interpreterStack().sizeOfExcludingThis(mallocSizeOf);
327 rtSizes->uncompressedSourceCache +=
328 caches().uncompressedSourceCache.sizeOfExcludingThis(mallocSizeOf);
330 rtSizes->gc.nurseryCommitted += gc.nursery().committed();
331 rtSizes->gc.nurseryMallocedBuffers +=
332 gc.nursery().sizeOfMallocedBuffers(mallocSizeOf);
333 gc.storeBuffer().addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc);
335 rtSizes->gc.nurseryMallocedBlockCache +=
336 gc.nursery().sizeOfMallocedBlockCache(mallocSizeOf);
337 rtSizes->gc.nurseryTrailerBlockSets +=
338 gc.nursery().sizeOfTrailerBlockSets(mallocSizeOf);
340 if (isMainRuntime()) {
341 rtSizes->sharedImmutableStringsCache +=
342 js::SharedImmutableStringsCache::getSingleton().sizeOfExcludingThis(
343 mallocSizeOf);
344 rtSizes->atomsTable +=
345 js::frontend::WellKnownParserAtoms::getSingleton().sizeOfExcludingThis(
346 mallocSizeOf);
349 #ifdef JS_HAS_INTL_API
350 rtSizes->sharedIntlData +=
351 sharedIntlData.ref().sizeOfExcludingThis(mallocSizeOf);
352 #endif
355 auto& table = scriptDataTableHolder().getWithoutLock();
357 rtSizes->scriptData += table.shallowSizeOfExcludingThis(mallocSizeOf);
358 for (SharedImmutableScriptDataTable::Range r = table.all(); !r.empty();
359 r.popFront()) {
360 rtSizes->scriptData += r.front()->sizeOfIncludingThis(mallocSizeOf);
364 if (isMainRuntime()) {
365 AutoLockGlobalScriptData lock;
367 auto& table = js::globalSharedScriptDataTableHolder.get(lock);
369 rtSizes->scriptData += table.shallowSizeOfExcludingThis(mallocSizeOf);
370 for (SharedImmutableScriptDataTable::Range r = table.all(); !r.empty();
371 r.popFront()) {
372 rtSizes->scriptData += r.front()->sizeOfIncludingThis(mallocSizeOf);
376 if (jitRuntime_) {
377 // Sizes of the IonCompileTasks we are holding for lazy linking
378 for (auto* task : jitRuntime_->ionLazyLinkList(this)) {
379 rtSizes->jitLazyLink += task->sizeOfExcludingThis(mallocSizeOf);
383 rtSizes->wasmRuntime +=
384 wasmInstances.lock()->sizeOfExcludingThis(mallocSizeOf);
387 static bool HandleInterrupt(JSContext* cx, bool invokeCallback) {
388 MOZ_ASSERT(!cx->zone()->isAtomsZone());
390 cx->runtime()->gc.gcIfRequested();
392 // A worker thread may have requested an interrupt after finishing an Ion
393 // compilation.
394 jit::AttachFinishedCompilations(cx);
396 // Don't call the interrupt callback if we only interrupted for GC or Ion.
397 if (!invokeCallback) {
398 return true;
401 // Important: Additional callbacks can occur inside the callback handler
402 // if it re-enters the JS engine. The embedding must ensure that the
403 // callback is disconnected before attempting such re-entry.
404 if (cx->interruptCallbackDisabled) {
405 return true;
408 bool stop = false;
409 for (JSInterruptCallback cb : cx->interruptCallbacks()) {
410 if (!cb(cx)) {
411 stop = true;
415 if (!stop) {
416 // Debugger treats invoking the interrupt callback as a "step", so
417 // invoke the onStep handler.
418 if (cx->realm()->isDebuggee()) {
419 ScriptFrameIter iter(cx);
420 if (!iter.done() && cx->compartment() == iter.compartment() &&
421 DebugAPI::stepModeEnabled(iter.script())) {
422 if (!DebugAPI::onSingleStep(cx)) {
423 return false;
428 return true;
431 // No need to set aside any pending exception here: ComputeStackString
432 // already does that.
433 JSString* stack = ComputeStackString(cx);
435 UniqueTwoByteChars stringChars;
436 if (stack) {
437 stringChars = JS_CopyStringCharsZ(cx, stack);
438 if (!stringChars) {
439 cx->recoverFromOutOfMemory();
443 const char16_t* chars;
444 if (stringChars) {
445 chars = stringChars.get();
446 } else {
447 chars = u"(stack not available)";
449 WarnNumberUC(cx, JSMSG_TERMINATED, chars);
450 return false;
453 void JSContext::requestInterrupt(InterruptReason reason) {
454 interruptBits_ |= uint32_t(reason);
455 jitStackLimit = JS::NativeStackLimitMin;
457 if (reason == InterruptReason::CallbackUrgent) {
458 // If this interrupt is urgent (slow script dialog for instance), take
459 // additional steps to interrupt corner cases where the above fields are
460 // not regularly polled.
461 FutexThread::lock();
462 if (fx.isWaiting()) {
463 fx.notify(FutexThread::NotifyForJSInterrupt);
465 fx.unlock();
468 if (reason == InterruptReason::CallbackUrgent ||
469 reason == InterruptReason::MajorGC ||
470 reason == InterruptReason::MinorGC) {
471 wasm::InterruptRunningCode(this);
475 bool JSContext::handleInterrupt() {
476 MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
477 if (hasAnyPendingInterrupt() || jitStackLimit == JS::NativeStackLimitMin) {
478 bool invokeCallback =
479 hasPendingInterrupt(InterruptReason::CallbackUrgent) ||
480 hasPendingInterrupt(InterruptReason::CallbackCanWait);
481 interruptBits_ = 0;
482 resetJitStackLimit();
483 return HandleInterrupt(this, invokeCallback);
485 return true;
488 void JSContext::clearPendingInterrupt(js::InterruptReason reason) {
489 // Interrupt bit have already been cleared.
490 interruptBits_ &= ~uint32_t(reason);
493 bool JSRuntime::setDefaultLocale(const char* locale) {
494 if (!locale) {
495 return false;
498 UniqueChars newLocale = DuplicateString(mainContextFromOwnThread(), locale);
499 if (!newLocale) {
500 return false;
503 defaultLocale.ref() = std::move(newLocale);
504 return true;
507 void JSRuntime::resetDefaultLocale() { defaultLocale = nullptr; }
509 const char* JSRuntime::getDefaultLocale() {
510 if (defaultLocale.ref()) {
511 return defaultLocale.ref().get();
514 // Use ICU if available to retrieve the default locale, this ensures ICU's
515 // default locale matches our default locale.
516 #if JS_HAS_INTL_API
517 const char* locale = mozilla::intl::Locale::GetDefaultLocale();
518 #else
519 const char* locale = setlocale(LC_ALL, nullptr);
520 #endif
522 // convert to a well-formed BCP 47 language tag
523 if (!locale || !strcmp(locale, "C")) {
524 locale = "und";
527 UniqueChars lang = DuplicateString(mainContextFromOwnThread(), locale);
528 if (!lang) {
529 return nullptr;
532 char* p;
533 if ((p = strchr(lang.get(), '.'))) {
534 *p = '\0';
536 while ((p = strchr(lang.get(), '_'))) {
537 *p = '-';
540 defaultLocale.ref() = std::move(lang);
541 return defaultLocale.ref().get();
544 #ifdef JS_HAS_INTL_API
545 void JSRuntime::traceSharedIntlData(JSTracer* trc) {
546 sharedIntlData.ref().trace(trc);
548 #endif
550 SharedScriptDataTableHolder& JSRuntime::scriptDataTableHolder() {
551 return scriptDataTableHolder_;
554 GlobalObject* JSRuntime::getIncumbentGlobal(JSContext* cx) {
555 MOZ_ASSERT(cx->jobQueue);
557 JSObject* obj = cx->jobQueue->getIncumbentGlobal(cx);
558 if (!obj) {
559 return nullptr;
562 MOZ_ASSERT(obj->is<GlobalObject>(),
563 "getIncumbentGlobalCallback must return a global!");
564 return &obj->as<GlobalObject>();
567 bool JSRuntime::enqueuePromiseJob(JSContext* cx, HandleFunction job,
568 HandleObject promise,
569 Handle<GlobalObject*> incumbentGlobal) {
570 MOZ_ASSERT(cx->jobQueue,
571 "Must select a JobQueue implementation using JS::JobQueue "
572 "or js::UseInternalJobQueues before using Promises");
574 RootedObject allocationSite(cx);
575 if (promise) {
576 #ifdef DEBUG
577 AssertSameCompartment(job, promise);
578 #endif
580 RootedObject unwrappedPromise(cx, promise);
581 // While the job object is guaranteed to be unwrapped, the promise
582 // might be wrapped. See the comments in EnqueuePromiseReactionJob in
583 // builtin/Promise.cpp for details.
584 if (IsWrapper(promise)) {
585 unwrappedPromise = UncheckedUnwrap(promise);
587 if (unwrappedPromise->is<PromiseObject>()) {
588 allocationSite = JS::GetPromiseAllocationSite(unwrappedPromise);
591 return cx->jobQueue->enqueuePromiseJob(cx, promise, job, allocationSite,
592 incumbentGlobal);
595 void JSRuntime::addUnhandledRejectedPromise(JSContext* cx,
596 js::HandleObject promise) {
597 MOZ_ASSERT(promise->is<PromiseObject>());
598 if (!cx->promiseRejectionTrackerCallback) {
599 return;
602 bool mutedErrors = false;
603 if (JSScript* script = cx->currentScript()) {
604 mutedErrors = script->mutedErrors();
607 void* data = cx->promiseRejectionTrackerCallbackData;
608 cx->promiseRejectionTrackerCallback(
609 cx, mutedErrors, promise, JS::PromiseRejectionHandlingState::Unhandled,
610 data);
613 void JSRuntime::removeUnhandledRejectedPromise(JSContext* cx,
614 js::HandleObject promise) {
615 MOZ_ASSERT(promise->is<PromiseObject>());
616 if (!cx->promiseRejectionTrackerCallback) {
617 return;
620 bool mutedErrors = false;
621 if (JSScript* script = cx->currentScript()) {
622 mutedErrors = script->mutedErrors();
625 void* data = cx->promiseRejectionTrackerCallbackData;
626 cx->promiseRejectionTrackerCallback(
627 cx, mutedErrors, promise, JS::PromiseRejectionHandlingState::Handled,
628 data);
631 mozilla::non_crypto::XorShift128PlusRNG& JSRuntime::randomKeyGenerator() {
632 MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
633 if (randomKeyGenerator_.isNothing()) {
634 mozilla::Array<uint64_t, 2> seed;
635 GenerateXorShift128PlusSeed(seed);
636 randomKeyGenerator_.emplace(seed[0], seed[1]);
638 return randomKeyGenerator_.ref();
641 mozilla::HashCodeScrambler JSRuntime::randomHashCodeScrambler() {
642 auto& rng = randomKeyGenerator();
643 return mozilla::HashCodeScrambler(rng.next(), rng.next());
646 mozilla::non_crypto::XorShift128PlusRNG JSRuntime::forkRandomKeyGenerator() {
647 auto& rng = randomKeyGenerator();
648 return mozilla::non_crypto::XorShift128PlusRNG(rng.next(), rng.next());
651 js::HashNumber JSRuntime::randomHashCode() {
652 MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
654 if (randomHashCodeGenerator_.isNothing()) {
655 mozilla::Array<uint64_t, 2> seed;
656 GenerateXorShift128PlusSeed(seed);
657 randomHashCodeGenerator_.emplace(seed[0], seed[1]);
660 return HashNumber(randomHashCodeGenerator_->next());
663 JS_PUBLIC_API void* JSRuntime::onOutOfMemory(AllocFunction allocFunc,
664 arena_id_t arena, size_t nbytes,
665 void* reallocPtr,
666 JSContext* maybecx) {
667 MOZ_ASSERT_IF(allocFunc != AllocFunction::Realloc, !reallocPtr);
669 if (JS::RuntimeHeapIsBusy()) {
670 return nullptr;
673 if (!oom::IsSimulatedOOMAllocation()) {
675 * Retry when we are done with the background sweeping and have stopped
676 * all the allocations and released the empty GC chunks.
678 gc.onOutOfMallocMemory();
679 void* p;
680 switch (allocFunc) {
681 case AllocFunction::Malloc:
682 p = js_arena_malloc(arena, nbytes);
683 break;
684 case AllocFunction::Calloc:
685 p = js_arena_calloc(arena, nbytes, 1);
686 break;
687 case AllocFunction::Realloc:
688 p = js_arena_realloc(arena, reallocPtr, nbytes);
689 break;
690 default:
691 MOZ_CRASH();
693 if (p) {
694 return p;
698 if (maybecx) {
699 ReportOutOfMemory(maybecx);
701 return nullptr;
704 void* JSRuntime::onOutOfMemoryCanGC(AllocFunction allocFunc, arena_id_t arena,
705 size_t bytes, void* reallocPtr) {
706 if (OnLargeAllocationFailure && bytes >= LARGE_ALLOCATION) {
707 OnLargeAllocationFailure();
709 return onOutOfMemory(allocFunc, arena, bytes, reallocPtr);
712 bool JSRuntime::activeGCInAtomsZone() {
713 Zone* zone = unsafeAtomsZone();
714 return (zone->needsIncrementalBarrier() &&
715 !gc.isVerifyPreBarriersEnabled()) ||
716 zone->wasGCStarted();
719 void JSRuntime::incrementNumDebuggeeRealms() {
720 if (numDebuggeeRealms_ == 0) {
721 jitRuntime()->baselineInterpreter().toggleDebuggerInstrumentation(true);
724 numDebuggeeRealms_++;
725 MOZ_ASSERT(numDebuggeeRealms_ <= numRealms);
728 void JSRuntime::decrementNumDebuggeeRealms() {
729 MOZ_ASSERT(numDebuggeeRealms_ > 0);
730 numDebuggeeRealms_--;
732 // Note: if we had shutdown leaks we can end up here while destroying the
733 // runtime. It's not safe to access JitRuntime trampolines because they're no
734 // longer traced.
735 if (numDebuggeeRealms_ == 0 && !isBeingDestroyed()) {
736 jitRuntime()->baselineInterpreter().toggleDebuggerInstrumentation(false);
740 void JSRuntime::incrementNumDebuggeeRealmsObservingCoverage() {
741 if (numDebuggeeRealmsObservingCoverage_ == 0) {
742 jit::BaselineInterpreter& interp = jitRuntime()->baselineInterpreter();
743 interp.toggleCodeCoverageInstrumentation(true);
746 numDebuggeeRealmsObservingCoverage_++;
747 MOZ_ASSERT(numDebuggeeRealmsObservingCoverage_ <= numRealms);
750 void JSRuntime::decrementNumDebuggeeRealmsObservingCoverage() {
751 MOZ_ASSERT(numDebuggeeRealmsObservingCoverage_ > 0);
752 numDebuggeeRealmsObservingCoverage_--;
754 // Note: if we had shutdown leaks we can end up here while destroying the
755 // runtime. It's not safe to access JitRuntime trampolines because they're no
756 // longer traced.
757 if (numDebuggeeRealmsObservingCoverage_ == 0 && !isBeingDestroyed()) {
758 jit::BaselineInterpreter& interp = jitRuntime()->baselineInterpreter();
759 interp.toggleCodeCoverageInstrumentation(false);
763 bool js::CurrentThreadCanAccessRuntime(const JSRuntime* rt) {
764 return rt->mainContextFromAnyThread() == TlsContext.get();
767 bool js::CurrentThreadCanAccessZone(Zone* zone) {
768 return CurrentThreadCanAccessRuntime(zone->runtime_);
771 #ifdef DEBUG
772 bool js::CurrentThreadIsMainThread() { return !!TlsContext.get(); }
773 #endif
775 JS_PUBLIC_API void JS::SetJSContextProfilerSampleBufferRangeStart(
776 JSContext* cx, uint64_t rangeStart) {
777 cx->runtime()->setProfilerSampleBufferRangeStart(rangeStart);
780 JS_PUBLIC_API bool JS::IsProfilingEnabledForContext(JSContext* cx) {
781 MOZ_ASSERT(cx);
782 return cx->runtime()->geckoProfiler().enabled();
785 JS_PUBLIC_API void JS::EnableRecordingAllocations(
786 JSContext* cx, JS::RecordAllocationsCallback callback, double probability) {
787 MOZ_ASSERT(cx);
788 cx->runtime()->startRecordingAllocations(probability, callback);
791 JS_PUBLIC_API void JS::DisableRecordingAllocations(JSContext* cx) {
792 MOZ_ASSERT(cx);
793 cx->runtime()->stopRecordingAllocations();
796 JS_PUBLIC_API void JS::shadow::RegisterWeakCache(
797 JSRuntime* rt, detail::WeakCacheBase* cachep) {
798 rt->registerWeakCache(cachep);
801 void JSRuntime::startRecordingAllocations(
802 double probability, JS::RecordAllocationsCallback callback) {
803 allocationSamplingProbability = probability;
804 recordAllocationCallback = callback;
806 // Go through all of the existing realms, and turn on allocation tracking.
807 for (RealmsIter realm(this); !realm.done(); realm.next()) {
808 realm->setAllocationMetadataBuilder(&SavedStacks::metadataBuilder);
809 realm->chooseAllocationSamplingProbability();
813 void JSRuntime::stopRecordingAllocations() {
814 recordAllocationCallback = nullptr;
815 // Go through all of the existing realms, and turn on allocation tracking.
816 for (RealmsIter realm(this); !realm.done(); realm.next()) {
817 js::GlobalObject* global = realm->maybeGlobal();
818 if (!realm->isDebuggee() || !global ||
819 !DebugAPI::isObservedByDebuggerTrackingAllocations(*global)) {
820 // Only remove the allocation metadata builder if no Debuggers are
821 // tracking allocations.
822 realm->forgetAllocationMetadataBuilder();
827 // This function can run to ensure that when new realms are created
828 // they have allocation logging turned on.
829 void JSRuntime::ensureRealmIsRecordingAllocations(
830 Handle<GlobalObject*> global) {
831 if (recordAllocationCallback) {
832 if (!global->realm()->isRecordingAllocations()) {
833 // This is a new realm, turn on allocations for it.
834 global->realm()->setAllocationMetadataBuilder(
835 &SavedStacks::metadataBuilder);
837 // Ensure the probability is up to date with the current combination of
838 // debuggers and runtime profiling.
839 global->realm()->chooseAllocationSamplingProbability();