зеркало из https://github.com/mozilla/gecko-dev.git
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
This commit is contained in:
Родитель
637185a2a1
Коммит
723358ef21
|
@ -5,6 +5,7 @@
|
|||
#include "CCGCScheduler.h"
|
||||
|
||||
#include "mozilla/StaticPrefs_javascript.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -230,6 +231,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();
|
||||
|
@ -268,6 +330,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();
|
||||
|
|
|
@ -148,14 +148,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
|
||||
|
@ -426,11 +430,8 @@ class CCGCScheduler {
|
|||
|
||||
TimeDuration mGCUnnotifiedTotalTime;
|
||||
|
||||
public: // XXX
|
||||
RefPtr<IdleTaskRunner> mGCRunner;
|
||||
RefPtr<IdleTaskRunner> mCCRunner;
|
||||
|
||||
private:
|
||||
nsITimer* mShrinkingGCTimer = nullptr;
|
||||
nsITimer* mFullGCTimer = nullptr;
|
||||
|
||||
|
|
|
@ -557,7 +557,7 @@ nsJSContext::~nsJSContext() {
|
|||
|
||||
void nsJSContext::Destroy() {
|
||||
if (mGCOnDestruction) {
|
||||
PokeGC(JS::GCReason::NSJSCONTEXT_DESTROY, mWindowProxy);
|
||||
sScheduler.PokeGC(JS::GCReason::NSJSCONTEXT_DESTROY, mWindowProxy);
|
||||
}
|
||||
|
||||
DropJSObjects(this);
|
||||
|
@ -1501,9 +1501,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.
|
||||
|
@ -1646,48 +1647,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
|
||||
|
@ -1722,22 +1682,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) {
|
||||
|
@ -1784,7 +1729,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();
|
||||
|
@ -1811,20 +1756,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()) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче