Bug 1415780 - Don't count all observers for nsRefreshDriver. r?smaug draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Sat, 27 Jan 2018 21:17:26 +0900
changeset 748018 a0e5533273a3c240af9bc66833d4ee5eb6b59fc9
parent 748017 ac437e98691b9c120269b45512ae5ac915cad997
child 748019 19e69815abc03543c30e08d57fb9d4d61d1e2f98
push id97048
push userhikezoe@mozilla.com
push dateSat, 27 Jan 2018 12:23:10 +0000
reviewerssmaug
bugs1415780
milestone60.0a1
Bug 1415780 - Don't count all observers for nsRefreshDriver. r?smaug We just need information whether there is still an observer or not in most cases. The only case we need to know the count is in an assertion in the dtor of nsRefreshDriver. In the dtor we are checking there remains no observers other than early runners. Note that the order in HasObserver() was adjusted to reflect that we check boolean flag first (mViewManagerFlushIsPending) and subsequently check observer which is likey happen to. mFrameRequestCallbackDocs should have checked prior to mResizeEventFlushObservers though. MozReview-Commit-ID: E1qplusqw1Y
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1434,24 +1434,45 @@ nsRefreshDriver::ObserverCount() const
   sum += mPendingEvents.Length();
   sum += mFrameRequestCallbackDocs.Length();
   sum += mThrottledFrameRequestCallbackDocs.Length();
   sum += mViewManagerFlushIsPending;
   sum += mEarlyRunners.Length();
   return sum;
 }
 
-uint32_t
-nsRefreshDriver::ImageRequestCount() const
+bool
+nsRefreshDriver::HasObservers() const
 {
-  uint32_t count = 0;
+  for (uint32_t i = 0; i < ArrayLength(mObservers); ++i) {
+    if (!mObservers[i].IsEmpty()) {
+      return true;
+    }
+  }
+
+  return mViewManagerFlushIsPending ||
+         !mStyleFlushObservers.IsEmpty() ||
+         !mLayoutFlushObservers.IsEmpty() ||
+         !mResizeEventFlushObservers.IsEmpty() ||
+         !mPendingEvents.IsEmpty() ||
+         !mFrameRequestCallbackDocs.IsEmpty() ||
+         !mThrottledFrameRequestCallbackDocs.IsEmpty() ||
+         !mEarlyRunners.IsEmpty();
+}
+
+bool
+nsRefreshDriver::HasImageRequests() const
+{
   for (auto iter = mStartTable.ConstIter(); !iter.Done(); iter.Next()) {
-    count += iter.UserData()->mEntries.Count();
+    if (!iter.UserData()->mEntries.IsEmpty()) {
+      return true;
+    }
   }
-  return count + mRequests.Count();
+
+  return !mRequests.IsEmpty();
 }
 
 nsRefreshDriver::ObserverArray&
 nsRefreshDriver::ArrayFor(FlushType aFlushType)
 {
   switch (aFlushType) {
     case FlushType::Event:
       return mObservers[0];
@@ -1813,17 +1834,18 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
   if (mRootRefresh) {
     mRootRefresh->RemoveRefreshObserver(this, FlushType::Style);
     mRootRefresh = nullptr;
   }
   mSkippedPaints = false;
   mWarningThreshold = 1;
 
   nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
-  if (!presShell || (ObserverCount() == 0 && ImageRequestCount() == 0 && mScrollEvents.Length() == 0)) {
+  if (!presShell ||
+      (!HasObservers() && !HasImageRequests() && mScrollEvents.IsEmpty())) {
     // Things are being destroyed, or we no longer have any observers.
     // We don't want to stop the timer when observers are initially
     // removed, because sometimes observers can be added and removed
     // often depending on what other things are going on and in that
     // situation we don't want to thrash our timer.  So instead we
     // wait until we get a Notify() call when we have no observers
     // before stopping the timer.
     StopTimer();
@@ -2135,17 +2157,17 @@ nsRefreshDriver::Thaw()
 {
   NS_ASSERTION(mFreezeCount > 0, "Thaw() called on an unfrozen refresh driver");
 
   if (mFreezeCount > 0) {
     mFreezeCount--;
   }
 
   if (mFreezeCount == 0) {
-    if (ObserverCount() || ImageRequestCount()) {
+    if (HasObservers() || HasImageRequests()) {
       // FIXME: This isn't quite right, since our EnsureTimerStarted call
       // updates our mMostRecentRefresh, but the DoRefresh call won't run
       // and notify our observers until we get back to the event loop.
       // Thus MostRecentRefresh() will lie between now and the DoRefresh.
       RefPtr<nsRunnableMethod<nsRefreshDriver>> event = NewRunnableMethod(
         "nsRefreshDriver::DoRefresh", this, &nsRefreshDriver::DoRefresh);
       nsPresContext* pc = GetPresContext();
       if (pc) {
@@ -2160,17 +2182,17 @@ nsRefreshDriver::Thaw()
 }
 
 void
 nsRefreshDriver::FinishedWaitingForTransaction()
 {
   mWaitingForTransaction = false;
   if (mSkippedPaints &&
       !IsInRefresh() &&
-      (ObserverCount() || ImageRequestCount())) {
+      (HasObservers() || HasImageRequests())) {
     AUTO_PROFILER_TRACING("Paint", "RefreshDriverTick");
     DoRefresh();
   }
   mSkippedPaints = false;
   mWarningThreshold = 1;
 }
 
 uint64_t
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -392,18 +392,19 @@ private:
     eNone = 0,
     eForceAdjustTimer = 1 << 0,
     eAllowTimeToGoBackwards = 1 << 1,
     eNeverAdjustTimer = 1 << 2,
   };
   void EnsureTimerStarted(EnsureTimerStartedFlags aFlags = eNone);
   void StopTimer();
 
+  bool HasObservers() const;
   uint32_t ObserverCount() const;
-  uint32_t ImageRequestCount() const;
+  bool HasImageRequests() const;
   ObserverArray& ArrayFor(mozilla::FlushType aFlushType);
   // Trigger a refresh immediately, if haven't been disconnected or frozen.
   void DoRefresh();
 
   double GetRefreshTimerInterval() const;
   double GetRegularTimerInterval(bool *outIsDefault = nullptr) const;
   static double GetThrottledTimerInterval();