Bug 1732161 - Track CCReason for all cycle collections (replacing ccType) r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D126395
This commit is contained in:
Steve Fink 2021-10-14 18:15:40 +00:00
parent b36e10c7b1
commit 436b3f12a2
23 changed files with 121 additions and 82 deletions

View File

@ -72,7 +72,7 @@ struct CCIntervalMarker {
};
#endif
void CCGCScheduler::NoteCCBegin(TimeStamp aWhen) {
void CCGCScheduler::NoteCCBegin(CCReason aReason, TimeStamp aWhen) {
#ifdef MOZ_GECKO_PROFILER
profiler_add_marker("CC", baseprofiler::category::GCCC,
MarkerOptions(MarkerTiming::IntervalStart(aWhen)),
@ -439,14 +439,13 @@ void CCGCScheduler::MaybePokeCC(TimeStamp aNow, uint32_t aSuspectedCCObjects) {
return;
}
MOZ_ASSERT(mCCReason == CCReason::NO_REASON);
CCReason reason = ShouldScheduleCC(aNow, aSuspectedCCObjects);
if (reason != CCReason::NO_REASON) {
// We can kill some objects before running forgetSkippable.
nsCycleCollector_dispatchDeferredDeletion();
if (!mCCRunner) {
InitCCRunnerStateMachine(CCRunnerState::ReducePurple);
InitCCRunnerStateMachine(CCRunnerState::ReducePurple, reason);
}
EnsureCCRunner(kCCSkippableDelay, kForgetSkippableSliceDuration);
}
@ -735,8 +734,12 @@ CCRunnerStep CCGCScheduler::AdvanceCCRunner(TimeStamp aDeadline, TimeStamp aNow,
[[fallthrough]];
// CycleCollecting: continue running slices until done.
case CCRunnerState::CycleCollecting:
return {CCRunnerAction::CycleCollect, Yield};
case CCRunnerState::CycleCollecting: {
CCRunnerStep step{CCRunnerAction::CycleCollect, Yield};
step.mCCReason = mCCReason;
mCCReason = CCReason::SLICE; // Set reason for following slices.
return step;
}
default:
MOZ_CRASH("Unexpected CCRunner state");

View File

@ -105,6 +105,9 @@ struct CCRunnerStep {
// or not. (ForgetSkippable is the only action requiring a parameter; if
// that changes, this will become a union.)
CCRunnerForgetSkippableRemoveChildless mRemoveChildless;
// If the action is CycleCollect, the reason for the collection.
CCReason mCCReason;
};
class CCGCScheduler {
@ -200,14 +203,18 @@ class CCGCScheduler {
return true;
}
// Starting a major GC (incremental or non-incremental).
void NoteGCBegin();
// Major GC completed.
void NoteGCEnd();
// A timer fired, but then decided not to run a GC.
void NoteWontGC();
// This is invoked when we reach the actual cycle collection portion of the
// overall cycle collection.
void NoteCCBegin(TimeStamp aWhen);
void NoteCCBegin(CCReason aReason, TimeStamp aWhen);
// This is invoked when the whole process of collection is done -- i.e., CC
// preparation (eg ForgetSkippables) in addition to the CC itself. There
@ -355,11 +362,14 @@ class CCGCScheduler {
NumStates
};
void InitCCRunnerStateMachine(CCRunnerState initialState) {
void InitCCRunnerStateMachine(CCRunnerState initialState, CCReason aReason) {
if (mCCRunner) {
return;
}
MOZ_ASSERT(mCCReason == CCReason::NO_REASON);
mCCReason = aReason;
// The state machine should always have been deactivated after the previous
// collection, however far that collection may have gone.
MOZ_ASSERT(mCCRunnerState == CCRunnerState::Inactive,
@ -378,7 +388,10 @@ class CCGCScheduler {
}
}
void DeactivateCCRunner() { mCCRunnerState = CCRunnerState::Inactive; }
void DeactivateCCRunner() {
mCCRunnerState = CCRunnerState::Inactive;
mCCReason = CCReason::NO_REASON;
}
GCRunnerStep GetNextGCRunnerAction() const;
@ -438,6 +451,7 @@ class CCGCScheduler {
nsITimer* mShrinkingGCTimer = nullptr;
nsITimer* mFullGCTimer = nullptr;
mozilla::CCReason mCCReason = mozilla::CCReason::NO_REASON;
JS::GCReason mMajorGCReason = JS::GCReason::NO_REASON;
bool mIsCompactingOnUserInactive = false;

View File

@ -50,7 +50,7 @@ void FuzzingFunctions::Crash(const GlobalObject& aGlobalObject,
/* static */
void FuzzingFunctions::CycleCollect(const GlobalObject&) {
nsJSContext::CycleCollectNow();
nsJSContext::CycleCollectNow(CCReason::API);
}
void FuzzingFunctions::MemoryPressure(const GlobalObject&) {

View File

@ -1294,14 +1294,14 @@ nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener* aListener) {
AUTO_PROFILER_LABEL("nsDOMWindowUtils::GarbageCollect", GCCC);
nsJSContext::GarbageCollectNow(JS::GCReason::DOM_UTILS);
nsJSContext::CycleCollectNow(aListener);
nsJSContext::CycleCollectNow(CCReason::API, aListener);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener* aListener) {
nsJSContext::CycleCollectNow(aListener);
nsJSContext::CycleCollectNow(CCReason::API, aListener);
return NS_OK;
}

View File

@ -1360,20 +1360,22 @@ void CycleCollectorStats::MaybeNotifyStats(
}
// static
void nsJSContext::CycleCollectNow(nsICycleCollectorListener* aListener) {
void nsJSContext::CycleCollectNow(CCReason aReason,
nsICycleCollectorListener* aListener) {
if (!NS_IsMainThread()) {
return;
}
AUTO_PROFILER_LABEL("nsJSContext::CycleCollectNow", GCCC);
PrepareForCycleCollectionSlice(TimeStamp());
nsCycleCollector_collect(aListener);
PrepareForCycleCollectionSlice(aReason, TimeStamp());
nsCycleCollector_collect(aReason, aListener);
sCCStats.AfterCycleCollectionSlice();
}
// static
void nsJSContext::PrepareForCycleCollectionSlice(TimeStamp aDeadline) {
void nsJSContext::PrepareForCycleCollectionSlice(CCReason aReason,
TimeStamp aDeadline) {
TimeStamp beginTime = TimeStamp::Now();
// Before we begin the cycle collection, make sure there is no active GC.
@ -1384,7 +1386,7 @@ void nsJSContext::PrepareForCycleCollectionSlice(TimeStamp aDeadline) {
}
if (!sScheduler.IsCollectingCycles()) {
sScheduler.NoteCCBegin(beginTime);
sScheduler.NoteCCBegin(aReason, beginTime);
}
sCCStats.AfterPrepareForCycleCollectionSlice(aDeadline, beginTime,
@ -1392,7 +1394,8 @@ void nsJSContext::PrepareForCycleCollectionSlice(TimeStamp aDeadline) {
}
// static
void nsJSContext::RunCycleCollectorSlice(TimeStamp aDeadline) {
void nsJSContext::RunCycleCollectorSlice(CCReason aReason,
TimeStamp aDeadline) {
if (!NS_IsMainThread()) {
return;
}
@ -1402,7 +1405,7 @@ void nsJSContext::RunCycleCollectorSlice(TimeStamp aDeadline) {
AUTO_PROFILER_LABEL("nsJSContext::RunCycleCollectorSlice", GCCC);
PrepareForCycleCollectionSlice(aDeadline);
PrepareForCycleCollectionSlice(aReason, aDeadline);
// Decide how long we want to budget for this slice.
if (sIncrementalCC) {
@ -1410,10 +1413,10 @@ void nsJSContext::RunCycleCollectorSlice(TimeStamp aDeadline) {
js::SliceBudget budget = sScheduler.ComputeCCSliceBudget(
aDeadline, sCCStats.mBeginTime, sCCStats.mEndSliceTime,
TimeStamp::Now(), &preferShorterSlices);
nsCycleCollector_collectSlice(budget, preferShorterSlices);
nsCycleCollector_collectSlice(budget, aReason, preferShorterSlices);
} else {
js::SliceBudget budget = js::SliceBudget::unlimited();
nsCycleCollector_collectSlice(budget, false);
nsCycleCollector_collectSlice(budget, aReason, false);
}
sCCStats.AfterCycleCollectionSlice();
@ -1427,10 +1430,10 @@ void nsJSContext::RunCycleCollectorWorkSlice(int64_t aWorkBudget) {
AUTO_PROFILER_LABEL("nsJSContext::RunCycleCollectorWorkSlice", GCCC);
PrepareForCycleCollectionSlice(TimeStamp());
PrepareForCycleCollectionSlice(CCReason::API, TimeStamp());
js::SliceBudget budget = js::SliceBudget(js::WorkBudget(aWorkBudget));
nsCycleCollector_collectSlice(budget);
nsCycleCollector_collectSlice(budget, CCReason::API);
sCCStats.AfterCycleCollectionSlice();
}
@ -1444,7 +1447,7 @@ uint32_t nsJSContext::GetMaxCCSliceTimeSinceClear() {
}
// static
void nsJSContext::BeginCycleCollectionCallback() {
void nsJSContext::BeginCycleCollectionCallback(CCReason aReason) {
MOZ_ASSERT(NS_IsMainThread());
TimeStamp startTime = TimeStamp::Now();
@ -1466,7 +1469,7 @@ void nsJSContext::BeginCycleCollectionCallback() {
}
sScheduler.InitCCRunnerStateMachine(
mozilla::CCGCScheduler::CCRunnerState::CycleCollecting);
mozilla::CCGCScheduler::CCRunnerState::CycleCollecting, aReason);
sScheduler.EnsureCCRunner(kICCIntersliceDelay, kIdleICCSliceBudget);
}
@ -1548,7 +1551,7 @@ bool CCGCScheduler::CCRunnerFired(TimeStamp aDeadline) {
case CCRunnerAction::CycleCollect:
// Cycle collection slice.
nsJSContext::RunCycleCollectorSlice(aDeadline);
nsJSContext::RunCycleCollectorSlice(step.mCCReason, aDeadline);
break;
case CCRunnerAction::StopRunning:
@ -1641,7 +1644,7 @@ void nsJSContext::DoLowMemoryGC() {
nsJSContext::GarbageCollectNow(JS::GCReason::MEM_PRESSURE,
nsJSContext::NonIncrementalGC,
nsJSContext::ShrinkingGC);
nsJSContext::CycleCollectNow();
nsJSContext::CycleCollectNow(CCReason::MEM_PRESSURE);
if (sScheduler.NeedsGCAfterCC()) {
nsJSContext::GarbageCollectNow(JS::GCReason::MEM_PRESSURE,
nsJSContext::NonIncrementalGC,

View File

@ -69,19 +69,22 @@ class nsJSContext : public nsIScriptContext {
IsShrinking aShrinking = NonShrinkingGC,
int64_t aSliceMillis = 0);
static void CycleCollectNow(nsICycleCollectorListener* aListener = nullptr);
static void CycleCollectNow(mozilla::CCReason aReason,
nsICycleCollectorListener* aListener = nullptr);
// Finish up any in-progress incremental GC.
static void PrepareForCycleCollectionSlice(mozilla::TimeStamp aDeadline);
static void PrepareForCycleCollectionSlice(mozilla::CCReason aReason,
mozilla::TimeStamp aDeadline);
// Run a cycle collector slice, using a heuristic to decide how long to run
// it.
static void RunCycleCollectorSlice(mozilla::TimeStamp aDeadline);
static void RunCycleCollectorSlice(mozilla::CCReason aReason,
mozilla::TimeStamp aDeadline);
// Run a cycle collector slice, using the given work budget.
static void RunCycleCollectorWorkSlice(int64_t aWorkBudget);
static void BeginCycleCollectionCallback();
static void BeginCycleCollectionCallback(mozilla::CCReason aReason);
static void EndCycleCollectionCallback(
mozilla::CycleCollectorResults& aResults);

View File

@ -105,10 +105,10 @@ void TestCC::MaybePokeCC() {
// nsJSContext::MaybePokeCC
// In all tests so far, we will be running this just after a GC.
mozilla::CCReason reason = mScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects());
CCReason reason = mScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects());
EXPECT_EQ(reason, CCReason::GC_FINISHED);
mScheduler.InitCCRunnerStateMachine(CCRunnerState::ReducePurple);
mScheduler.InitCCRunnerStateMachine(CCRunnerState::ReducePurple, reason);
EXPECT_TRUE(mScheduler.IsEarlyForgetSkippable());
}
@ -184,9 +184,8 @@ void TestCC::EndCycleCollectionCallback() {
void TestCC::KillCCRunner() {
// nsJSContext::KillCCRunner
mScheduler.UnblockCC();
mScheduler.DeactivateCCRunner();
mScheduler.NoteCCEnd(Now());
mScheduler.KillCCRunner();
}
class TestIdleCC : public TestCC {

View File

@ -130,7 +130,7 @@ void MaybeCollectGarbageOnIPCMessage() {
}
nsJSContext::GarbageCollectNow(JS::GCReason::DOM_IPC);
nsJSContext::CycleCollectNow();
nsJSContext::CycleCollectNow(CCReason::API);
#endif // BUILD_GC_ON_IPC_MESSAGES
}

View File

@ -2638,7 +2638,7 @@ mozilla::ipc::IPCResult ContentChild::RecvCycleCollect() {
if (obs) {
obs->NotifyObservers(nullptr, "child-cc-request", nullptr);
}
nsJSContext::CycleCollectNow();
nsJSContext::CycleCollectNow(CCReason::IPC_MESSAGE);
return IPC_OK();
}

View File

@ -837,7 +837,8 @@ class WorkerJSRuntime final : public mozilla::CycleCollectedJSRuntime {
virtual void PrepareForForgetSkippable() override {}
virtual void BeginCycleCollectionCallback() override {}
virtual void BeginCycleCollectionCallback(
mozilla::CCReason aReason) override {}
virtual void EndCycleCollectionCallback(
CycleCollectorResults& aResults) override {}
@ -858,7 +859,8 @@ class WorkerJSRuntime final : public mozilla::CycleCollectedJSRuntime {
mWorkerPrivate->AssertIsOnWorkerThread();
if (aStatus == JSGC_END) {
bool collectedAnything = nsCycleCollector_collect(nullptr);
bool collectedAnything =
nsCycleCollector_collect(CCReason::GC_FINISHED, nullptr);
mWorkerPrivate->SetCCCollectedAnything(collectedAnything);
}
}

View File

@ -5012,7 +5012,7 @@ void WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking,
void WorkerPrivate::CycleCollectInternal(bool aCollectChildren) {
auto data = mWorkerThreadAccessible.Access();
nsCycleCollector_collect(nullptr);
nsCycleCollector_collect(CCReason::WORKER, nullptr);
if (aCollectChildren) {
for (uint32_t index = 0; index < data->mChildWorkers.Length(); index++) {

View File

@ -73,7 +73,8 @@ class WorkletJSRuntime final : public mozilla::CycleCollectedJSRuntime {
virtual void PrepareForForgetSkippable() override {}
virtual void BeginCycleCollectionCallback() override {}
virtual void BeginCycleCollectionCallback(
mozilla::CCReason aReason) override {}
virtual void EndCycleCollectionCallback(
CycleCollectorResults& aResults) override {}
@ -91,7 +92,7 @@ class WorkletJSRuntime final : public mozilla::CycleCollectedJSRuntime {
// call can be skipped in this GC as ~CycleCollectedJSContext removes the
// context from |this|.
if (aStatus == JSGC_END && GetContext()) {
nsCycleCollector_collect(nullptr);
nsCycleCollector_collect(CCReason::GC_FINISHED, nullptr);
}
}
};

View File

@ -1631,7 +1631,7 @@ nsXPCComponents_Utils::ForceGC(JSContext* aCx) {
NS_IMETHODIMP
nsXPCComponents_Utils::ForceCC(nsICycleCollectorListener* listener) {
nsJSContext::CycleCollectNow(listener);
nsJSContext::CycleCollectNow(CCReason::API, listener);
return NS_OK;
}

View File

@ -740,8 +740,8 @@ void XPCJSRuntime::PrepareForForgetSkippable() {
}
}
void XPCJSRuntime::BeginCycleCollectionCallback() {
nsJSContext::BeginCycleCollectionCallback();
void XPCJSRuntime::BeginCycleCollectionCallback(CCReason aReason) {
nsJSContext::BeginCycleCollectionCallback(aReason);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
@ -801,9 +801,12 @@ void XPCJSRuntime::GCSliceCallback(JSContext* cx, JS::GCProgress progress,
void XPCJSRuntime::DoCycleCollectionCallback(JSContext* cx) {
// The GC has detected that a CC at this point would collect a tremendous
// amount of garbage that is being revivified unnecessarily.
NS_DispatchToCurrentThread(
NS_NewRunnableFunction("XPCJSRuntime::DoCycleCollectionCallback",
[]() { nsJSContext::CycleCollectNow(nullptr); }));
//
// The GC_WAITING reason is a little overloaded here, but we want to do
// a CC to allow Realms to be collected when they are referenced by a cycle.
NS_DispatchToCurrentThread(NS_NewRunnableFunction(
"XPCJSRuntime::DoCycleCollectionCallback",
[]() { nsJSContext::CycleCollectNow(CCReason::GC_WAITING, nullptr); }));
XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
if (!self) {

View File

@ -947,7 +947,7 @@ MOZ_EXPORT void DumpCompleteHeap() {
return;
}
nsJSContext::CycleCollectNow(alltracesListener);
nsJSContext::CycleCollectNow(CCReason::DUMP_HEAP, alltracesListener);
}
} // extern "C"

View File

@ -533,7 +533,7 @@ class XPCJSRuntime final : public mozilla::CycleCollectedJSRuntime {
nsCycleCollectionNoteRootCallback& cb) override;
void UnmarkSkippableJSHolders();
void PrepareForForgetSkippable() override;
void BeginCycleCollectionCallback() override;
void BeginCycleCollectionCallback(mozilla::CCReason aReason) override;
void EndCycleCollectionCallback(
mozilla::CycleCollectorResults& aResults) override;
void DispatchDeferredDeletion(bool aContinuation,

View File

@ -240,7 +240,7 @@ static int FuzzingRunNetworkHttp(const uint8_t* data, size_t size) {
// Wait for the channel to be destroyed
SpinEventLoopUntil(
"FuzzingRunNetworkHttp(channel == nullptr)"_ns, [&]() -> bool {
nsCycleCollector_collect(nullptr);
nsCycleCollector_collect(CCReason::API, nullptr);
nsCOMPtr<nsIHttpChannel> channel = do_QueryReferent(channelRef);
return channel == nullptr;
});

View File

@ -205,7 +205,7 @@ static int FuzzingRunNetworkWebsocket(const uint8_t* data, size_t size) {
// Wait for the channel to be destroyed
SpinEventLoopUntil(
"FuzzingRunNetworkWebsocket(channel == nullptr)"_ns, [&]() -> bool {
nsCycleCollector_collect(nullptr);
nsCycleCollector_collect(CCReason::API, nullptr);
nsCOMPtr<nsIWebSocketChannel> channel = do_QueryReferent(channelRef);
return channel == nullptr;
});

View File

@ -305,7 +305,7 @@ class CycleCollectedJSRuntime {
CycleCollectedJSContext::DeferredFinalizeType aType);
virtual void PrepareForForgetSkippable() = 0;
virtual void BeginCycleCollectionCallback() = 0;
virtual void BeginCycleCollectionCallback(mozilla::CCReason aReason) = 0;
virtual void EndCycleCollectionCallback(CycleCollectorResults& aResults) = 0;
virtual void DispatchDeferredDeletion(bool aContinuation,
bool aPurge = false) = 0;

View File

@ -106,6 +106,21 @@ static inline bool IsManualCCReason(CCReason reason) {
return reason >= CCReason::FIRST_MANUAL_REASON;
}
static inline const char* CCReasonToString(CCReason aReason) {
switch (aReason) {
#define SET_REASON_STR(name) \
case CCReason::name: \
return #name; \
break;
FOR_EACH_CCREASON(SET_REASON_STR)
#undef SET_REASON_STR
default:
return "<unknown-reason>";
}
}
} // namespace mozilla
/**
* Just holds the IID so NS_GET_IID works.
*/

View File

@ -1075,13 +1075,6 @@ enum ccPhase {
CleanupPhase
};
enum ccType {
SliceCC, /* If a CC is in progress, continue it.
Otherwise, start a new one. */
ManualCC, /* Explicitly triggered. */
ShutdownCC /* Shutdown CC, used for finding leaks. */
};
enum ccIsManual { CCIsNotManual = false, CCIsManual = true };
////////////////////////////////////////////////////////////////////////
@ -1163,9 +1156,9 @@ class nsCycleCollector : public nsIMemoryReporter {
void RemoveObjectFromGraph(void* aPtr);
void PrepareForGarbageCollection();
void FinishAnyCurrentCollection();
void FinishAnyCurrentCollection(CCReason aReason);
bool Collect(ccType aCCType, ccIsManual aIsManual, SliceBudget& aBudget,
bool Collect(CCReason aReason, ccIsManual aIsManual, SliceBudget& aBudget,
nsICycleCollectorListener* aManualListener,
bool aPreferShorterSlices = false);
MOZ_CAN_RUN_SCRIPT
@ -1191,7 +1184,7 @@ class nsCycleCollector : public nsIMemoryReporter {
void FinishAnyIncrementalGCInProgress();
bool ShouldMergeZones(ccIsManual aIsManual);
void BeginCollection(ccType aCCType, ccIsManual aIsManual,
void BeginCollection(CCReason aReason, ccIsManual aIsManual,
nsICycleCollectorListener* aManualListener);
void MarkRoots(SliceBudget& aBudget);
void ScanRoots(bool aFullySynchGraphBuild);
@ -3349,8 +3342,8 @@ void nsCycleCollector::ShutdownCollect() {
uint32_t i;
bool collectedAny = true;
for (i = 0; i < DEFAULT_SHUTDOWN_COLLECTIONS && collectedAny; ++i) {
collectedAny =
Collect(ShutdownCC, ccIsManual::CCIsManual, unlimitedBudget, nullptr);
collectedAny = Collect(CCReason::SHUTDOWN, ccIsManual::CCIsManual,
unlimitedBudget, nullptr);
// Run any remaining tasks that may have been enqueued via RunInStableState
// or DispatchToMicroTask. These can hold alive CCed objects, and we want to
// clear them out before we run the CC again or finish shutting down.
@ -3367,7 +3360,7 @@ static void PrintPhase(const char* aPhase) {
#endif
}
bool nsCycleCollector::Collect(ccType aCCType, ccIsManual aIsManual,
bool nsCycleCollector::Collect(CCReason aReason, ccIsManual aIsManual,
SliceBudget& aBudget,
nsICycleCollectorListener* aManualListener,
bool aPreferShorterSlices) {
@ -3408,7 +3401,7 @@ bool nsCycleCollector::Collect(ccType aCCType, ccIsManual aIsManual,
switch (mIncrementalPhase) {
case IdlePhase:
PrintPhase("BeginCollection");
BeginCollection(aCCType, aIsManual, aManualListener);
BeginCollection(aReason, aIsManual, aManualListener);
break;
case GraphBuildingPhase:
PrintPhase("MarkRoots");
@ -3460,7 +3453,7 @@ bool nsCycleCollector::Collect(ccType aCCType, ccIsManual aIsManual,
// Somebody has forced a CC, so after having finished out the current CC,
// run the CC again using the new listener.
MOZ_ASSERT(IsIdle());
if (Collect(aCCType, ccIsManual::CCIsManual, aBudget, aManualListener)) {
if (Collect(aReason, ccIsManual::CCIsManual, aBudget, aManualListener)) {
collectedAny = true;
}
}
@ -3484,18 +3477,18 @@ void nsCycleCollector::PrepareForGarbageCollection() {
return;
}
FinishAnyCurrentCollection();
FinishAnyCurrentCollection(CCReason::GC_WAITING);
}
void nsCycleCollector::FinishAnyCurrentCollection() {
void nsCycleCollector::FinishAnyCurrentCollection(CCReason aReason) {
if (IsIdle()) {
return;
}
SliceBudget unlimitedBudget = SliceBudget::unlimited();
PrintPhase("FinishAnyCurrentCollection");
// Use SliceCC because we only want to finish the CC in progress.
Collect(SliceCC, ccIsManual::CCIsNotManual, unlimitedBudget, nullptr);
// Use CCIsNotManual because we only want to finish the CC in progress.
Collect(aReason, ccIsManual::CCIsNotManual, unlimitedBudget, nullptr);
// It is only okay for Collect() to have failed to finish the
// current CC if we're reentering the CC at some point past
@ -3540,7 +3533,7 @@ bool nsCycleCollector::ShouldMergeZones(ccIsManual aIsManual) {
}
void nsCycleCollector::BeginCollection(
ccType aCCType, ccIsManual aIsManual,
CCReason aReason, ccIsManual aIsManual,
nsICycleCollectorListener* aManualListener) {
TimeLog timeLog;
MOZ_ASSERT(IsIdle());
@ -3549,11 +3542,11 @@ void nsCycleCollector::BeginCollection(
mCollectionStart = TimeStamp::Now();
if (mCCJSRuntime) {
mCCJSRuntime->BeginCycleCollectionCallback();
mCCJSRuntime->BeginCycleCollectionCallback(aReason);
timeLog.Checkpoint("BeginCycleCollectionCallback()");
}
bool isShutdown = (aCCType == ShutdownCC);
bool isShutdown = (aReason == CCReason::SHUTDOWN);
// Set up the listener for this CC.
MOZ_ASSERT_IF(isShutdown, !aManualListener);
@ -3902,7 +3895,8 @@ already_AddRefed<nsICycleCollectorLogSink> nsCycleCollector_createLogSink() {
return sink.forget();
}
bool nsCycleCollector_collect(nsICycleCollectorListener* aManualListener) {
bool nsCycleCollector_collect(CCReason aReason,
nsICycleCollectorListener* aManualListener) {
CollectorData* data = sCollectorData.get();
// We should have started the cycle collector by now.
@ -3912,11 +3906,11 @@ bool nsCycleCollector_collect(nsICycleCollectorListener* aManualListener) {
AUTO_PROFILER_LABEL("nsCycleCollector_collect", GCCC);
SliceBudget unlimitedBudget = SliceBudget::unlimited();
return data->mCollector->Collect(ManualCC, ccIsManual::CCIsManual,
return data->mCollector->Collect(aReason, ccIsManual::CCIsManual,
unlimitedBudget, aManualListener);
}
void nsCycleCollector_collectSlice(SliceBudget& budget,
void nsCycleCollector_collectSlice(SliceBudget& budget, CCReason aReason,
bool aPreferShorterSlices) {
CollectorData* data = sCollectorData.get();
@ -3926,7 +3920,7 @@ void nsCycleCollector_collectSlice(SliceBudget& budget,
AUTO_PROFILER_LABEL("nsCycleCollector_collectSlice", GCCC);
data->mCollector->Collect(SliceCC, ccIsManual::CCIsNotManual, budget, nullptr,
data->mCollector->Collect(aReason, ccIsManual::CCIsNotManual, budget, nullptr,
aPreferShorterSlices);
}
@ -3951,7 +3945,7 @@ void nsCycleCollector_finishAnyCurrentCollection() {
return;
}
data->mCollector->FinishAnyCurrentCollection();
data->mCollector->FinishAnyCurrentCollection(CCReason::API);
}
void nsCycleCollector_shutdown(bool aDoCollect) {

View File

@ -53,9 +53,11 @@ already_AddRefed<nsICycleCollectorLogSink> nsCycleCollector_createLogSink();
already_AddRefed<nsICycleCollectorListener> nsCycleCollector_createLogger();
// Run a cycle collection and return whether anything was collected.
bool nsCycleCollector_collect(nsICycleCollectorListener* aManualListener);
bool nsCycleCollector_collect(mozilla::CCReason aReason,
nsICycleCollectorListener* aManualListener);
void nsCycleCollector_collectSlice(js::SliceBudget& budget,
mozilla::CCReason aReason,
bool aPreferShorterSlices = false);
uint32_t nsCycleCollector_suspectedCount();

View File

@ -346,7 +346,7 @@ nsMemoryInfoDumper::DumpGCAndCCLogsToFile(
logSink->SetFilenameIdentifier(identifier);
nsJSContext::CycleCollectNow(logger);
nsJSContext::CycleCollectNow(CCReason::DUMP_HEAP, logger);
nsCOMPtr<nsIFile> gcLog, ccLog;
logSink->GetGcLog(getter_AddRefs(gcLog));
@ -369,7 +369,7 @@ nsMemoryInfoDumper::DumpGCAndCCLogsToSink(bool aDumpAllTraces,
logger->SetLogSink(aSink);
nsJSContext::CycleCollectNow(logger);
nsJSContext::CycleCollectNow(CCReason::DUMP_HEAP, logger);
return NS_OK;
}