Bug 1544546 - Un-fill the styleset and drop the cascade data when removing a pres shell. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 19 Apr 2019 04:32:12 +0000
changeset 470171 2099599a5ad519efa9e85f900d6ea51136469001
parent 470170 7b1bfcf749fd4b947b4f9202fe858c12d0bba2ee
child 470172 9bf44f82eea61a6f22a12e20ce941df0602993ba
push id112843
push useraiakab@mozilla.com
push dateFri, 19 Apr 2019 09:50:22 +0000
treeherdermozilla-inbound@c06f27cbfe40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1544546
milestone68.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 1544546 - Un-fill the styleset and drop the cascade data when removing a pres shell. r=heycam This should keep memory usage a bit more under control when loosing a pres shell. Differential Revision: https://phabricator.services.mozilla.com/D27571
dom/base/Document.cpp
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -3982,18 +3982,16 @@ bool Document::ShouldThrottleFrameReques
 }
 
 void Document::DeletePresShell() {
   mExternalResourceMap.HideViewers();
   if (nsPresContext* presContext = mPresShell->GetPresContext()) {
     presContext->RefreshDriver()->CancelPendingFullscreenEvents(this);
   }
 
-  mStyleSet->ShellDetachedFromDocument();
-
   // When our shell goes away, request that all our images be immediately
   // discarded, so we don't carry around decoded image data for a document we
   // no longer intend to paint.
   ImageTracker()->RequestDiscardAll();
 
   // Now that we no longer have a shell, we need to forget about any FontFace
   // objects for @font-face rules that came from the style set. There's no need
   // to call EnsureStyleFlush either, the shell is going away anyway, so there's
@@ -4001,16 +3999,20 @@ void Document::DeletePresShell() {
   MarkUserFontSetDirty();
 
   PresShell* oldPresShell = mPresShell;
   mPresShell = nullptr;
   UpdateFrameRequestCallbackSchedulingState(oldPresShell);
 
   ClearStaleServoData();
   AssertNoStaleServoDataIn(*this);
+
+  mStyleSet->ShellDetachedFromDocument();
+  mStyleSetFilled = false;
+  mQuirkSheetAdded = false;
 }
 
 void Document::SetBFCacheEntry(nsIBFCacheEntry* aEntry) {
   MOZ_ASSERT(IsBFCachingAllowed() || !aEntry, "You should have checked!");
 
   if (mPresShell) {
     if (aEntry) {
       mPresShell->StopObservingRefreshDriver();
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -46,16 +46,19 @@ using namespace mozilla::dom;
 
 #ifdef DEBUG
 bool ServoStyleSet::IsCurrentThreadInServoTraversal() {
   return sInServoTraversal && (NS_IsMainThread() || Servo_IsWorkerThread());
 }
 #endif
 
 namespace mozilla {
+
+constexpr const StyleOrigin ServoStyleSet::kOrigins[];
+
 ServoStyleSet* sInServoTraversal = nullptr;
 
 // On construction, sets sInServoTraversal to the given ServoStyleSet.
 // On destruction, clears sInServoTraversal and calls RunPostTraversalTasks.
 class MOZ_RAII AutoSetInServoTraversal {
  public:
   explicit AutoSetInServoTraversal(ServoStyleSet* aSet) : mSet(aSet) {
     MOZ_ASSERT(!sInServoTraversal);
@@ -112,23 +115,32 @@ void EnumerateShadowRoots(const Document
     ShadowRoot* root = iter.Get()->GetKey();
     MOZ_ASSERT(root);
     MOZ_DIAGNOSTIC_ASSERT(root->IsInComposedDoc());
     aCb(*root);
   }
 }
 
 void ServoStyleSet::ShellDetachedFromDocument() {
-  // Make sure we drop our cached styles before the presshell arena starts going
-  // away.
-  //
-  // TODO(emilio): The presshell arena comment is no longer relevant. We could
-  // avoid doing this if we wanted to.
   ClearNonInheritingComputedStyles();
   mStyleRuleMap = nullptr;
+
+  // Remove all our stylesheets...
+  for (const Origin origin : kOrigins) {
+    for (size_t count = SheetCount(origin); count--;) {
+      RemoveStyleSheet(origin, SheetAt(origin, count));
+    }
+  }
+
+  // And remove all the CascadeDatas from memory.
+  UpdateStylistIfNeeded();
+
+  // Also GC the ruletree if it got big now that the DOM no longer has
+  // references to styles around anymore.
+  MaybeGCRuleTree();
 }
 
 void ServoStyleSet::RecordShadowStyleChange(ShadowRoot& aShadowRoot) {
   // TODO(emilio): We could keep track of the actual shadow roots that need
   // their styles recomputed.
   SetStylistXBLStyleSheetsDirty();
 
   // FIXME(emilio): This should be done using stylesheet invalidation instead.
@@ -595,34 +607,27 @@ void ServoStyleSet::ReplaceSheets(
     StyleOrigin aOrigin, const nsTArray<RefPtr<StyleSheet>>& aNewSheets) {
   // Gecko uses a two-dimensional array keyed by sheet type, whereas Servo
   // stores a flattened list. This makes ReplaceSheets a pretty clunky thing
   // to express. If the need ever arises, we can easily make this more efficent,
   // probably by aligning the representations better between engines.
 
   SetStylistStyleSheetsDirty();
 
+  mStyleRuleMap = nullptr;
+
   // Remove all the existing sheets first.
   for (size_t count = SheetCount(aOrigin); count--;) {
-    StyleSheet* sheet = SheetAt(aOrigin, count);
-    sheet->DropStyleSet(this);
-    Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), sheet);
+    RemoveStyleSheet(aOrigin, SheetAt(aOrigin, count));
   }
 
   // Add in all the new sheets.
   for (auto& sheet : aNewSheets) {
-    sheet->AddStyleSet(this);
-    MOZ_ASSERT(sheet->RawContents(),
-               "Raw sheet should be in place before replacement.");
-    Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet);
+    AppendStyleSheet(aOrigin, sheet);
   }
-
-  // Just don't bother calling SheetRemoved / SheetAdded, and recreate the rule
-  // map when needed.
-  mStyleRuleMap = nullptr;
 }
 
 void ServoStyleSet::InsertStyleSheetBefore(Origin aOrigin,
                                            StyleSheet* aNewSheet,
                                            StyleSheet* aReferenceSheet) {
   MOZ_ASSERT(aNewSheet);
   MOZ_ASSERT(aReferenceSheet);
   MOZ_ASSERT(aNewSheet->IsApplicable());
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -80,16 +80,19 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Or
  */
 class ServoStyleSet {
   friend class RestyleManager;
   typedef ServoElementSnapshotTable SnapshotTable;
 
   using Origin = StyleOrigin;
 
  public:
+  static constexpr const StyleOrigin kOrigins[] = {
+      StyleOrigin::UserAgent, StyleOrigin::User, StyleOrigin::Author};
+
   static bool IsInServoTraversal() { return mozilla::IsInServoTraversal(); }
 
 #ifdef DEBUG
   // Used for debug assertions. We make this debug-only to prevent callers from
   // accidentally using it instead of IsInServoTraversal, which is cheaper. We
   // can change this if a use-case arises.
   static bool IsCurrentThreadInServoTraversal();
 #endif
@@ -289,18 +292,16 @@ class ServoStyleSet {
   /**
    * Notifies the Servo stylesheet that the document's compatibility mode has
    * changed.
    */
   void CompatibilityModeChanged();
 
   template <typename T>
   void EnumerateStyleSheets(T aCb) {
-    const StyleOrigin kOrigins[] = {StyleOrigin::UserAgent, StyleOrigin::User,
-                                    StyleOrigin::Author};
     for (auto origin : kOrigins) {
       for (size_t i = 0, count = SheetCount(origin); i < count; ++i) {
         aCb(*SheetAt(origin, i));
       }
     }
   }
 
   /**