Bug 977940, part 2 - Don't automatically trigger the ghost window detector during ICC. r=smaug
authorAndrew McCreight <continuation@gmail.com>
Sat, 08 Mar 2014 05:38:53 -0800
changeset 190861 32504c2466e34da205889d55b6df184af394ed31
parent 190860 f1106ddac0b5fd535e964aafa5d526a430bc8573
child 190862 71e286533bd90a6e763df7d64489ddef649c5ea0
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs977940
milestone30.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 977940, part 2 - Don't automatically trigger the ghost window detector during ICC. r=smaug
dom/base/nsWindowMemoryReporter.cpp
dom/base/nsWindowMemoryReporter.h
js/xpconnect/src/XPCJSRuntime.cpp
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -26,17 +26,19 @@ StaticRefPtr<nsWindowMemoryReporter> sWi
 
 /**
  * Don't trigger a ghost window check when a DOM window is detached if we've
  * run it this recently.
  */
 const int32_t kTimeBetweenChecks = 45; /* seconds */
 
 nsWindowMemoryReporter::nsWindowMemoryReporter()
-  : mLastCheckForGhostWindows(TimeStamp::NowLoRes())
+  : mLastCheckForGhostWindows(TimeStamp::NowLoRes()),
+    mCycleCollectorIsRunning(false),
+    mCheckTimerWaitingForCCEnd(false)
 {
 }
 
 nsWindowMemoryReporter::~nsWindowMemoryReporter()
 {
   KillCheckTimer();
 }
 
@@ -111,16 +113,20 @@ nsWindowMemoryReporter::Init()
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
     // DOM_WINDOW_DESTROYED_TOPIC announces what we call window "detachment",
     // when a window's docshell is set to nullptr.
     os->AddObserver(sWindowReporter, DOM_WINDOW_DESTROYED_TOPIC,
                     /* weakRef = */ true);
     os->AddObserver(sWindowReporter, "after-minimize-memory-usage",
                     /* weakRef = */ true);
+    os->AddObserver(sWindowReporter, "cycle-collector-begin",
+                    /* weakRef = */ true);
+    os->AddObserver(sWindowReporter, "cycle-collector-end",
+                    /* weakRef = */ true);
   }
 
   RegisterStrongMemoryReporter(new GhostWindowsReporter());
   RegisterGhostWindowsDistinguishedAmount(GhostWindowsReporter::DistinguishedAmount);
 }
 
 static already_AddRefed<nsIURI>
 GetWindowURI(nsIDOMWindow *aWindow)
@@ -614,16 +620,28 @@ nsWindowMemoryReporter::GetGhostTimeout(
 NS_IMETHODIMP
 nsWindowMemoryReporter::Observe(nsISupports *aSubject, const char *aTopic,
                                 const char16_t *aData)
 {
   if (!strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC)) {
     ObserveDOMWindowDetached(aSubject);
   } else if (!strcmp(aTopic, "after-minimize-memory-usage")) {
     ObserveAfterMinimizeMemoryUsage();
+  } else if (!strcmp(aTopic, "cycle-collector-begin")) {
+    if (mCheckTimer) {
+      mCheckTimerWaitingForCCEnd = true;
+      KillCheckTimer();
+    }
+    mCycleCollectorIsRunning = true;
+  } else if (!strcmp(aTopic, "cycle-collector-end")) {
+    mCycleCollectorIsRunning = false;
+    if (mCheckTimerWaitingForCCEnd) {
+      mCheckTimerWaitingForCCEnd = false;
+      AsyncCheckForGhostWindows();
+    }
   } else {
     MOZ_ASSERT(false);
   }
 
   return NS_OK;
 }
 
 void
@@ -640,27 +658,33 @@ nsWindowMemoryReporter::ObserveDOMWindow
   AsyncCheckForGhostWindows();
 }
 
 // static
 void
 nsWindowMemoryReporter::CheckTimerFired(nsITimer* aTimer, void* aClosure)
 {
   if (sWindowReporter) {
+    MOZ_ASSERT(!sWindowReporter->mCycleCollectorIsRunning);
     sWindowReporter->CheckForGhostWindows();
   }
 }
 
 void
 nsWindowMemoryReporter::AsyncCheckForGhostWindows()
 {
   if (mCheckTimer) {
     return;
   }
 
+  if (mCycleCollectorIsRunning) {
+    mCheckTimerWaitingForCCEnd = true;
+    return;
+  }
+
   // If more than kTimeBetweenChecks seconds have elapsed since the last check,
   // timerDelay is 0.  Otherwise, it is kTimeBetweenChecks, reduced by the time
   // since the last check.  Reducing the delay by the time since the last check
   // prevents the timer from being completely starved if it is repeatedly killed
   // and restarted.
   int32_t timeSinceLastCheck = (TimeStamp::NowLoRes() - mLastCheckForGhostWindows).ToSeconds();
   int32_t timerDelay = (kTimeBetweenChecks - std::min(timeSinceLastCheck, kTimeBetweenChecks)) * PR_MSEC_PER_SEC;
 
--- a/dom/base/nsWindowMemoryReporter.h
+++ b/dom/base/nsWindowMemoryReporter.h
@@ -232,12 +232,16 @@ private:
 
   /**
    * Track the last time we ran CheckForGhostWindows(), to avoid running it
    * too often after a DOM window is detached.
    */
   mozilla::TimeStamp mLastCheckForGhostWindows;
 
   nsCOMPtr<nsITimer> mCheckTimer;
+
+  bool mCycleCollectorIsRunning;
+
+  bool mCheckTimerWaitingForCCEnd;
 };
 
 #endif // nsWindowMemoryReporter_h__
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -724,16 +724,21 @@ XPCJSRuntime::BeginCycleCollectionCallba
         obs->NotifyObservers(nullptr, "cycle-collector-begin", nullptr);
     }
 }
 
 void
 XPCJSRuntime::EndCycleCollectionCallback(CycleCollectorResults &aResults)
 {
     nsJSContext::EndCycleCollectionCallback(aResults);
+
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+        obs->NotifyObservers(nullptr, "cycle-collector-end", nullptr);
+    }
 }
 
 void
 XPCJSRuntime::DispatchDeferredDeletion(bool aContinuation)
 {
     mAsyncSnowWhiteFreer->Dispatch(aContinuation);
 }