Bug 1413833 - Cap the number of modified frames that we track to avoid the overhead getting too large. r=miko
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 08 Nov 2017 15:23:34 +1300
changeset 441498 e05d3e232865dbb2533966879f50db54daa7340e
parent 441497 891b6831d29bdfc80fc14434185bfd7c975e45dd
child 441499 8bd69298b447dc9c5cb11a77f0d14afdb8f9a990
push id8130
push userryanvm@gmail.com
push dateThu, 09 Nov 2017 00:28:20 +0000
treeherdermozilla-beta@a49a6fa54363 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmiko
bugs1413833
milestone58.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 1413833 - Cap the number of modified frames that we track to avoid the overhead getting too large. r=miko
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/nsFrame.cpp
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -7320,36 +7320,16 @@ nsLayoutUtils::GetDisplayRootFrame(nsIFr
     nsIFrame* parent = GetCrossDocParentFrame(f);
     if (!parent)
       return f;
     f = parent;
   }
 }
 
 /* static */ nsIFrame*
-nsLayoutUtils::GetViewportFrame(nsIFrame* aFrame)
-{
-  nsIFrame* f = aFrame;
-
-  for (;;) {
-    MOZ_ASSERT(f);
-    if (f->Type() == LayoutFrameType::Viewport) {
-      return f;
-    }
-
-    nsIFrame* parent = GetCrossDocParentFrame(f);
-    if (!parent) {
-      return f;
-    }
-
-    f = parent;
-  }
-}
-
-/* static */ nsIFrame*
 nsLayoutUtils::GetReferenceFrame(nsIFrame* aFrame)
 {
   nsIFrame *f = aFrame;
   for (;;) {
     const nsStyleDisplay* disp = f->StyleDisplay();
     if (f->IsTransformed(disp) || f->IsPreserve3DLeaf(disp) || IsPopup(f)) {
       return f;
     }
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2014,21 +2014,16 @@ public:
 
   /**
    * Find the nearest "display root". This is the nearest enclosing
    * popup frame or the root prescontext's root frame.
    */
   static nsIFrame* GetDisplayRootFrame(nsIFrame* aFrame);
 
   /**
-   * Find the nearest viewport frame that is an ancestor of the given frame.
-   */
-  static nsIFrame* GetViewportFrame(nsIFrame* aFrame);
-
-  /**
    * Get the reference frame that would be used when constructing a
    * display item for this frame.  Rather than using their own frame
    * as a reference frame.)
    *
    * This duplicates some of the logic of GetDisplayRootFrame above and
    * of nsDisplayListBuilder::FindReferenceFrameFor.
    *
    * If you have an nsDisplayListBuilder, you should get the reference
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -985,32 +985,53 @@ nsIFrame::MarkNeedsDisplayItemRebuild()
 
   RetainedDisplayListBuilder* retainedBuilder =
     displayRoot->GetProperty(RetainedDisplayListBuilder::Cached());
 
   if (!retainedBuilder) {
     return;
   }
 
-  nsIFrame* viewport = nsLayoutUtils::GetViewportFrame(this);
-  MOZ_ASSERT(viewport);
+  nsIFrame* rootFrame = PresContext()->PresShell()->GetRootFrame();
+  MOZ_ASSERT(rootFrame);
+
+  if (rootFrame->IsFrameModified()) {
+    return;
+  }
 
   std::vector<WeakFrame>* modifiedFrames =
-    viewport->GetProperty(nsIFrame::ModifiedFrameList());
+    rootFrame->GetProperty(nsIFrame::ModifiedFrameList());
 
   if (!modifiedFrames) {
     modifiedFrames = new std::vector<WeakFrame>();
-    viewport->SetProperty(nsIFrame::ModifiedFrameList(), modifiedFrames);
+    rootFrame->SetProperty(nsIFrame::ModifiedFrameList(), modifiedFrames);
+  }
+
+  if (this == rootFrame) {
+    // If this is the root frame, then marking us as needing a display
+    // item rebuild implies the same for all our descendents. Clear them
+    // all out to reduce the number of WeakFrames we keep around.
+    for (nsIFrame* f : *modifiedFrames) {
+      if (f) {
+        f->SetFrameIsModified(false);
+      }
+    }
+    modifiedFrames->clear();
+  } else if (modifiedFrames->size() > gfxPrefs::LayoutRebuildFrameLimit()) {
+    // If the list starts getting too big, then just mark the root frame
+    // as needing a rebuild.
+    rootFrame->MarkNeedsDisplayItemRebuild();
+    return;
   }
 
   modifiedFrames->emplace_back(this);
 
   // TODO: this is a bit of a hack. We are using ModifiedFrameList property to
   // decide whether we are trying to reuse the display list.
-  if (displayRoot != viewport &&
+  if (displayRoot != rootFrame &&
       !displayRoot->HasProperty(nsIFrame::ModifiedFrameList())) {
     displayRoot->SetProperty(nsIFrame::ModifiedFrameList(),
                              new std::vector<WeakFrame>());
   }
 
   MOZ_ASSERT(PresContext()->LayoutPhaseCount(eLayoutPhase_DisplayListBuilding) == 0);
   SetFrameIsModified(true);