From afe76690ad8ba36b5cdf9863f7e6b2be674efe08 Mon Sep 17 00:00:00 2001 From: Paul Bone Date: Fri, 25 Jun 2021 02:47:17 +0000 Subject: [PATCH] Bug 1703443 - pt 7. Make GC/CC runners private to CCGCScheduler and move more code r=smaug Differential Revision: https://phabricator.services.mozilla.com/D118342 --- dom/base/CCGCScheduler.cpp | 78 ++++++++++++++++++++++++++++++++++++++ dom/base/CCGCScheduler.h | 7 ++-- dom/base/nsJSEnvironment.cpp | 90 +++++++------------------------------------- 3 files changed, 95 insertions(+), 80 deletions(-) diff --git a/dom/base/CCGCScheduler.cpp b/dom/base/CCGCScheduler.cpp index 7426abb20638..dd6500272a2f 100644 --- a/dom/base/CCGCScheduler.cpp +++ b/dom/base/CCGCScheduler.cpp @@ -5,6 +5,7 @@ #include "CCGCScheduler.h" #include "mozilla/StaticPrefs_javascript.h" +#include "mozilla/CycleCollectedJSRuntime.h" namespace mozilla { @@ -223,6 +224,67 @@ void CCGCScheduler::PokeFullGC() { } } +void CCGCScheduler::PokeGC(JS::GCReason aReason, JSObject* aObj, + uint32_t aDelay) { + if (mDidShutdown) { + return; + } + + if (aObj) { + JS::Zone* zone = JS::GetObjectZone(aObj); + CycleCollectedJSRuntime::Get()->AddZoneWaitingForGC(zone); + } else if (aReason != JS::GCReason::CC_FINISHED) { + SetNeedsFullGC(); + } + + if (mGCRunner) { + // There's already a runner for GC'ing, just return + return; + } + + SetWantMajorGC(aReason); + + if (mCCRunner) { + // Make sure CC is called regardless of the size of the purple buffer, and + // GC after it. + EnsureCCThenGC(); + return; + } + + static bool first = true; + + uint32_t delay = + aDelay ? aDelay + : (first ? StaticPrefs::javascript_options_gc_delay_first() + : StaticPrefs::javascript_options_gc_delay()); + first = false; + + mGCRunner = IdleTaskRunner::Create( + [this](TimeStamp aDeadline) { return GCRunnerFired(aDeadline); }, + "GCRunnerFired", + // Wait for javascript.options.gc_delay, then start looking for idle time + // to run the initial GC slice. Wait at most the interslice GC delay + // before forcing a run. + delay, StaticPrefs::javascript_options_gc_delay_interslice(), + mActiveIntersliceGCBudget.ToMilliseconds(), true, + [this] { return mDidShutdown; }); +} + +void CCGCScheduler::EnsureGCRunner() { + if (mGCRunner) { + return; + } + + mGCRunner = IdleTaskRunner::Create( + [this](TimeStamp aDeadline) { return GCRunnerFired(aDeadline); }, + "CCGCScheduler::EnsureGCRunner", + // Start immediately looking for idle time, waiting at most the + // interslice GC delay before forcing a run. + 0, StaticPrefs::javascript_options_gc_delay_interslice(), + mActiveIntersliceGCBudget.ToMilliseconds(), true, + [this] { return mDidShutdown; }); +} + void CCGCScheduler::KillShrinkingGCTimer() { if (mShrinkingGCTimer) { mShrinkingGCTimer->Cancel(); @@ -261,6 +323,22 @@ void CCGCScheduler::EnsureCCRunner(TimeDuration aDelay, TimeDuration aBudget) { } } +void CCGCScheduler::MaybePokeCC() { + if (mCCRunner || mDidShutdown) { + return; + } + + if (ShouldScheduleCC()) { + // We can kill some objects before running forgetSkippable. + nsCycleCollector_dispatchDeferredDeletion(); + + if (!mCCRunner) { + InitCCRunnerStateMachine(CCRunnerState::ReducePurple); + } + EnsureCCRunner(kCCSkippableDelay, kForgetSkippableSliceDuration); + } +} + void CCGCScheduler::KillCCRunner() { UnblockCC(); DeactivateCCRunner(); diff --git a/dom/base/CCGCScheduler.h b/dom/base/CCGCScheduler.h index 4b4ba427cb04..1bf2681289a1 100644 --- a/dom/base/CCGCScheduler.h +++ b/dom/base/CCGCScheduler.h @@ -146,14 +146,18 @@ class CCGCScheduler { bool NeedsFullGC() const { return mNeedsFullGC; } // Requests + void PokeGC(JS::GCReason aReason, JSObject* aObj, uint32_t aDelay = 0); void PokeShrinkingGC(); void PokeFullGC(); + void MaybePokeCC(); + void KillShrinkingGCTimer(); void KillFullGCTimer(); void KillGCRunner(); void KillCCRunner(); void KillAllTimersAndRunners(); + void EnsureGCRunner(); void EnsureCCRunner(TimeDuration aDelay, TimeDuration aBudget); // State modification @@ -424,11 +428,8 @@ class CCGCScheduler { TimeDuration mGCUnnotifiedTotalTime; - public: // XXX RefPtr mGCRunner; RefPtr mCCRunner; - - private: nsITimer* mShrinkingGCTimer = nullptr; nsITimer* mFullGCTimer = nullptr; diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index c451afa05614..d539e6325a61 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -556,7 +556,7 @@ nsJSContext::~nsJSContext() { void nsJSContext::Destroy() { if (mGCOnDestruction) { - PokeGC(JS::GCReason::NSJSCONTEXT_DESTROY, mWindowProxy); + sScheduler.PokeGC(JS::GCReason::NSJSCONTEXT_DESTROY, mWindowProxy); } DropJSObjects(this); @@ -1500,9 +1500,10 @@ void nsJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) { kMaxICCDuration.ToMilliseconds(), "A max duration ICC shouldn't reduce GC delay to 0"); - PokeGC(JS::GCReason::CC_FINISHED, nullptr, - StaticPrefs::javascript_options_gc_delay() - - std::min(ccNowDuration, kMaxICCDuration).ToMilliseconds()); + sScheduler.PokeGC( + JS::GCReason::CC_FINISHED, nullptr, + StaticPrefs::javascript_options_gc_delay() - + std::min(ccNowDuration, kMaxICCDuration).ToMilliseconds()); } // Log information about the CC via telemetry, JSON and the console. @@ -1645,48 +1646,7 @@ void nsJSContext::MaybeRunNextCollectorSlice(nsIDocShell* aDocShell, // static void nsJSContext::PokeGC(JS::GCReason aReason, JSObject* aObj, uint32_t aDelay) { - if (sShuttingDown) { - return; - } - - if (aObj) { - JS::Zone* zone = JS::GetObjectZone(aObj); - CycleCollectedJSRuntime::Get()->AddZoneWaitingForGC(zone); - } else if (aReason != JS::GCReason::CC_FINISHED) { - sScheduler.SetNeedsFullGC(); - } - - if (sScheduler.mGCRunner) { - // There's already a runner for GC'ing, just return - return; - } - - sScheduler.SetWantMajorGC(aReason); - - if (sScheduler.mCCRunner) { - // Make sure CC is called regardless of the size of the purple buffer, and - // GC after it. - sScheduler.EnsureCCThenGC(); - return; - } - - static bool first = true; - - uint32_t delay = - aDelay ? aDelay - : (first ? StaticPrefs::javascript_options_gc_delay_first() - : StaticPrefs::javascript_options_gc_delay()); - first = false; - - sScheduler.mGCRunner = IdleTaskRunner::Create( - [](TimeStamp aDeadline) { return sScheduler.GCRunnerFired(aDeadline); }, - "GCRunnerFired", - // Wait for javascript.options.gc_delay, then start looking for idle time - // to run the initial GC slice. Wait at most the interslice GC delay - // before forcing a run. - delay, StaticPrefs::javascript_options_gc_delay_interslice(), - sScheduler.mActiveIntersliceGCBudget.ToMilliseconds(), true, - [] { return sShuttingDown; }); + sScheduler.PokeGC(aReason, aObj, aDelay); } // static @@ -1721,22 +1681,7 @@ void nsJSContext::LowMemoryGC() { } // static -void nsJSContext::MaybePokeCC() { - if (sScheduler.mCCRunner || sShuttingDown) { - return; - } - - if (sScheduler.ShouldScheduleCC()) { - // We can kill some objects before running forgetSkippable. - nsCycleCollector_dispatchDeferredDeletion(); - - if (!sScheduler.mCCRunner) { - sScheduler.InitCCRunnerStateMachine( - mozilla::CCGCScheduler::CCRunnerState::ReducePurple); - } - sScheduler.EnsureCCRunner(kCCSkippableDelay, kForgetSkippableSliceDuration); - } -} +void nsJSContext::MaybePokeCC() { sScheduler.MaybePokeCC(); } static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, const JS::GCDescription& aDesc) { @@ -1783,7 +1728,7 @@ static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, // May need to kill the GC runner sScheduler.KillGCRunner(); - nsJSContext::MaybePokeCC(); + sScheduler.MaybePokeCC(); if (aDesc.isZone_) { sScheduler.PokeFullGC(); @@ -1810,20 +1755,11 @@ static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, if (sShuttingDown || aDesc.isComplete_) { sScheduler.KillGCRunner(); - } else if (!sScheduler.mGCRunner) { - // If incremental GC wasn't triggered by GCTimerFired, we may not - // have a runner to ensure all the slices are handled. So, create - // the runner here. - sScheduler.mGCRunner = IdleTaskRunner::Create( - [](TimeStamp aDeadline) { - return sScheduler.GCRunnerFired(aDeadline); - }, - "DOMGCSliceCallback::GCRunnerFired", - // Start immediately looking for idle time, waiting at most the - // interslice GC delay before forcing a run. - 0, StaticPrefs::javascript_options_gc_delay_interslice(), - sScheduler.mActiveIntersliceGCBudget.ToMilliseconds(), true, - [] { return sShuttingDown; }); + } else { + // If incremental GC wasn't triggered by GCTimerFired, we may not have a + // runner to ensure all the slices are handled. So, create the runner + // here. + sScheduler.EnsureGCRunner(); } if (sScheduler.IsCCNeeded()) { -- 2.11.4.GIT