Bug 751561 - Call forgetSkippable at least twice before CC, r=mccr8
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 03 May 2012 19:17:01 +0300
changeset 92898 82fad02b755a613ce6733d408b97187afd00a3ab
parent 92897 625cac524c5719f3e110e4e44c90c880bd667e1a
child 92899 3e391f4c1bcbc8691a3a9f68ff15d90d1091bb59
push id22599
push useropettay@mozilla.com
push dateThu, 03 May 2012 16:27:50 +0000
treeherdermozilla-central@82fad02b755a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs751561
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 751561 - Call forgetSkippable at least twice before CC, r=mccr8
content/base/src/nsCCUncollectableMarker.cpp
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -312,17 +312,17 @@ nsCCUncollectableMarker::Observe(nsISupp
     return NS_OK;
   }
 
   NS_ASSERTION(!strcmp(aTopic, "cycle-collector-begin") ||
                !strcmp(aTopic, "cycle-collector-forget-skippable"), "wrong topic");
 
   // JS cleanup can be slow. Do it only if there has been a GC.
   bool cleanupJS =
-    !nsJSContext::CleanupSinceLastGC() &&
+    nsJSContext::CleanupsSinceLastGC() == 0 &&
     !strcmp(aTopic, "cycle-collector-forget-skippable");
 
   bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
     
 
   // Increase generation to effectivly unmark all current objects
   if (!++sGeneration) {
     ++sGeneration;
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -181,17 +181,17 @@ static bool sPostGCEventsToConsole;
 static PRUint32 sCCTimerFireCount = 0;
 static PRUint32 sMinForgetSkippableTime = PR_UINT32_MAX;
 static PRUint32 sMaxForgetSkippableTime = 0;
 static PRUint32 sTotalForgetSkippableTime = 0;
 static PRUint32 sRemovedPurples = 0;
 static PRUint32 sForgetSkippableBeforeCC = 0;
 static PRUint32 sPreviousSuspectedCount = 0;
 
-static bool sCleanupSinceLastGC = true;
+static PRUint32 sCleanupsSinceLastGC = PR_UINT32_MAX;
 static bool sNeedsFullCC = false;
 
 nsScriptNameSpaceManager *gNameSpaceManager;
 
 static nsIJSRuntimeService *sRuntimeService;
 JSRuntime *nsJSRuntime::sRuntime;
 
 static const char kJSRuntimeServiceContractID[] =
@@ -2946,24 +2946,28 @@ nsJSContext::CycleCollectNow(nsICycleCol
   NS_TIME_FUNCTION_MIN(1.0);
 
   KillCCTimer();
 
   PRTime start = PR_Now();
 
   PRUint32 suspected = nsCycleCollector_suspectedCount();
 
+  // nsCycleCollector_forgetSkippable may mark some gray js to black.
+  if (sCleanupsSinceLastGC < 2 && aExtraForgetSkippableCalls >= 0) {
+    for (;sCleanupsSinceLastGC < 2; ++sCleanupsSinceLastGC) {
+      nsCycleCollector_forgetSkippable();
+    }
+  }
+
   for (PRInt32 i = 0; i < aExtraForgetSkippableCalls; ++i) {
     nsCycleCollector_forgetSkippable();
+    ++sCleanupsSinceLastGC;
   }
 
-  // nsCycleCollector_forgetSkippable may mark some gray js to black.
-  if (!sCleanupSinceLastGC && aExtraForgetSkippableCalls >= 0) {
-    nsCycleCollector_forgetSkippable();
-  }
   nsCycleCollectorResults ccResults;
   nsCycleCollector_collect(&ccResults, aListener);
   sCCollectedWaitingForGC += ccResults.mFreedRefCounted + ccResults.mFreedGCed;
 
   // If we collected a substantial amount of cycles, poke the GC since more objects
   // might be unreachable now.
   if (sCCollectedWaitingForGC > 250) {
     PokeGC(js::gcreason::CC_WAITING);
@@ -3057,17 +3061,16 @@ nsJSContext::CycleCollectNow(nsICycleCol
       observerService->NotifyObservers(nsnull, "cycle-collection-statistics", json.get());
     }
   }
   sMinForgetSkippableTime = PR_UINT32_MAX;
   sMaxForgetSkippableTime = 0;
   sTotalForgetSkippableTime = 0;
   sRemovedPurples = 0;
   sForgetSkippableBeforeCC = 0;
-  sCleanupSinceLastGC = true;
   sNeedsFullCC = false;
 }
 
 // static
 void
 GCTimerFired(nsITimer *aTimer, void *aClosure)
 {
   NS_RELEASE(sGCTimer);
@@ -3093,17 +3096,17 @@ ShouldTriggerCC(PRUint32 aSuspected)
 }
 
 static void
 TimerFireForgetSkippable(PRUint32 aSuspected, bool aRemoveChildless)
 {
   PRTime startTime = PR_Now();
   nsCycleCollector_forgetSkippable(aRemoveChildless);
   sPreviousSuspectedCount = nsCycleCollector_suspectedCount();
-  sCleanupSinceLastGC = true;
+  ++sCleanupsSinceLastGC;
   PRTime delta = PR_Now() - startTime;
   if (sMinForgetSkippableTime > delta) {
     sMinForgetSkippableTime = delta;
   }
   if (sMaxForgetSkippableTime < delta) {
     sMaxForgetSkippableTime = delta;
   }
   sTotalForgetSkippableTime += delta;
@@ -3162,20 +3165,20 @@ CCTimerFired(nsITimer *aTimer, void *aCl
     // We have either just run the CC or decided we don't want to run the CC
     // next time, so kill the timer.
     sPreviousSuspectedCount = 0;
     nsJSContext::KillCCTimer();
   }
 }
 
 // static
-bool
-nsJSContext::CleanupSinceLastGC()
+PRUint32
+nsJSContext::CleanupsSinceLastGC()
 {
-  return sCleanupSinceLastGC;
+  return sCleanupsSinceLastGC;
 }
 
 // static
 void
 nsJSContext::LoadStart()
 {
   sLoadingInProgress = true;
   ++sPendingLoadCount;
@@ -3384,17 +3387,17 @@ DOMGCSliceCallback(JSRuntime *aRt, js::G
     nsJSContext::PokeGC(js::gcreason::INTER_SLICE_GC, NS_INTERSLICE_GC_DELAY);
   }
 
   if (aProgress == js::GC_CYCLE_END) {
     // May need to kill the inter-slice GC timer
     nsJSContext::KillGCTimer();
 
     sCCollectedWaitingForGC = 0;
-    sCleanupSinceLastGC = false;
+    sCleanupsSinceLastGC = 0;
 
     if (aDesc.isCompartment) {
       // If this is a compartment GC, restart it. We still want
       // a full GC to happen. Compartment GCs usually happen as a
       // result of last-ditch or MaybeGC. In both cases it is
       // probably a time of heavy activity and we want to delay
       // the full GC, but we do want it to happen eventually.
       nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -197,17 +197,17 @@ public:
   static void PokeShrinkGCBuffers();
   static void KillShrinkGCBuffersTimer();
 
   static void MaybePokeCC();
   static void KillCCTimer();
 
   virtual void GC(js::gcreason::Reason aReason);
 
-  static bool CleanupSinceLastGC();
+  static PRUint32 CleanupsSinceLastGC();
 
   nsIScriptGlobalObject* GetCachedGlobalObject()
   {
     // Verify that we have a global so that this
     // does always return a null when GetGlobalObject() is null.
     JSObject* global = JS_GetGlobalObject(mContext);
     return global ? mGlobalObjectRef.get() : nsnull;
   }