Bug 1158557 - Don't throttle rAF for documents with live static clones. r=smaug
authorSeth Fowler <mark.seth.fowler@gmail.com>
Fri, 01 May 2015 12:37:27 -0700
changeset 242105 352eda4d6a0520648c9838eb01093811eafee984
parent 242104 b7d29990d64510692ad42aa6d14974d347bc46ff
child 242106 6fa4bb578765097f82a0affb14a4feb0ef585f42
push id28679
push userphilringnalda@gmail.com
push dateSat, 02 May 2015 17:02:29 +0000
treeherdermozilla-central@0f5eacc986e8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1158557
milestone40.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 1158557 - Don't throttle rAF for documents with live static clones. r=smaug
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1631,16 +1631,18 @@ ClearAllBoxObjects(nsIContent* aKey, nsP
 nsIDocument::~nsIDocument()
 {
   MOZ_ASSERT(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
              "must not have media query lists left");
 
   if (mNodeInfoManager) {
     mNodeInfoManager->DropDocumentReference();
   }
+
+  UnlinkOriginalDocumentIfStatic();
 }
 
 
 nsDocument::~nsDocument()
 {
 #ifdef PR_LOGGING
   if (gDocumentLeakPRLog)
     PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
@@ -2088,23 +2090,24 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   // Unlink the mChildren nsAttrAndChildArray.
   for (int32_t indx = int32_t(tmp->mChildren.ChildCount()) - 1;
        indx >= 0; --indx) {
     tmp->mChildren.ChildAt(indx)->UnbindFromTree();
     tmp->mChildren.RemoveChildAt(indx);
   }
   tmp->mFirstChild = nullptr;
 
+  tmp->UnlinkOriginalDocumentIfStatic();
+
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mXPathEvaluator)
   tmp->mCachedRootElement = nullptr; // Avoid a dangling pointer
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFirstBaseNodeWithHref)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mUndoManager)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentTimeline)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingAnimationTracker)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mRegistry)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMasterDocument)
@@ -3920,16 +3923,21 @@ nsIDocument::TakeFrameRequestCallbacks(F
 {
   aCallbacks.AppendElements(mFrameRequestCallbacks);
   mFrameRequestCallbacks.Clear();
 }
 
 bool
 nsIDocument::ShouldThrottleFrameRequests()
 {
+  if (mStaticCloneCount > 0) {
+    // Even if we're not visible, a static clone may be, so run at full speed.
+    return false;
+  }
+
   if (!mIsShowing) {
     // We're not showing (probably in a background tab or the bf cache).
     return true;
   }
 
   if (!mPresShell) {
     return false;  // Can't do anything smarter.
   }
@@ -10275,16 +10283,19 @@ nsIDocument::CreateStaticClone(nsIDocShe
     nsCOMPtr<nsIDocument> tmp = do_QueryInterface(clonedNode);
     if (tmp) {
       clonedDoc = static_cast<nsDocument*>(tmp.get());
       if (IsStaticDocument()) {
         clonedDoc->mOriginalDocument = mOriginalDocument;
       } else {
         clonedDoc->mOriginalDocument = this;
       }
+
+      clonedDoc->mOriginalDocument->mStaticCloneCount++;
+
       int32_t sheetsCount = GetNumberOfStyleSheets();
       for (int32_t i = 0; i < sheetsCount; ++i) {
         nsRefPtr<CSSStyleSheet> sheet = do_QueryObject(GetStyleSheetAt(i));
         if (sheet) {
           if (sheet->IsApplicable()) {
             nsRefPtr<CSSStyleSheet> clonedSheet =
               sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
             NS_WARN_IF_FALSE(clonedSheet, "Cloning a stylesheet didn't work!");
@@ -10312,16 +10323,27 @@ nsIDocument::CreateStaticClone(nsIDocShe
         }
       }
     }
   }
   mCreatingStaticClone = false;
   return clonedDoc.forget();
 }
 
+void
+nsIDocument::UnlinkOriginalDocumentIfStatic()
+{
+  if (IsStaticDocument() && mOriginalDocument) {
+    MOZ_ASSERT(mOriginalDocument->mStaticCloneCount > 0);
+    mOriginalDocument->mStaticCloneCount--;
+    mOriginalDocument = nullptr;
+  }
+  MOZ_ASSERT(!mOriginalDocument);
+}
+
 nsresult
 nsIDocument::ScheduleFrameRequestCallback(const FrameRequestCallbackHolder& aCallback,
                                           int32_t *aHandle)
 {
   if (mFrameRequestCallbackCounter == INT32_MAX) {
     // Can't increment without overflowing; bail out
     return NS_ERROR_NOT_AVAILABLE;
   }
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -1933,16 +1933,22 @@ public:
    */
   nsIDocument* GetOriginalDocument()
   {
     MOZ_ASSERT(!mOriginalDocument || !mOriginalDocument->GetOriginalDocument());
     return mOriginalDocument;
   }
 
   /**
+   * If this document is a static clone, let the original document know that
+   * we're going away and then release our reference to it.
+   */
+  void UnlinkOriginalDocumentIfStatic();
+
+  /**
    * These are called by the parser as it encounters <picture> tags, the end of
    * said tags, and possible picture <source srcset> sources respectively. These
    * are used to inform ResolvePreLoadImage() calls.  Unset attributes are
    * expected to be marked void.
    *
    * NOTE that the parser does not attempt to track the current picture nesting
    * level or whether the given <source> tag is within a picture -- it is only
    * guaranteed to order these calls properly with respect to
@@ -2856,16 +2862,19 @@ protected:
    */
   uint32_t mExternalScriptsBeingEvaluated;
 
   /**
    * The current frame request callback handle
    */
   int32_t mFrameRequestCallbackCounter;
 
+  // Count of live static clones of this document.
+  uint32_t mStaticCloneCount;
+
   // Array of nodes that have been blocked to prevent user tracking.
   // They most likely have had their nsIChannel canceled by the URL
   // classifier. (Safebrowsing)
   //
   // Weak nsINode pointers are used to allow nodes to disappear.
   nsTArray<nsWeakPtr> mBlockedTrackingNodes;
 
   // Weak reference to mScriptGlobalObject QI:d to nsPIDOMWindow,