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 189836 32504c2466e34da205889d55b6df184af394ed31
parent 189835 f1106ddac0b5fd535e964aafa5d526a430bc8573
child 189837 71e286533bd90a6e763df7d64489ddef649c5ea0
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [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);
 }