Bug 1472065 - Initialize mSheet and mParentRule in css::Rule's constructor. r=xidorn
authorCameron McCormack <cam@mcc.id.au>
Fri, 29 Jun 2018 12:56:09 +1000
changeset 479693 8fb94a730b6c42d4dd0c9c76a2b2d697bb4b6025
parent 479692 8c7b5e66c06cb8e5196909d1c421628b0ee3fc26
child 479715 9c02d2ecf22050bfee5d70c04a359d8aaff6eb91
child 479716 e0c1a76aca4f77227d35e2d53faa587de279fb6e
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersxidorn
bugs1472065
milestone63.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 1472065 - Initialize mSheet and mParentRule in css::Rule's constructor. r=xidorn MozReview-Commit-ID: JI3cMiJaH3x
layout/inspector/InspectorFontFace.cpp
layout/style/BindingStyleRule.h
layout/style/CSSCounterStyleRule.h
layout/style/CSSFontFaceRule.h
layout/style/CSSFontFeatureValuesRule.cpp
layout/style/CSSFontFeatureValuesRule.h
layout/style/CSSImportRule.cpp
layout/style/CSSImportRule.h
layout/style/CSSKeyframeRule.cpp
layout/style/CSSKeyframeRule.h
layout/style/CSSKeyframesRule.cpp
layout/style/CSSKeyframesRule.h
layout/style/CSSMediaRule.cpp
layout/style/CSSMediaRule.h
layout/style/CSSMozDocumentRule.cpp
layout/style/CSSMozDocumentRule.h
layout/style/CSSNamespaceRule.h
layout/style/CSSPageRule.cpp
layout/style/CSSPageRule.h
layout/style/CSSStyleRule.cpp
layout/style/CSSStyleRule.h
layout/style/CSSSupportsRule.cpp
layout/style/CSSSupportsRule.h
layout/style/GroupRule.cpp
layout/style/GroupRule.h
layout/style/Rule.cpp
layout/style/Rule.h
layout/style/ServoCSSRuleList.cpp
layout/style/ServoCSSRuleList.h
layout/style/StyleSheet.cpp
--- a/layout/inspector/InspectorFontFace.cpp
+++ b/layout/inspector/InspectorFontFace.cpp
@@ -89,17 +89,18 @@ InspectorFontFace::GetRule()
     if (rule) {
       // XXX It would be better if we can share this with CSSOM tree,
       // but that may require us to create another map, which is not
       // great either. As far as they would use the same backend, and
       // we don't really support mutating @font-face rule via CSSOM,
       // it's probably fine for now.
       uint32_t line, column;
       Servo_FontFaceRule_GetSourceLocation(rule, &line, &column);
-      mRule = new CSSFontFaceRule(do_AddRef(rule), line, column);
+      mRule = new CSSFontFaceRule(do_AddRef(rule), nullptr, nullptr,
+                                  line, column);
     }
   }
   return mRule;
 }
 
 int32_t
 InspectorFontFace::SrcIndex()
 {
--- a/layout/style/BindingStyleRule.h
+++ b/layout/style/BindingStyleRule.h
@@ -23,18 +23,21 @@ namespace mozilla {
 class DeclarationBlock;
 namespace dom {
 class Element;
 }
 
 class BindingStyleRule : public css::Rule
 {
 protected:
-  BindingStyleRule(uint32_t aLineNumber, uint32_t aColumnNumber)
-    : css::Rule(aLineNumber, aColumnNumber)
+  BindingStyleRule(StyleSheet* aSheet,
+                   css::Rule* aParentRule,
+                   uint32_t aLineNumber,
+                   uint32_t aColumnNumber)
+    : css::Rule(aSheet, aParentRule, aLineNumber, aColumnNumber)
   {
   }
   BindingStyleRule(const BindingStyleRule& aCopy)
     : css::Rule(aCopy)
   {
   }
   virtual ~BindingStyleRule() {}
 
--- a/layout/style/CSSCounterStyleRule.h
+++ b/layout/style/CSSCounterStyleRule.h
@@ -14,18 +14,21 @@ struct RawServoCounterStyleRule;
 
 namespace mozilla {
 namespace dom {
 
 class CSSCounterStyleRule final : public css::Rule
 {
 public:
   CSSCounterStyleRule(already_AddRefed<RawServoCounterStyleRule> aRawRule,
-                      uint32_t aLine, uint32_t aColumn)
-    : mozilla::css::Rule(aLine, aColumn)
+                      StyleSheet* aSheet,
+                      css::Rule* aParentRule,
+                      uint32_t aLine,
+                      uint32_t aColumn)
+    : css::Rule(aSheet, aParentRule, aLine, aColumn)
     , mRawRule(std::move(aRawRule))
   {
   }
 
 private:
   CSSCounterStyleRule(const CSSCounterStyleRule& aCopy) = delete;
   ~CSSCounterStyleRule() = default;
 
--- a/layout/style/CSSFontFaceRule.h
+++ b/layout/style/CSSFontFaceRule.h
@@ -47,18 +47,21 @@ protected:
 private:
   void* operator new(size_t size) CPP_THROW_NEW = delete;
 };
 
 class CSSFontFaceRule final : public css::Rule
 {
 public:
   CSSFontFaceRule(already_AddRefed<RawServoFontFaceRule> aRawRule,
-                    uint32_t aLine, uint32_t aColumn)
-    : css::Rule(aLine, aColumn)
+                  StyleSheet* aSheet,
+                  css::Rule* aParentRule,
+                  uint32_t aLine,
+                  uint32_t aColumn)
+    : css::Rule(aSheet, aParentRule, aLine, aColumn)
     , mDecl(std::move(aRawRule))
   {}
 
   CSSFontFaceRule(const CSSFontFaceRule&) = delete;
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
       CSSFontFaceRule, css::Rule)
--- a/layout/style/CSSFontFeatureValuesRule.cpp
+++ b/layout/style/CSSFontFeatureValuesRule.cpp
@@ -5,24 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/CSSFontFeatureValuesRule.h"
 #include "mozilla/dom/CSSFontFeatureValuesRuleBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-CSSFontFeatureValuesRule::CSSFontFeatureValuesRule(
-  RefPtr<RawServoFontFeatureValuesRule> aRawRule,
-  uint32_t aLine, uint32_t aColumn)
-  : Rule(aLine, aColumn)
-  , mRawRule(std::move(aRawRule))
-{
-}
-
 size_t
 CSSFontFeatureValuesRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   // TODO Implement this!
   return aMallocSizeOf(this);
 }
 
 #ifdef DEBUG
--- a/layout/style/CSSFontFeatureValuesRule.h
+++ b/layout/style/CSSFontFeatureValuesRule.h
@@ -14,17 +14,24 @@
 
 namespace mozilla {
 namespace dom {
 
 class CSSFontFeatureValuesRule final : public css::Rule
 {
 public:
   CSSFontFeatureValuesRule(RefPtr<RawServoFontFeatureValuesRule> aRawRule,
-                           uint32_t aLine, uint32_t aColumn);
+                           StyleSheet* aSheet,
+                           css::Rule* aParentRule,
+                           uint32_t aLine,
+                           uint32_t aColumn)
+    : css::Rule(aSheet, aParentRule, aLine, aColumn)
+    , mRawRule(std::move(aRawRule))
+  {
+  }
 
   virtual bool IsCCLeaf() const override;
 
   RawServoFontFeatureValuesRule* Raw() const { return mRawRule; }
 
   // WebIDL interfaces
   uint16_t Type() const final { return CSSRule_Binding::FONT_FEATURE_VALUES_RULE; }
   void GetCssText(nsAString& aCssText) const override;
--- a/layout/style/CSSImportRule.cpp
+++ b/layout/style/CSSImportRule.cpp
@@ -10,19 +10,21 @@
 #include "mozilla/dom/MediaList.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/StyleSheet.h"
 
 namespace mozilla {
 namespace dom {
 
 CSSImportRule::CSSImportRule(RefPtr<RawServoImportRule> aRawRule,
+                             StyleSheet* aSheet,
+                             css::Rule* aParentRule,
                              uint32_t aLine,
                              uint32_t aColumn)
-  : Rule(aLine, aColumn)
+  : css::Rule(aSheet, aParentRule, aLine, aColumn)
   , mRawRule(std::move(aRawRule))
 {
   const auto* sheet = Servo_ImportRule_GetSheet(mRawRule.get());
   MOZ_ASSERT(sheet);
   mChildSheet = const_cast<StyleSheet*>(sheet);
   mChildSheet->SetOwnerRule(this);
 }
 
--- a/layout/style/CSSImportRule.h
+++ b/layout/style/CSSImportRule.h
@@ -14,17 +14,20 @@ namespace mozilla {
 class StyleSheet;
 
 namespace dom {
 
 class CSSImportRule final : public css::Rule
 {
 public:
   CSSImportRule(RefPtr<RawServoImportRule> aRawRule,
-                uint32_t aLine, uint32_t aColumn);
+                StyleSheet* aSheet,
+                css::Rule* aParentRule,
+                uint32_t aLine,
+                uint32_t aColumn);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSImportRule, css::Rule)
 
   bool IsCCLeaf() const final;
 
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const final;
--- a/layout/style/CSSKeyframeRule.cpp
+++ b/layout/style/CSSKeyframeRule.cpp
@@ -96,19 +96,24 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
 
 // -------------------------------------------
 // CSSKeyframeRule
 //
 
 CSSKeyframeRule::CSSKeyframeRule(already_AddRefed<RawServoKeyframe> aRaw,
-                                 uint32_t aLine, uint32_t aColumn)
-    : css::Rule(aLine, aColumn)
-    , mRaw(aRaw) {}
+                                 StyleSheet* aSheet,
+                                 css::Rule* aParentRule,
+                                 uint32_t aLine,
+                                 uint32_t aColumn)
+  : css::Rule(aSheet, aParentRule, aLine, aColumn)
+  , mRaw(aRaw)
+{
+}
 
 CSSKeyframeRule::~CSSKeyframeRule()
 {
   if (mDeclaration) {
     mDeclaration->DropReference();
   }
 }
 
--- a/layout/style/CSSKeyframeRule.h
+++ b/layout/style/CSSKeyframeRule.h
@@ -17,17 +17,20 @@ namespace mozilla {
 namespace dom {
 
 class CSSKeyframeDeclaration;
 
 class CSSKeyframeRule final : public css::Rule
 {
 public:
   CSSKeyframeRule(already_AddRefed<RawServoKeyframe> aRaw,
-                  uint32_t aLine, uint32_t aColumn);
+                  StyleSheet* aSheet,
+                  css::Rule* aParentRule,
+                  uint32_t aLine,
+                  uint32_t aColumn);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSKeyframeRule,
                                            css::Rule)
   bool IsCCLeaf() const final;
 
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const final;
--- a/layout/style/CSSKeyframesRule.cpp
+++ b/layout/style/CSSKeyframesRule.cpp
@@ -17,57 +17,54 @@ namespace dom {
 
 // -------------------------------------------
 // CSSKeyframeList
 //
 
 class CSSKeyframeList : public dom::CSSRuleList
 {
 public:
-  explicit CSSKeyframeList(already_AddRefed<RawServoKeyframesRule> aRawRule)
-    : mRawRule(aRawRule)
+  CSSKeyframeList(already_AddRefed<RawServoKeyframesRule> aRawRule,
+                  StyleSheet* aSheet,
+                  CSSKeyframesRule* aParentRule)
+    : mStyleSheet(aSheet)
+    , mParentRule(aParentRule)
+    , mRawRule(aRawRule)
   {
     mRules.SetCount(Servo_KeyframesRule_GetCount(mRawRule));
   }
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSKeyframeList, dom::CSSRuleList)
 
-  void SetParentRule(CSSKeyframesRule* aParentRule)
+  void DropSheetReference()
   {
-    mParentRule = aParentRule;
+    if (!mStyleSheet) {
+      return;
+    }
+    mStyleSheet = nullptr;
     for (css::Rule* rule : mRules) {
       if (rule) {
-        rule->SetParentRule(aParentRule);
-      }
-    }
-  }
-  void SetStyleSheet(StyleSheet* aSheet)
-  {
-    mStyleSheet = aSheet;
-    for (css::Rule* rule : mRules) {
-      if (rule) {
-        rule->SetStyleSheet(aSheet);
+        rule->DropSheetReference();
       }
     }
   }
 
   StyleSheet* GetParentObject() final { return mStyleSheet; }
 
   CSSKeyframeRule* GetRule(uint32_t aIndex) {
     if (!mRules[aIndex]) {
       uint32_t line = 0, column = 0;
       RefPtr<RawServoKeyframe> rule =
         Servo_KeyframesRule_GetKeyframeAt(mRawRule, aIndex,
                                           &line, &column).Consume();
       CSSKeyframeRule* ruleObj =
-        new CSSKeyframeRule(rule.forget(), line, column);
+        new CSSKeyframeRule(rule.forget(), mStyleSheet, mParentRule,
+                            line, column);
       mRules.ReplaceObjectAt(ruleObj, aIndex);
-      ruleObj->SetStyleSheet(mStyleSheet);
-      ruleObj->SetParentRule(mParentRule);
     }
     return static_cast<CSSKeyframeRule*>(mRules[aIndex]);
   }
 
   CSSKeyframeRule* IndexedGetter(uint32_t aIndex, bool& aFound) final
   {
     if (aIndex >= mRules.Length()) {
       aFound = false;
@@ -82,24 +79,27 @@ public:
   }
 
   void RemoveRule(uint32_t aIndex) {
     mRules.RemoveObjectAt(aIndex);
   }
 
   uint32_t Length() final { return mRules.Length(); }
 
-  void DropReference()
+  void DropReferences()
   {
+    if (!mStyleSheet && !mParentRule) {
+      return;
+    }
     mStyleSheet = nullptr;
     mParentRule = nullptr;
     for (css::Rule* rule : mRules) {
       if (rule) {
-        rule->SetStyleSheet(nullptr);
-        rule->SetParentRule(nullptr);
+        rule->DropParentRuleReference();
+        rule->DropSheetReference();
       }
     }
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   {
     size_t n = aMallocSizeOf(this);
     for (const css::Rule* rule : mRules) {
@@ -112,19 +112,17 @@ private:
   virtual ~CSSKeyframeList() {
     MOZ_ASSERT(!mParentRule, "Backpointer should have been cleared");
     MOZ_ASSERT(!mStyleSheet, "Backpointer should have been cleared");
     DropAllRules();
   }
 
   void DropAllRules()
   {
-    if (mParentRule || mStyleSheet) {
-      DropReference();
-    }
+    DropReferences();
     mRules.Clear();
     mRawRule = nullptr;
   }
 
   // may be nullptr when the style sheet drops the reference to us.
   StyleSheet* mStyleSheet = nullptr;
   CSSKeyframesRule* mParentRule = nullptr;
   RefPtr<RawServoKeyframesRule> mRawRule;
@@ -153,41 +151,44 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 // -------------------------------------------
 // CSSKeyframesRule
 //
 
 CSSKeyframesRule::CSSKeyframesRule(RefPtr<RawServoKeyframesRule> aRawRule,
-                                   uint32_t aLine, uint32_t aColumn)
-  : css::Rule(aLine, aColumn)
+                                   StyleSheet* aSheet,
+                                   css::Rule* aParentRule,
+                                   uint32_t aLine,
+                                   uint32_t aColumn)
+  : css::Rule(aSheet, aParentRule, aLine, aColumn)
   , mRawRule(std::move(aRawRule))
 {
 }
 
 CSSKeyframesRule::~CSSKeyframesRule()
 {
   if (mKeyframeList) {
-    mKeyframeList->DropReference();
+    mKeyframeList->DropReferences();
   }
 }
 
 NS_IMPL_ADDREF_INHERITED(CSSKeyframesRule, css::Rule)
 NS_IMPL_RELEASE_INHERITED(CSSKeyframesRule, css::Rule)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSKeyframesRule)
 NS_INTERFACE_MAP_END_INHERITING(css::Rule)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(CSSKeyframesRule)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(CSSKeyframesRule,
                                                 css::Rule)
   if (tmp->mKeyframeList) {
-    tmp->mKeyframeList->DropReference();
+    tmp->mKeyframeList->DropReferences();
     tmp->mKeyframeList = nullptr;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSKeyframesRule, Rule)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mKeyframeList)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
@@ -207,22 +208,22 @@ CSSKeyframesRule::List(FILE* out, int32_
     str.AppendLiteral("  ");
   }
   Servo_KeyframesRule_Debug(mRawRule, &str);
   fprintf_stderr(out, "%s\n", str.get());
 }
 #endif
 
 /* virtual */ void
-CSSKeyframesRule::SetStyleSheet(StyleSheet* aSheet)
+CSSKeyframesRule::DropSheetReference()
 {
   if (mKeyframeList) {
-    mKeyframeList->SetStyleSheet(aSheet);
+    mKeyframeList->DropSheetReference();
   }
-  css::Rule::SetStyleSheet(aSheet);
+  css::Rule::DropSheetReference();
 }
 
 static const uint32_t kRuleNotFound = std::numeric_limits<uint32_t>::max();
 
 uint32_t
 CSSKeyframesRule::FindRuleIndexForKey(const nsAString& aKey)
 {
   NS_ConvertUTF16toUTF8 key(aKey);
@@ -300,21 +301,17 @@ CSSKeyframesRule::GetCssText(nsAString& 
 {
   Servo_KeyframesRule_GetCssText(mRawRule, &aCssText);
 }
 
 /* virtual */ dom::CSSRuleList*
 CSSKeyframesRule::CssRules()
 {
   if (!mKeyframeList) {
-    mKeyframeList = new CSSKeyframeList(do_AddRef(mRawRule));
-    mKeyframeList->SetParentRule(this);
-    if (StyleSheet* sheet = GetStyleSheet()) {
-      mKeyframeList->SetStyleSheet(sheet);
-    }
+    mKeyframeList = new CSSKeyframeList(do_AddRef(mRawRule), mSheet, this);
   }
   return mKeyframeList;
 }
 
 /* virtual */ dom::CSSKeyframeRule*
 CSSKeyframesRule::FindRule(const nsAString& aKey)
 {
   auto index = FindRuleIndexForKey(aKey);
--- a/layout/style/CSSKeyframesRule.h
+++ b/layout/style/CSSKeyframesRule.h
@@ -14,29 +14,32 @@ namespace mozilla {
 namespace dom {
 
 class CSSKeyframeList;
 
 class CSSKeyframesRule final : public css::Rule
 {
 public:
   CSSKeyframesRule(RefPtr<RawServoKeyframesRule> aRawRule,
-                   uint32_t aLine, uint32_t aColumn);
+                   StyleSheet* aSheet,
+                   css::Rule* aParentRule,
+                   uint32_t aLine,
+                   uint32_t aColumn);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSKeyframesRule,
                                            css::Rule)
 
   bool IsCCLeaf() const final;
 
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const final;
 #endif
 
-  void SetStyleSheet(StyleSheet* aSheet) final;
+  void DropSheetReference() final;
 
   // WebIDL interface
   uint16_t Type() const final { return CSSRule_Binding::KEYFRAMES_RULE; }
   void GetCssText(nsAString& aCssText) const final;
   void GetName(nsAString& aName) const;
   void SetName(const nsAString& aName);
   CSSRuleList* CssRules();
   void AppendRule(const nsAString& aRule);
--- a/layout/style/CSSMediaRule.cpp
+++ b/layout/style/CSSMediaRule.cpp
@@ -8,18 +8,22 @@
 
 #include "mozilla/dom/CSSMediaRuleBinding.h"
 #include "mozilla/dom/MediaList.h"
 
 namespace mozilla {
 namespace dom {
 
 CSSMediaRule::CSSMediaRule(RefPtr<RawServoMediaRule> aRawRule,
-                           uint32_t aLine, uint32_t aColumn)
-  : ConditionRule(Servo_MediaRule_GetRules(aRawRule).Consume(), aLine, aColumn)
+                           StyleSheet* aSheet,
+                           css::Rule* aParentRule,
+                           uint32_t aLine,
+                           uint32_t aColumn)
+  : ConditionRule(Servo_MediaRule_GetRules(aRawRule).Consume(),
+                  aSheet, aParentRule, aLine, aColumn)
   , mRawRule(std::move(aRawRule))
 {
 }
 
 CSSMediaRule::~CSSMediaRule()
 {
   if (mMediaList) {
     mMediaList->SetStyleSheet(nullptr);
@@ -42,22 +46,22 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSMediaRule, css::ConditionRule)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaList)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 /* virtual */ void
-CSSMediaRule::SetStyleSheet(StyleSheet* aSheet)
+CSSMediaRule::DropSheetReference()
 {
   if (mMediaList) {
-    mMediaList->SetStyleSheet(aSheet);
+    mMediaList->SetStyleSheet(nullptr);
   }
-  ConditionRule::SetStyleSheet(aSheet);
+  ConditionRule::DropSheetReference();
 }
 
 #ifdef DEBUG
 /* virtual */ void
 CSSMediaRule::List(FILE* out, int32_t aIndent) const
 {
   nsAutoCString str;
   for (int32_t i = 0; i < aIndent; i++) {
--- a/layout/style/CSSMediaRule.h
+++ b/layout/style/CSSMediaRule.h
@@ -12,22 +12,25 @@
 
 namespace mozilla {
 namespace dom {
 
 class CSSMediaRule final : public css::ConditionRule
 {
 public:
   CSSMediaRule(RefPtr<RawServoMediaRule> aRawRule,
-               uint32_t aLine, uint32_t aColumn);
+               StyleSheet* aSheet,
+               css::Rule* aParentRule,
+               uint32_t aLine,
+               uint32_t aColumn);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSMediaRule, css::ConditionRule)
 
-  void SetStyleSheet(StyleSheet* aSheet) override;
+  void DropSheetReference() override;
 
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const final;
 #endif
 
   RawServoMediaRule* Raw() const { return mRawRule; }
 
   // WebIDL interface
--- a/layout/style/CSSMozDocumentRule.cpp
+++ b/layout/style/CSSMozDocumentRule.cpp
@@ -63,19 +63,22 @@ CSSMozDocumentRule::Match(nsIDocument* a
       }
     } break;
   }
 
   return false;
 }
 
 CSSMozDocumentRule::CSSMozDocumentRule(RefPtr<RawServoMozDocumentRule> aRawRule,
-                                       uint32_t aLine, uint32_t aColumn)
+                                       StyleSheet* aSheet,
+                                       css::Rule* aParentRule,
+                                       uint32_t aLine,
+                                       uint32_t aColumn)
   : css::ConditionRule(Servo_MozDocumentRule_GetRules(aRawRule).Consume(),
-                       aLine, aColumn)
+                       aSheet, aParentRule, aLine, aColumn)
   , mRawRule(std::move(aRawRule))
 {
 }
 
 NS_IMPL_ADDREF_INHERITED(CSSMozDocumentRule, css::ConditionRule)
 NS_IMPL_RELEASE_INHERITED(CSSMozDocumentRule, css::ConditionRule)
 
 // QueryInterface implementation for MozDocumentRule
--- a/layout/style/CSSMozDocumentRule.h
+++ b/layout/style/CSSMozDocumentRule.h
@@ -13,17 +13,20 @@
 
 namespace mozilla {
 namespace dom {
 
 class CSSMozDocumentRule final : public css::ConditionRule
 {
 public:
   CSSMozDocumentRule(RefPtr<RawServoMozDocumentRule> aRawRule,
-                     uint32_t aLine, uint32_t aColumn);
+                     StyleSheet* aSheet,
+                     css::Rule* aParentRule,
+                     uint32_t aLine,
+                     uint32_t aColumn);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   static bool Match(nsIDocument* aDoc,
                     nsIURI* aDocURI,
                     const nsACString& aDocURISpec,
                     const nsACString& aPattern,
                     css::URLMatchingFunction aUrlMatchingFunction);
--- a/layout/style/CSSNamespaceRule.h
+++ b/layout/style/CSSNamespaceRule.h
@@ -15,18 +15,21 @@ class nsAtom;
 
 namespace mozilla {
 namespace dom {
 
 class CSSNamespaceRule final : public css::Rule
 {
 public:
   CSSNamespaceRule(already_AddRefed<RawServoNamespaceRule> aRule,
-                   uint32_t aLine, uint32_t aColumn)
-    : css::Rule(aLine, aColumn)
+                   StyleSheet* aSheet,
+                   css::Rule* aParentRule,
+                   uint32_t aLine,
+                   uint32_t aColumn)
+    : css::Rule(aSheet, aParentRule, aLine, aColumn)
     , mRawRule(std::move(aRule))
   {
   }
 
   bool IsCCLeaf() const final {
     return Rule::IsCCLeaf();
   }
 
--- a/layout/style/CSSPageRule.cpp
+++ b/layout/style/CSSPageRule.cpp
@@ -91,18 +91,21 @@ CSSPageRuleDeclaration::GetParsingEnviro
   nsIPrincipal* aSubjectPrincipal) const
 {
   return GetParsingEnvironmentForRule(Rule());
 }
 
 // -- CSSPageRule --------------------------------------------------
 
 CSSPageRule::CSSPageRule(RefPtr<RawServoPageRule> aRawRule,
-                         uint32_t aLine, uint32_t aColumn)
-  : Rule(aLine, aColumn)
+                         StyleSheet* aSheet,
+                         css::Rule* aParentRule,
+                         uint32_t aLine,
+                         uint32_t aColumn)
+  : css::Rule(aSheet, aParentRule, aLine, aColumn)
   , mRawRule(std::move(aRawRule))
   , mDecls(Servo_PageRule_GetStyle(mRawRule).Consume())
 {
 }
 
 NS_IMPL_ADDREF_INHERITED(CSSPageRule, css::Rule)
 NS_IMPL_RELEASE_INHERITED(CSSPageRule, css::Rule)
 
--- a/layout/style/CSSPageRule.h
+++ b/layout/style/CSSPageRule.h
@@ -50,17 +50,20 @@ private:
 
   RefPtr<DeclarationBlock> mDecls;
 };
 
 class CSSPageRule final : public css::Rule
 {
 public:
   CSSPageRule(RefPtr<RawServoPageRule> aRawRule,
-                uint32_t aLine, uint32_t aColumn);
+              StyleSheet* aSheet,
+              css::Rule* aParentRule,
+              uint32_t aLine,
+              uint32_t aColumn);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
     CSSPageRule, css::Rule
   )
 
   bool IsCCLeaf() const final;
 
--- a/layout/style/CSSStyleRule.cpp
+++ b/layout/style/CSSStyleRule.cpp
@@ -95,18 +95,21 @@ CSSStyleRuleDeclaration::GetParsingEnvir
   nsIPrincipal* aSubjectPrincipal) const
 {
   return GetParsingEnvironmentForRule(Rule());
 }
 
 // -- CSSStyleRule --------------------------------------------------
 
 CSSStyleRule::CSSStyleRule(already_AddRefed<RawServoStyleRule> aRawRule,
-                               uint32_t aLine, uint32_t aColumn)
-  : BindingStyleRule(aLine, aColumn)
+                           StyleSheet* aSheet,
+                           css::Rule* aParentRule,
+                           uint32_t aLine,
+                           uint32_t aColumn)
+  : BindingStyleRule(aSheet, aParentRule, aLine, aColumn)
   , mRawRule(aRawRule)
   , mDecls(Servo_StyleRule_GetStyle(mRawRule).Consume())
 {
 }
 
 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(CSSStyleRule, css::Rule)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(CSSStyleRule)
--- a/layout/style/CSSStyleRule.h
+++ b/layout/style/CSSStyleRule.h
@@ -48,21 +48,24 @@ private:
 
   inline CSSStyleRule* Rule();
   inline const CSSStyleRule* Rule() const;
 
   RefPtr<DeclarationBlock> mDecls;
 };
 
 class CSSStyleRule final : public BindingStyleRule
-                           , public SupportsWeakPtr<CSSStyleRule>
+                         , public SupportsWeakPtr<CSSStyleRule>
 {
 public:
   CSSStyleRule(already_AddRefed<RawServoStyleRule> aRawRule,
-                 uint32_t aLine, uint32_t aColumn);
+               StyleSheet* aSheet,
+               css::Rule* aParentRule,
+               uint32_t aLine,
+               uint32_t aColumn);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(CSSStyleRule,
                                                          css::Rule)
   bool IsCCLeaf() const final MOZ_MUST_OVERRIDE;
 
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(CSSStyleRule)
 
--- a/layout/style/CSSSupportsRule.cpp
+++ b/layout/style/CSSSupportsRule.cpp
@@ -11,19 +11,22 @@
 #include "mozilla/ServoBindings.h"
 
 using namespace mozilla::css;
 
 namespace mozilla {
 namespace dom {
 
 CSSSupportsRule::CSSSupportsRule(RefPtr<RawServoSupportsRule> aRawRule,
-                                 uint32_t aLine, uint32_t aColumn)
+                                 StyleSheet* aSheet,
+                                 css::Rule* aParentRule,
+                                 uint32_t aLine,
+                                 uint32_t aColumn)
   : css::ConditionRule(Servo_SupportsRule_GetRules(aRawRule).Consume(),
-                       aLine, aColumn)
+                       aSheet, aParentRule, aLine, aColumn)
   , mRawRule(std::move(aRawRule))
 {
 }
 
 NS_IMPL_ADDREF_INHERITED(CSSSupportsRule, ConditionRule)
 NS_IMPL_RELEASE_INHERITED(CSSSupportsRule, ConditionRule)
 
 // QueryInterface implementation for SupportsRule
--- a/layout/style/CSSSupportsRule.h
+++ b/layout/style/CSSSupportsRule.h
@@ -12,17 +12,20 @@
 
 namespace mozilla {
 namespace dom {
 
 class CSSSupportsRule : public css::ConditionRule
 {
 public:
   CSSSupportsRule(RefPtr<RawServoSupportsRule> aRawRule,
-                  uint32_t aLine, uint32_t aColumn);
+                  StyleSheet* aSheet,
+                  css::Rule* aParentRule,
+                  uint32_t aLine,
+                  uint32_t aColumn);
 
   NS_DECL_ISUPPORTS_INHERITED
 
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const final;
 #endif
 
   RawServoSupportsRule* Raw() const { return mRawRule; }
--- a/layout/style/GroupRule.cpp
+++ b/layout/style/GroupRule.cpp
@@ -14,28 +14,30 @@
 #include "mozilla/dom/CSSRuleList.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 namespace css {
 
 GroupRule::GroupRule(already_AddRefed<ServoCssRules> aRules,
-                     uint32_t aLineNumber, uint32_t aColumnNumber)
-  : Rule(aLineNumber, aColumnNumber)
-  , mRuleList(new ServoCSSRuleList(std::move(aRules), nullptr))
+                     StyleSheet* aSheet,
+                     Rule* aParentRule,
+                     uint32_t aLineNumber,
+                     uint32_t aColumnNumber)
+  : Rule(aSheet, aParentRule, aLineNumber, aColumnNumber)
+  , mRuleList(new ServoCSSRuleList(std::move(aRules), aSheet, this))
 {
-  mRuleList->SetParentRule(this);
 }
 
 GroupRule::~GroupRule()
 {
   MOZ_ASSERT(!mSheet, "SetStyleSheet should have been called");
   if (mRuleList) {
-    mRuleList->DropReference();
+    mRuleList->DropReferences();
   }
 }
 
 NS_IMPL_ADDREF_INHERITED(GroupRule, Rule)
 NS_IMPL_RELEASE_INHERITED(GroupRule, Rule)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GroupRule)
 NS_INTERFACE_MAP_END_INHERITING(Rule)
@@ -46,27 +48,20 @@ GroupRule::IsCCLeaf() const
   // Let's not worry for now about sorting out whether we're a leaf or not.
   return false;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(GroupRule)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(GroupRule, Rule)
   if (tmp->mRuleList) {
-    tmp->mRuleList->SetParentRule(nullptr);
-    // If tmp does not have a stylesheet, neither do its descendants.
-    // In that case, don't try to null out their stylesheet, to avoid
-    // O(N^2) behavior in depth of group rule nesting.  But if tmp
-    // _does_ have a stylesheet (which can happen if it gets unlinked
-    // earlier than its owning stylesheet), then we need to null out the
-    // stylesheet pointer on descendants now, before we clear mRuleList.
-    if (tmp->GetStyleSheet()) {
-      tmp->mRuleList->SetStyleSheet(nullptr);
-    }
-    tmp->mRuleList->DropReference();
+    // If tmp has a style sheet (which can happen if it gets unlinked
+    // earlier than its owning style sheet), then we need to null out the
+    // style sheet pointer on descendants now, before we clear mRuleList.
+    tmp->mRuleList->DropReferences();
     tmp->mRuleList = nullptr;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(GroupRule, Rule)
   ImplCycleCollectionTraverse(cb, tmp->mRuleList, "mRuleList");
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
@@ -74,28 +69,22 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 void
 GroupRule::List(FILE* out, int32_t aIndent) const
 {
   // TODO list something reasonable?
 }
 #endif
 
 /* virtual */ void
-GroupRule::SetStyleSheet(StyleSheet* aSheet)
+GroupRule::DropSheetReference()
 {
-  // Don't set the sheet on the kids if it's already the same as the sheet we
-  // already have.  This is needed to avoid O(N^2) behavior in group nesting
-  // depth when seting the sheet to null during unlink, if we happen to unlin in
-  // order from most nested rule up to least nested rule.
-  if (aSheet != GetStyleSheet()) {
-    if (mRuleList) {
-      mRuleList->SetStyleSheet(aSheet);
-    }
-    Rule::SetStyleSheet(aSheet);
+  if (mRuleList) {
+    mRuleList->DropSheetReference();
   }
+  Rule::DropSheetReference();
 }
 
 uint32_t
 GroupRule::InsertRule(const nsAString& aRule, uint32_t aIndex, ErrorResult& aRv)
 {
   StyleSheet* sheet = GetStyleSheet();
   if (NS_WARN_IF(!sheet)) {
     aRv.Throw(NS_ERROR_FAILURE);
--- a/layout/style/GroupRule.h
+++ b/layout/style/GroupRule.h
@@ -30,29 +30,32 @@ class CSSRuleList;
 namespace css {
 
 // inherits from Rule so it can be shared between
 // MediaRule and DocumentRule
 class GroupRule : public Rule
 {
 protected:
   GroupRule(already_AddRefed<ServoCssRules> aRules,
-            uint32_t aLineNumber, uint32_t aColumnNumber);
+            StyleSheet* aSheet,
+            Rule* aParentRule,
+            uint32_t aLineNumber,
+            uint32_t aColumnNumber);
   GroupRule(const GroupRule& aCopy) = delete;
   virtual ~GroupRule();
 public:
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(GroupRule, Rule)
   NS_DECL_ISUPPORTS_INHERITED
   virtual bool IsCCLeaf() const override;
 
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
-  virtual void SetStyleSheet(StyleSheet* aSheet) override;
+  void DropSheetReference() override;
 
 public:
 
   int32_t StyleRuleCount() const { return mRuleList->Length(); }
 
   Rule* GetStyleRuleAt(int32_t aIndex) const {
     return mRuleList->GetRule(aIndex);
   }
--- a/layout/style/Rule.cpp
+++ b/layout/style/Rule.cpp
@@ -68,22 +68,19 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_
     (tmp->IsKnownLive() && tmp->HasNothingToTrace(tmp));
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(Rule)
   return tmp->IsCCLeaf() || tmp->IsKnownLive();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
 /* virtual */ void
-Rule::SetStyleSheet(StyleSheet* aSheet)
+Rule::DropSheetReference()
 {
-  // We don't reference count this up reference. The style sheet
-  // will tell us when it's going away or when we're detached from
-  // it.
-  mSheet = aSheet;
+  mSheet = nullptr;
 }
 
 void
 Rule::SetCssText(const nsAString& aCssText)
 {
   // We used to throw for some rule types, but not all.  Specifically, we did
   // not throw for StyleRule.  Let's just always not throw.
 }
--- a/layout/style/Rule.h
+++ b/layout/style/Rule.h
@@ -24,22 +24,37 @@ class nsHTMLCSSStyleSheet;
 namespace mozilla {
 namespace css {
 class GroupRule;
 
 class Rule : public nsISupports
            , public nsWrapperCache
 {
 protected:
-  Rule(uint32_t aLineNumber, uint32_t aColumnNumber)
-    : mSheet(nullptr),
-      mParentRule(nullptr),
-      mLineNumber(aLineNumber),
-      mColumnNumber(aColumnNumber)
+  Rule(StyleSheet* aSheet,
+       Rule* aParentRule,
+       uint32_t aLineNumber,
+       uint32_t aColumnNumber)
+    : mSheet(aSheet)
+    , mParentRule(aParentRule)
+    , mLineNumber(aLineNumber)
+    , mColumnNumber(aColumnNumber)
   {
+#ifdef DEBUG
+    // Would be nice to check that this->Type() is KEYFRAME_RULE when
+    // mParentRule->Tye() is KEYFRAMES_RULE, but we can't call
+    // this->Type() here since it's virtual.
+    if (mParentRule) {
+      int16_t type = mParentRule->Type();
+      MOZ_ASSERT(type == dom::CSSRule_Binding::MEDIA_RULE ||
+                 type == dom::CSSRule_Binding::DOCUMENT_RULE ||
+                 type == dom::CSSRule_Binding::SUPPORTS_RULE ||
+                 type == dom::CSSRule_Binding::KEYFRAMES_RULE);
+    }
+#endif
   }
 
   Rule(const Rule& aCopy)
     : mSheet(aCopy.mSheet),
       mParentRule(aCopy.mParentRule),
       mLineNumber(aCopy.mLineNumber),
       mColumnNumber(aCopy.mColumnNumber)
   {
@@ -64,32 +79,29 @@ public:
   // Return the document the rule applies to, if any.
   //
   // Suitable for style updates, and that's about it.
   nsIDocument* GetComposedDoc() const
   {
     return mSheet ? mSheet->GetComposedDoc() : nullptr;
   }
 
-  virtual void SetStyleSheet(StyleSheet* aSheet);
+  // Clear the mSheet pointer on this rule and descendants.
+  virtual void DropSheetReference();
 
-  // We don't reference count this up reference. The rule will tell us
-  // when it's going away or when we're detached from it.
-  void SetParentRule(Rule* aRule) {
-#ifdef DEBUG
-    if (aRule) {
-      int16_t type = aRule->Type();
-      MOZ_ASSERT(type == dom::CSSRule_Binding::MEDIA_RULE ||
-                 type == dom::CSSRule_Binding::DOCUMENT_RULE ||
-                 type == dom::CSSRule_Binding::SUPPORTS_RULE ||
-                 (type == dom::CSSRule_Binding::KEYFRAMES_RULE &&
-                  Type() == dom::CSSRule_Binding::KEYFRAME_RULE));
-    }
-#endif
-    mParentRule = aRule;
+  // Clear the mParentRule pointer on this rule.
+  void DropParentRuleReference()
+  {
+    mParentRule = nullptr;
+  }
+
+  void DropReferences()
+  {
+    DropSheetReference();
+    DropParentRuleReference();
   }
 
   uint32_t GetLineNumber() const { return mLineNumber; }
   uint32_t GetColumnNumber() const { return mColumnNumber; }
 
   // This is pure virtual because all of Rule's data members are non-owning and
   // thus measured elsewhere.
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
@@ -109,20 +121,23 @@ public:
     auto* associated = mSheet->GetAssociatedDocumentOrShadowRoot();
     return associated ? &associated->AsNode() : nullptr;
   }
 
 protected:
   // True if we're known-live for cycle collection purposes.
   bool IsKnownLive() const;
 
-  // This is sometimes null (e.g., for style attributes).
-  StyleSheet* mSheet;
-  // When the parent GroupRule is destroyed, it will call SetParentRule(nullptr)
-  // on this object. (Through SetParentRuleReference);
+  // mSheet should only ever be null when we create a synthetic CSSFontFaceRule
+  // for an InspectorFontFace.
+  //
+  // mSheet and mParentRule will be cleared when they are detached from the
+  // parent object, either because the rule is removed or the parent is
+  // destroyed.
+  StyleSheet* MOZ_NON_OWNING_REF mSheet;
   Rule* MOZ_NON_OWNING_REF mParentRule;
 
   // Keep the same type so that MSVC packs them.
   uint32_t          mLineNumber;
   uint32_t          mColumnNumber;
 };
 
 } // namespace css
--- a/layout/style/ServoCSSRuleList.cpp
+++ b/layout/style/ServoCSSRuleList.cpp
@@ -23,18 +23,20 @@
 #include "mozilla/ServoBindings.h"
 #include "mozilla/StyleSheet.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 ServoCSSRuleList::ServoCSSRuleList(already_AddRefed<ServoCssRules> aRawRules,
-                                   StyleSheet* aDirectOwnerStyleSheet)
-  : mStyleSheet(aDirectOwnerStyleSheet)
+                                   StyleSheet* aSheet,
+                                   css::GroupRule* aParentRule)
+  : mStyleSheet(aSheet)
+  , mParentRule(aParentRule)
   , mRawRules(aRawRules)
 {
   Servo_CssRules_ListTypes(mRawRules, &mRules);
 }
 
 // QueryInterface implementation for ServoCSSRuleList
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServoCSSRuleList)
 NS_INTERFACE_MAP_END_INHERITING(dom::CSSRuleList)
@@ -52,50 +54,33 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   tmp->EnumerateInstantiatedRules([&](css::Rule* aRule) {
     if (!aRule->IsCCLeaf()) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
       cb.NoteXPCOMChild(aRule);
     }
   });
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-void
-ServoCSSRuleList::SetParentRule(css::GroupRule* aParentRule)
-{
-  mParentRule = aParentRule;
-  EnumerateInstantiatedRules([aParentRule](css::Rule* rule) {
-    rule->SetParentRule(aParentRule);
-  });
-}
-
-void
-ServoCSSRuleList::SetStyleSheet(StyleSheet* aStyleSheet)
-{
-  mStyleSheet = aStyleSheet;
-  EnumerateInstantiatedRules([this](css::Rule* rule) {
-    rule->SetStyleSheet(mStyleSheet);
-  });
-}
-
 css::Rule*
 ServoCSSRuleList::GetRule(uint32_t aIndex)
 {
   uintptr_t rule = mRules[aIndex];
   if (rule <= kMaxRuleType) {
     RefPtr<css::Rule> ruleObj = nullptr;
     switch (rule) {
 #define CASE_RULE(const_, name_)                                            \
-      case CSSRule_Binding::const_##_RULE: {                                 \
+      case CSSRule_Binding::const_##_RULE: {                                \
         uint32_t line = 0, column = 0;                                      \
         RefPtr<RawServo##name_##Rule> rule =                                \
           Servo_CssRules_Get##name_##RuleAt(                                \
               mRawRules, aIndex, &line, &column                             \
           ).Consume();                                                      \
         MOZ_ASSERT(rule);                                                   \
-        ruleObj = new CSS##name_##Rule(rule.forget(), line, column);        \
+        ruleObj = new CSS##name_##Rule(rule.forget(), mStyleSheet,          \
+                                       mParentRule, line, column);          \
         break;                                                              \
       }
       CASE_RULE(STYLE, Style)
       CASE_RULE(KEYFRAMES, Keyframes)
       CASE_RULE(MEDIA, Media)
       CASE_RULE(NAMESPACE, Namespace)
       CASE_RULE(PAGE, Page)
       CASE_RULE(SUPPORTS, Supports)
@@ -107,18 +92,16 @@ ServoCSSRuleList::GetRule(uint32_t aInde
 #undef CASE_RULE
       case CSSRule_Binding::KEYFRAME_RULE:
         MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here");
         return nullptr;
       default:
         NS_WARNING("stylo: not implemented yet");
         return nullptr;
     }
-    ruleObj->SetStyleSheet(mStyleSheet);
-    ruleObj->SetParentRule(mParentRule);
     rule = CastToUint(ruleObj.forget().take());
     mRules[aIndex] = rule;
   }
   return CastToPtr(rule);
 }
 
 css::Rule*
 ServoCSSRuleList::IndexedGetter(uint32_t aIndex, bool& aFound)
@@ -141,36 +124,55 @@ ServoCSSRuleList::EnumerateInstantiatedR
     }
   }
 }
 
 static void
 DropRule(already_AddRefed<css::Rule> aRule)
 {
   RefPtr<css::Rule> rule = aRule;
-  rule->SetStyleSheet(nullptr);
-  rule->SetParentRule(nullptr);
+  rule->DropReferences();
 }
 
 void
 ServoCSSRuleList::DropAllRules()
 {
+  mStyleSheet = nullptr;
+  mParentRule = nullptr;
   EnumerateInstantiatedRules([](css::Rule* rule) {
     DropRule(already_AddRefed<css::Rule>(rule));
   });
   mRules.Clear();
   mRawRules = nullptr;
 }
 
 void
-ServoCSSRuleList::DropReference()
+ServoCSSRuleList::DropSheetReference()
 {
+  // If mStyleSheet is not set on this rule list, then it is not set on any of
+  // its instantiated rules either.  To avoid O(N^2) beavhior in the depth of
+  // group rule nesting, which can happen if we are unlinked starting from the
+  // deepest nested group rule, skip recursing into the rule list if we know we
+  // don't need to.
+  if (!mStyleSheet) {
+    return;
+  }
   mStyleSheet = nullptr;
+  EnumerateInstantiatedRules([](css::Rule* rule) {
+    rule->DropSheetReference();
+  });
+}
+
+void
+ServoCSSRuleList::DropParentRuleReference()
+{
   mParentRule = nullptr;
-  DropAllRules();
+  EnumerateInstantiatedRules([](css::Rule* rule) {
+    rule->DropParentRuleReference();
+  });
 }
 
 nsresult
 ServoCSSRuleList::InsertRule(const nsAString& aRule, uint32_t aIndex)
 {
   MOZ_ASSERT(mStyleSheet, "Caller must ensure that "
              "the list is not unlinked from stylesheet");
   NS_ConvertUTF16toUTF8 rule(aRule);
--- a/layout/style/ServoCSSRuleList.h
+++ b/layout/style/ServoCSSRuleList.h
@@ -22,36 +22,37 @@ class StyleSheet;
 namespace css {
 class GroupRule;
 class Rule;
 } // namespace css
 
 class ServoCSSRuleList final : public dom::CSSRuleList
 {
 public:
-  // @param aDirectOwnerStyleSheet should be set to the owner stylesheet
-  // if this rule list is owned directly by a stylesheet, which means it
-  // is a top level CSSRuleList. If it's owned by a group rule, nullptr.
-  // If this param is set, the caller doesn't need to call SetStyleSheet.
   ServoCSSRuleList(already_AddRefed<ServoCssRules> aRawRules,
-                   StyleSheet* aDirectOwnerStyleSheet);
+                   StyleSheet* aSheet,
+                   css::GroupRule* aParentRule);
   css::GroupRule* GetParentRule() const { return mParentRule; }
-  void SetParentRule(css::GroupRule* aParentRule);
-  void SetStyleSheet(StyleSheet* aSheet);
+  void DropSheetReference();
+  void DropParentRuleReference();
+
+  void DropReferences()
+  {
+    DropSheetReference();
+    DropParentRuleReference();
+  }
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServoCSSRuleList, dom::CSSRuleList)
 
   StyleSheet* GetParentObject() final { return mStyleSheet; }
 
   css::Rule* IndexedGetter(uint32_t aIndex, bool& aFound) final;
   uint32_t Length() final { return mRules.Length(); }
 
-  void DropReference();
-
   css::Rule* GetRule(uint32_t aIndex);
   nsresult InsertRule(const nsAString& aRule, uint32_t aIndex);
   nsresult DeleteRule(uint32_t aIndex);
 
   uint16_t GetDOMCSSRuleType(uint32_t aIndex) const;
 
 private:
   virtual ~ServoCSSRuleList();
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -583,17 +583,18 @@ StyleSheet::DeleteRuleFromGroup(css::Gro
     return NS_ERROR_INVALID_ARG;
   }
 
   WillDirty();
 
   nsresult result = aGroup->DeleteStyleRuleAt(aIndex);
   NS_ENSURE_SUCCESS(result, result);
 
-  rule->SetStyleSheet(nullptr);
+  rule->DropReferences();
+
   RuleRemoved(*rule);
   return NS_OK;
 }
 
 dom::ShadowRoot*
 StyleSheet::GetContainingShadow() const
 {
   if (!mOwningNode || !mOwningNode->IsContent()) {
@@ -1213,17 +1214,17 @@ StyleSheet::StyleSheetLoaded(StyleSheet*
 
   return NS_OK;
 }
 
 void
 StyleSheet::DropRuleList()
 {
   if (mRuleList) {
-    mRuleList->DropReference();
+    mRuleList->DropReferences();
     mRuleList = nullptr;
   }
 }
 
 already_AddRefed<StyleSheet>
 StyleSheet::Clone(StyleSheet* aCloneParent,
                   dom::CSSImportRule* aCloneOwnerRule,
                   dom::DocumentOrShadowRoot* aCloneDocumentOrShadowRoot,
@@ -1242,17 +1243,17 @@ ServoCSSRuleList*
 StyleSheet::GetCssRulesInternal()
 {
   if (!mRuleList) {
     EnsureUniqueInner();
 
     RefPtr<ServoCssRules> rawRules =
       Servo_StyleSheet_GetRules(Inner().mContents).Consume();
     MOZ_ASSERT(rawRules);
-    mRuleList = new ServoCSSRuleList(rawRules.forget(), this);
+    mRuleList = new ServoCSSRuleList(rawRules.forget(), this, nullptr);
   }
   return mRuleList;
 }
 
 uint32_t
 StyleSheet::InsertRuleInternal(const nsAString& aRule,
                                uint32_t aIndex,
                                ErrorResult& aRv)