mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-25 20:01:50 +00:00
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:
parent
b36e10c7b1
commit
436b3f12a2
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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&) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -130,7 +130,7 @@ void MaybeCollectGarbageOnIPCMessage() {
|
||||
}
|
||||
|
||||
nsJSContext::GarbageCollectNow(JS::GCReason::DOM_IPC);
|
||||
nsJSContext::CycleCollectNow();
|
||||
nsJSContext::CycleCollectNow(CCReason::API);
|
||||
#endif // BUILD_GC_ON_IPC_MESSAGES
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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++) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -947,7 +947,7 @@ MOZ_EXPORT void DumpCompleteHeap() {
|
||||
return;
|
||||
}
|
||||
|
||||
nsJSContext::CycleCollectNow(alltracesListener);
|
||||
nsJSContext::CycleCollectNow(CCReason::DUMP_HEAP, alltracesListener);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user