diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 9bb8efd22f8..084cda85c94 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -3871,6 +3871,13 @@ nsDOMWindowUtils::SetNextPaintSyncId(int32_t aSyncId) return NS_OK; } +NS_IMETHODIMP +nsDOMWindowUtils::CycleCollectFull() +{ + nsJSContext::CycleCollectFullNow(); + return NS_OK; +} + NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 8d27cf3d468..c653bc86619 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1583,6 +1583,22 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, gCCStats.FinishCycleCollectionSlice(); } +//static +void +nsJSContext::CycleCollectFullNow() +{ + if (!NS_IsMainThread()) { + return; + } + + PROFILER_LABEL("nsJSContext", "CycleCollectFullNow", + js::ProfileEntry::Category::CC); + + gCCStats.PrepareForCycleCollectionSlice(0); + nsCycleCollector_collectFull(); + gCCStats.FinishCycleCollectionSlice(); +} + //static void nsJSContext::RunCycleCollectorSlice() diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index 5b9509cf9d3..b25dd48b007 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -94,6 +94,7 @@ public: // called even if the previous collection was GC. static void CycleCollectNow(nsICycleCollectorListener *aListener = nullptr, int32_t aExtraForgetSkippableCalls = 0); + static void CycleCollectFullNow(); // Run a cycle collector slice, using a heuristic to decide how long to run it. static void RunCycleCollectorSlice(); diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 5df31008946..33533561725 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -1842,6 +1842,9 @@ interface nsIDOMWindowUtils : nsISupports { void forceUseCounterFlush(in nsIDOMNode aNode); void setNextPaintSyncId(in long aSyncId); + + /* Force a full cycle collection, including garbage collection and freeing all SnowWhites. */ + void cycleCollectFull(); }; [scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)] diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 0fc5051d684..bb9627a10f8 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -1239,6 +1239,7 @@ enum ccType { SliceCC, /* If a CC is in progress, continue it. Otherwise, start a new one. */ ManualCC, /* Explicitly triggered. */ + FullCC, /* Explicitly triggered, always doing a full collection. */ ShutdownCC /* Shutdown CC, used for finding leaks. */ }; @@ -3692,6 +3693,8 @@ nsCycleCollector::Collect(ccType aCCType, if (Collect(aCCType, aBudget, aManualListener)) { collectedAny = true; } + } else if (aCCType == FullCC && collectedAny) { + FreeSnowWhite(true); } MOZ_ASSERT_IF(aCCType != SliceCC, IsIdle()); @@ -3808,7 +3811,7 @@ nsCycleCollector::BeginCollection(ccType aCCType, // On a WantAllTraces CC, force a synchronous global GC to prevent // hijinks from ForgetSkippable and compartmental GCs. - bool forceGC = isShutdown || (mLogger && mLogger->IsAllTraces()); + bool forceGC = isShutdown || aCCType == FullCC || (mLogger && mLogger->IsAllTraces()); // BeginCycleCollectionCallback() might have started an IGC, and we need // to finish it before we run FixGrayBits. @@ -4137,6 +4140,22 @@ nsCycleCollector_collect(nsICycleCollectorListener* aManualListener) data->mCollector->Collect(ManualCC, unlimitedBudget, aManualListener); } +void +nsCycleCollector_collectFull() +{ + CollectorData* data = sCollectorData.get(); + + // We should have started the cycle collector by now. + MOZ_ASSERT(data); + MOZ_ASSERT(data->mCollector); + + PROFILER_LABEL("nsCycleCollector", "collectFull", + js::ProfileEntry::Category::CC); + + SliceBudget unlimitedBudget = SliceBudget::unlimited(); + data->mCollector->Collect(FullCC, unlimitedBudget, NULL); +} + void nsCycleCollector_collectSlice(SliceBudget& budget, bool aPreferShorterSlices) diff --git a/xpcom/base/nsCycleCollector.h b/xpcom/base/nsCycleCollector.h index 3988702e48d..747a777b724 100644 --- a/xpcom/base/nsCycleCollector.h +++ b/xpcom/base/nsCycleCollector.h @@ -47,6 +47,8 @@ already_AddRefed nsCycleCollector_createLogSink(); void nsCycleCollector_collect(nsICycleCollectorListener* aManualListener); +void nsCycleCollector_collectFull(); + void nsCycleCollector_collectSlice(js::SliceBudget& budget, bool aPreferShorterSlices = false);