diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp index 2b2046fd4f3d..0eb3801665b6 100644 --- a/Source/JavaScriptCore/heap/Heap.cpp +++ b/Source/JavaScriptCore/heap/Heap.cpp @@ -3005,6 +3005,13 @@ void Heap::collectIfNecessaryOrDefer(GCDeferralContext* deferralContext) } } +void Heap::performPendingDeferredGCWork() +{ + ASSERT(hasPendingDeferredGCWork()); + m_didDeferGCWork = false; + collectIfNecessaryOrDefer(); +} + void Heap::decrementDeferralDepthAndGCIfNeededSlow() { // Can't do anything if we're still deferred. diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h index 61ee1f3769ea..f3c245314b53 100644 --- a/Source/JavaScriptCore/heap/Heap.h +++ b/Source/JavaScriptCore/heap/Heap.h @@ -438,6 +438,13 @@ class Heap { void collectIfNecessaryOrDefer(GCDeferralContext* = nullptr); + // A GC request raised while collection was deferred by DeferGCForAWhile (e.g. the extra-memory + // reports in ScriptExecutable::prepareForExecutionImpl) only sets m_didDeferGCWork; nothing acts on it + // until the next allocation slow path or ~DeferGC, which an embedder-driven loop may not reach for a + // long time. VM entry is a safe point to honor it. + bool hasPendingDeferredGCWork() const { return m_didDeferGCWork && !m_deferralDepth; } + JS_EXPORT_PRIVATE void performPendingDeferredGCWork(); + void completeAllJITPlans(); // Note that: diff --git a/Source/JavaScriptCore/runtime/OptionsList.h b/Source/JavaScriptCore/runtime/OptionsList.h index bb22bd7a8b5c..3f1353b807c1 100644 --- a/Source/JavaScriptCore/runtime/OptionsList.h +++ b/Source/JavaScriptCore/runtime/OptionsList.h @@ -238,6 +238,7 @@ bool hasCapacityToUseLargeGigacage(); v(Bool, testTheFTL, false, Normal, nullptr) \ v(Bool, verboseSanitizeStack, false, Normal, nullptr) \ v(Bool, useGenerationalGC, true, Normal, nullptr) \ + v(Bool, usePollingDeferredGCWorkAtVMEntry, true, Normal, "Honor a GC request left pending by a DeferGCForAWhile scope when the VM is next entered, instead of waiting for the next allocation slow path or ~DeferGC."_s) \ v(Bool, useConcurrentGC, true, Normal, nullptr) \ v(Bool, collectContinuously, false, Normal, nullptr) \ v(Double, collectContinuouslyPeriodMS, 1, Normal, nullptr) \ diff --git a/Source/JavaScriptCore/runtime/VMEntryScopeInlines.h b/Source/JavaScriptCore/runtime/VMEntryScopeInlines.h index e8570400283f..3be83b0783fe 100644 --- a/Source/JavaScriptCore/runtime/VMEntryScopeInlines.h +++ b/Source/JavaScriptCore/runtime/VMEntryScopeInlines.h @@ -37,6 +37,8 @@ ALWAYS_INLINE VMEntryScope::VMEntryScope(VM& vm, JSGlobalObject* globalObject) if (!vm.entryScope) setUpSlow(); vm.clearLastException(); + if (vm.heap.hasPendingDeferredGCWork() && Options::usePollingDeferredGCWorkAtVMEntry()) [[unlikely]] + vm.heap.performPendingDeferredGCWork(); } ALWAYS_INLINE VMEntryScope::~VMEntryScope()