Bug 1692308 - Merge sGCTimer + sInterSliceGCRunner -> sGCRunner
Differential Revision: https://phabricator.services.mozilla.com/D104881
This commit is contained in:
@@ -92,11 +92,10 @@ using namespace mozilla::dom;
|
||||
# undef CompareString
|
||||
#endif
|
||||
|
||||
static nsITimer* sGCTimer;
|
||||
static nsITimer* sShrinkingGCTimer;
|
||||
static StaticRefPtr<IdleTaskRunner> sCCRunner;
|
||||
static nsITimer* sFullGCTimer;
|
||||
static StaticRefPtr<IdleTaskRunner> sInterSliceGCRunner;
|
||||
static StaticRefPtr<IdleTaskRunner> sGCRunner;
|
||||
|
||||
static JS::GCSliceCallback sPrevGCSliceCallback;
|
||||
|
||||
@@ -285,11 +284,10 @@ static TimeDuration GetCollectionTimeDelta() {
|
||||
}
|
||||
|
||||
static void KillTimers() {
|
||||
nsJSContext::KillGCTimer();
|
||||
nsJSContext::KillShrinkingGCTimer();
|
||||
nsJSContext::KillCCRunner();
|
||||
nsJSContext::KillFullGCTimer();
|
||||
nsJSContext::KillInterSliceGCRunner();
|
||||
nsJSContext::KillGCRunner();
|
||||
}
|
||||
|
||||
class nsJSEnvironmentObserver final : public nsIObserver {
|
||||
@@ -1079,8 +1077,6 @@ void nsJSContext::GarbageCollectNow(JS::GCReason aReason,
|
||||
|
||||
MOZ_ASSERT_IF(aSliceMillis, aIncremental == IncrementalGC);
|
||||
|
||||
KillGCTimer();
|
||||
|
||||
// We use danger::GetJSContext() since AutoJSAPI will assert if the current
|
||||
// thread's context is null (such as during shutdown).
|
||||
JSContext* cx = danger::GetJSContext();
|
||||
@@ -1108,6 +1104,9 @@ void nsJSContext::GarbageCollectNow(JS::GCReason aReason,
|
||||
}
|
||||
|
||||
if (aIncremental == IncrementalGC) {
|
||||
// Incremental GC slices will be triggered by the sGCRunner. If one doesn't
|
||||
// already exist, create it in the GC_SLICE_END callback for the first
|
||||
// slice being executed here.
|
||||
JS::StartIncrementalGC(cx, gckind, aReason, aSliceMillis);
|
||||
} else {
|
||||
JS::NonIncrementalGC(cx, gckind, aReason);
|
||||
@@ -1549,17 +1548,30 @@ void nsJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) {
|
||||
}
|
||||
|
||||
// static
|
||||
bool InterSliceGCRunnerFired(TimeStamp aDeadline, void* aData) {
|
||||
bool GCRunnerFired(TimeStamp aDeadline, void* /* aClosure */) {
|
||||
MOZ_ASSERT(!sShuttingDown, "GCRunner still alive during shutdown");
|
||||
|
||||
GCRunnerStep step = sScheduler.GetNextGCRunnerAction(aDeadline);
|
||||
switch (step.mAction) {
|
||||
case GCRunnerAction::None:
|
||||
nsJSContext::KillGCRunner();
|
||||
return false;
|
||||
|
||||
case GCRunnerAction::MajorGC:
|
||||
case GCRunnerAction::GCSlice:
|
||||
break;
|
||||
}
|
||||
|
||||
// Run a GC slice, possibly the first one of a major GC.
|
||||
|
||||
MOZ_ASSERT(sScheduler.mActiveIntersliceGCBudget);
|
||||
TimeStamp startTimeStamp = TimeStamp::Now();
|
||||
TimeDuration budget =
|
||||
sScheduler.ComputeInterSliceGCBudget(aDeadline, startTimeStamp);
|
||||
TimeDuration duration = sGCUnnotifiedTotalTime;
|
||||
uintptr_t reason = reinterpret_cast<uintptr_t>(aData);
|
||||
nsJSContext::GarbageCollectNow(
|
||||
aData ? static_cast<JS::GCReason>(reason) : JS::GCReason::INTER_SLICE_GC,
|
||||
nsJSContext::IncrementalGC, nsJSContext::NonShrinkingGC,
|
||||
budget.ToMilliseconds());
|
||||
nsJSContext::GarbageCollectNow(step.mReason, nsJSContext::IncrementalGC,
|
||||
nsJSContext::NonShrinkingGC,
|
||||
budget.ToMilliseconds());
|
||||
|
||||
sGCUnnotifiedTotalTime = TimeDuration();
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
@@ -1590,29 +1602,6 @@ bool InterSliceGCRunnerFired(TimeStamp aDeadline, void* aData) {
|
||||
return JS::IncrementalGCHasForegroundWork(cx);
|
||||
}
|
||||
|
||||
// static
|
||||
void GCTimerFired(nsITimer* aTimer, void* aClosure) {
|
||||
nsJSContext::KillGCTimer();
|
||||
if (sShuttingDown) {
|
||||
nsJSContext::KillInterSliceGCRunner();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sInterSliceGCRunner) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now start the actual GC after initial timer has fired.
|
||||
sInterSliceGCRunner = IdleTaskRunner::Create(
|
||||
[aClosure](TimeStamp aDeadline) {
|
||||
return InterSliceGCRunnerFired(aDeadline, aClosure);
|
||||
},
|
||||
"GCTimerFired::InterSliceGCRunnerFired", 0,
|
||||
StaticPrefs::javascript_options_gc_delay_interslice(),
|
||||
sScheduler.mActiveIntersliceGCBudget.ToMilliseconds(), true,
|
||||
[] { return sShuttingDown; });
|
||||
}
|
||||
|
||||
// static
|
||||
void ShrinkingGCTimerFired(nsITimer* aTimer, void* aClosure) {
|
||||
nsJSContext::KillShrinkingGCTimer();
|
||||
@@ -1708,20 +1697,14 @@ void nsJSContext::RunNextCollectorTimer(JS::GCReason aReason,
|
||||
return;
|
||||
}
|
||||
|
||||
if (sGCTimer) {
|
||||
if (aReason == JS::GCReason::DOM_WINDOW_UTILS) {
|
||||
// Force full GCs when called from reftests so that we collect dead zones
|
||||
// that have not been scheduled for collection.
|
||||
sScheduler.SetNeedsFullGC();
|
||||
}
|
||||
GCTimerFired(nullptr, reinterpret_cast<void*>(aReason));
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<IdleTaskRunner> runner;
|
||||
if (sInterSliceGCRunner) {
|
||||
sInterSliceGCRunner->SetIdleDeadline(aDeadline);
|
||||
runner = sInterSliceGCRunner;
|
||||
RefPtr<IdleTaskRunner> runnable;
|
||||
if (sGCRunner) {
|
||||
// If the GC has already started, we will just run the next slice here and
|
||||
// this call will have no effect (the reason will be ignored, and the
|
||||
// trigger will be cleared at the end of the GC.)
|
||||
sScheduler.SetWantMajorGC(aReason);
|
||||
sGCRunner->SetIdleDeadline(aDeadline);
|
||||
runnable = sGCRunner;
|
||||
} else {
|
||||
// Check the CC timers after the GC timers, because the CC timers won't do
|
||||
// anything if a GC is in progress.
|
||||
@@ -1731,12 +1714,12 @@ void nsJSContext::RunNextCollectorTimer(JS::GCReason aReason,
|
||||
|
||||
if (sCCRunner) {
|
||||
sCCRunner->SetIdleDeadline(aDeadline);
|
||||
runner = sCCRunner;
|
||||
runnable = sCCRunner;
|
||||
}
|
||||
}
|
||||
|
||||
if (runner) {
|
||||
runner->Run();
|
||||
if (runnable) {
|
||||
runnable->Run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1812,11 +1795,13 @@ void nsJSContext::PokeGC(JS::GCReason aReason, JSObject* aObj,
|
||||
sScheduler.SetNeedsFullGC();
|
||||
}
|
||||
|
||||
if (sGCTimer || sInterSliceGCRunner) {
|
||||
// There's already a timer for GC'ing, just return
|
||||
if (sGCRunner) {
|
||||
// There's already a runner for GC'ing, just return
|
||||
return;
|
||||
}
|
||||
|
||||
sScheduler.SetWantMajorGC(aReason);
|
||||
|
||||
if (sCCRunner) {
|
||||
// Make sure CC is called regardless of the size of the purple buffer, and
|
||||
// GC after it.
|
||||
@@ -1826,14 +1811,21 @@ void nsJSContext::PokeGC(JS::GCReason aReason, JSObject* aObj,
|
||||
|
||||
static bool first = true;
|
||||
|
||||
NS_NewTimerWithFuncCallback(
|
||||
&sGCTimer, GCTimerFired, reinterpret_cast<void*>(aReason),
|
||||
uint32_t delay =
|
||||
aDelay ? aDelay
|
||||
: (first ? StaticPrefs::javascript_options_gc_delay_first()
|
||||
: StaticPrefs::javascript_options_gc_delay()),
|
||||
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY, "GCTimerFired");
|
||||
|
||||
: StaticPrefs::javascript_options_gc_delay());
|
||||
first = false;
|
||||
|
||||
sGCRunner = IdleTaskRunner::Create(
|
||||
[](TimeStamp aDeadline) { return GCRunnerFired(aDeadline, nullptr); },
|
||||
"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; });
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -1866,14 +1858,6 @@ void nsJSContext::MaybePokeCC() {
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void nsJSContext::KillGCTimer() {
|
||||
if (sGCTimer) {
|
||||
sGCTimer->Cancel();
|
||||
NS_RELEASE(sGCTimer);
|
||||
}
|
||||
}
|
||||
|
||||
void nsJSContext::KillFullGCTimer() {
|
||||
if (sFullGCTimer) {
|
||||
sFullGCTimer->Cancel();
|
||||
@@ -1881,10 +1865,10 @@ void nsJSContext::KillFullGCTimer() {
|
||||
}
|
||||
}
|
||||
|
||||
void nsJSContext::KillInterSliceGCRunner() {
|
||||
if (sInterSliceGCRunner) {
|
||||
sInterSliceGCRunner->Cancel();
|
||||
sInterSliceGCRunner = nullptr;
|
||||
void nsJSContext::KillGCRunner() {
|
||||
if (sGCRunner) {
|
||||
sGCRunner->Cancel();
|
||||
sGCRunner = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1941,8 +1925,8 @@ static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress,
|
||||
sScheduler.NoteGCEnd();
|
||||
sIsCompactingOnUserInactive = false;
|
||||
|
||||
// May need to kill the inter-slice GC runner
|
||||
nsJSContext::KillInterSliceGCRunner();
|
||||
// May need to kill the GC runner
|
||||
nsJSContext::KillGCRunner();
|
||||
|
||||
nsJSContext::MaybePokeCC();
|
||||
|
||||
@@ -1975,17 +1959,19 @@ static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress,
|
||||
aDesc.lastSliceEnd(aCx) - aDesc.lastSliceStart(aCx);
|
||||
|
||||
if (sShuttingDown || aDesc.isComplete_) {
|
||||
nsJSContext::KillInterSliceGCRunner();
|
||||
} else if (!sInterSliceGCRunner) {
|
||||
nsJSContext::KillGCRunner();
|
||||
} else if (!sGCRunner) {
|
||||
// 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.
|
||||
sInterSliceGCRunner = IdleTaskRunner::Create(
|
||||
sGCRunner = IdleTaskRunner::Create(
|
||||
[](TimeStamp aDeadline) {
|
||||
return InterSliceGCRunnerFired(aDeadline, nullptr);
|
||||
return GCRunnerFired(aDeadline, nullptr);
|
||||
},
|
||||
"DOMGCSliceCallback::InterSliceGCRunnerFired", 0,
|
||||
StaticPrefs::javascript_options_gc_delay_interslice(),
|
||||
"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; });
|
||||
}
|
||||
@@ -2031,7 +2017,7 @@ void nsJSContext::LikelyShortLivingObjectCreated() {
|
||||
|
||||
void mozilla::dom::StartupJSEnvironment() {
|
||||
// initialize all our statics, so that we can restart XPCOM
|
||||
sGCTimer = sShrinkingGCTimer = sFullGCTimer = nullptr;
|
||||
sShrinkingGCTimer = sFullGCTimer = nullptr;
|
||||
sIsInitialized = false;
|
||||
sShuttingDown = false;
|
||||
new (&sScheduler) CCGCScheduler(); // Reset the scheduler state.
|
||||
|
||||
Reference in New Issue
Block a user