Bug 1373018 - Part 11: stylo: Move cached style structs to GeckoStyleContext; r?bholley draft
authorManish Goregaokar <manishearth@gmail.com>
Sat, 10 Jun 2017 22:27:45 -0700
changeset 595173 9f8e3d6c1522c46ecaf513e174f9833249920ef1
parent 595125 3447e52dabfef140b786c3b06f4012f94138ee32
child 595322 4eadb5fb9d2dba271c5ca9e2addc2799c0d73c7b
push id64267
push userbmo:manishearth@gmail.com
push dateFri, 16 Jun 2017 03:42:05 +0000
reviewersbholley
bugs1373018
milestone56.0a1
Bug 1373018 - Part 11: stylo: Move cached style structs to GeckoStyleContext; r?bholley MozReview-Commit-ID: 1LA8AJ3oNwF
layout/base/GeckoRestyleManager.cpp
layout/base/RestyleTracker.cpp
layout/style/GeckoStyleContext.cpp
layout/style/GeckoStyleContext.h
layout/style/nsStyleContext.cpp
layout/style/nsStyleContext.h
layout/style/nsStyleContextInlines.h
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -1913,17 +1913,17 @@ ElementRestyler::Restyle(nsRestyleHint a
     }
 
     // Turns out we couldn't stop restyling here.  Process the struct
     // swaps that RestyleSelf would've done had we not returned
     // RestyleResult::eStopWithStyleChange.
     for (SwapInstruction& swap : swaps) {
       LOG_RESTYLE("swapping style structs between %p and %p",
                   swap.mOldContext.get(), swap.mNewContext.get());
-      swap.mOldContext->SwapStyleData(swap.mNewContext, swap.mStructsToSwap);
+      swap.mOldContext->AsGecko()->SwapStyleData(swap.mNewContext->AsGecko(), swap.mStructsToSwap);
       swappedStructs |= swap.mStructsToSwap;
     }
     swaps.Clear();
   }
 
   if (!swappedStructs) {
     // If we swapped any structs from the old context, then we need to keep
     // it alive until after the RestyleChildren call so that we can fix up
@@ -2748,27 +2748,27 @@ ElementRestyler::RestyleSelf(nsIFrame* a
                         oldContext.get(), newContext.get());
             SwapInstruction* swap = aSwaps.AppendElement();
             swap->mOldContext = oldContext;
             swap->mNewContext = newContext;
             swap->mStructsToSwap = equalStructs;
           } else {
             LOG_RESTYLE("swapping style structs between %p and %p",
                         oldContext.get(), newContext.get());
-            oldContext->SwapStyleData(newContext, equalStructs);
+            oldContext->AsGecko()->SwapStyleData(newContext->AsGecko(), equalStructs);
             *aSwappedStructs |= equalStructs;
           }
 #ifdef RESTYLE_LOGGING
           uint32_t structs = GeckoRestyleManager::StructsToLog() & equalStructs;
           if (structs) {
             LOG_RESTYLE_INDENT();
             LOG_RESTYLE("old style context now has: %s",
-                        oldContext->GetCachedStyleDataAsString(structs).get());
+                        oldContext->AsGecko()->GetCachedStyleDataAsString(structs).get());
             LOG_RESTYLE("new style context now has: %s",
-                        newContext->GetCachedStyleDataAsString(structs).get());
+                        newContext->AsGecko()->GetCachedStyleDataAsString(structs).get());
           }
 #endif
         }
         LOG_RESTYLE("setting new style context");
         aSelf->SetStyleContext(newContext);
       }
     } else {
       LOG_RESTYLE("not setting new style context, since we'll reframe");
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -83,17 +83,17 @@ RestyleTracker::ProcessOneRestyle(Elemen
   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
 
   if (aRestyleHint & ~eRestyle_LaterSiblings) {
 #ifdef RESTYLE_LOGGING
     if (ShouldLogRestyle() && primaryFrame &&
         GeckoRestyleManager::StructsToLog() != 0) {
       LOG_RESTYLE("style context tree before restyle:");
       LOG_RESTYLE_INDENT();
-      primaryFrame->StyleContext()->LogStyleContextTree(
+      primaryFrame->StyleContext()->AsGecko()->LogStyleContextTree(
           LoggingDepth(), GeckoRestyleManager::StructsToLog());
     }
 #endif
     mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
                                     *this, aRestyleHint, aRestyleHintData);
   } else if (aChangeHint &&
              (primaryFrame ||
               (aChangeHint & nsChangeHint_ReconstructFrame))) {
--- a/layout/style/GeckoStyleContext.cpp
+++ b/layout/style/GeckoStyleContext.cpp
@@ -18,16 +18,17 @@
 using namespace mozilla;
 
 GeckoStyleContext::GeckoStyleContext(nsStyleContext* aParent,
                                      nsIAtom* aPseudoTag,
                                      CSSPseudoElementType aPseudoType,
                                      already_AddRefed<nsRuleNode> aRuleNode,
                                      bool aSkipParentDisplayBasedStyleFixup)
   : nsStyleContext(aParent, aPseudoTag, aPseudoType)
+  , mCachedResetData(nullptr)
   , mChild(nullptr)
   , mEmptyChild(nullptr)
   , mRuleNode(Move(aRuleNode))
 {
   mBits |= NS_STYLE_CONTEXT_IS_GECKO;
 
   if (aParent) {
 #ifdef DEBUG
@@ -351,19 +352,91 @@ GeckoStyleContext::SetIneligibleForShari
     do {
       child->SetIneligibleForSharing();
       child = child->mNextSibling;
     } while (mEmptyChild != child);
   }
 }
 
 #ifdef RESTYLE_LOGGING
+nsCString
+GeckoStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
+{
+  nsCString structs;
+  for (nsStyleStructID i = nsStyleStructID(0);
+       i < nsStyleStructID_Length;
+       i = nsStyleStructID(i + 1)) {
+    if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
+      const void* data = GetCachedStyleData(i);
+      if (!structs.IsEmpty()) {
+        structs.Append(' ');
+      }
+      structs.AppendPrintf("%s=%p", StructName(i), data);
+      if (HasCachedDependentStyleData(i)) {
+        structs.AppendLiteral("(dependent)");
+      } else {
+        structs.AppendLiteral("(owned)");
+      }
+    }
+  }
+  return structs;
+}
+
+int32_t&
+GeckoStyleContext::LoggingDepth()
+{
+  static int32_t depth = 0;
+  return depth;
+}
+
 void
-GeckoStyleContext::LogChildStyleContextTree(uint32_t aStructs) const
+GeckoStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
+{
+  LoggingDepth() = aLoggingDepth;
+  LogStyleContextTree(true, aStructs);
+}
+
+void
+GeckoStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
 {
+  nsCString structs = GetCachedStyleDataAsString(aStructs);
+  if (!structs.IsEmpty()) {
+    structs.Append(' ');
+  }
+
+  nsCString pseudo;
+  if (mPseudoTag) {
+    nsAutoString pseudoTag;
+    mPseudoTag->ToString(pseudoTag);
+    AppendUTF16toUTF8(pseudoTag, pseudo);
+    pseudo.Append(' ');
+  }
+
+  nsCString flags;
+  if (IsStyleIfVisited()) {
+    flags.AppendLiteral("IS_STYLE_IF_VISITED ");
+  }
+  if (HasChildThatUsesGrandancestorStyle()) {
+    flags.AppendLiteral("CHILD_USES_GRANDANCESTOR_STYLE ");
+  }
+  if (IsShared()) {
+    flags.AppendLiteral("IS_SHARED ");
+  }
+
+  nsCString parent;
+  if (aFirst) {
+    parent.AppendPrintf("parent=%p ", mParent.get());
+  }
+
+  LOG_RESTYLE("%p(%d) %s%s%s%s",
+              this, mRefCnt,
+              structs.get(), pseudo.get(), flags.get(), parent.get());
+
+  LOG_RESTYLE_INDENT();
+
   if (nullptr != mChild) {
     GeckoStyleContext* child = mChild;
     do {
       child->LogStyleContextTree(false, aStructs);
       child = child->mNextSibling;
     } while (mChild != child);
   }
   if (nullptr != mEmptyChild) {
@@ -491,19 +564,83 @@ ShouldBlockifyChildren(const nsStyleDisp
   return mozilla::StyleDisplay::Flex == displayVal ||
     mozilla::StyleDisplay::InlineFlex == displayVal ||
     mozilla::StyleDisplay::Grid == displayVal ||
     mozilla::StyleDisplay::InlineGrid == displayVal;
 }
 
 #ifdef DEBUG
 void
-GeckoStyleContext::AssertChildStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext,
-                                                      int32_t aLevels) const
+GeckoStyleContext::AssertStructsNotUsedElsewhere(
+                                       GeckoStyleContext* aDestroyingContext,
+                                       int32_t aLevels) const
 {
+  if (aLevels == 0) {
+    return;
+  }
+
+  void* data;
+
+  if (mBits & NS_STYLE_IS_GOING_AWAY) {
+    return;
+  }
+
+  if (this != aDestroyingContext) {
+    nsInheritedStyleData& destroyingInheritedData =
+      aDestroyingContext->mCachedInheritedData;
+#define STYLE_STRUCT_INHERITED(name_, checkdata_cb)                            \
+    data = destroyingInheritedData.mStyleStructs[eStyleStruct_##name_];        \
+    if (data &&                                                                \
+        !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) &&          \
+         (mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] == data)) { \
+      printf_stderr("style struct %p found on style context %p\n", data, this);\
+      nsString url;                                                            \
+      nsresult rv = PresContext()->Document()->GetURL(url);                    \
+      if (NS_SUCCEEDED(rv)) {                                                  \
+        printf_stderr("  in %s\n", NS_ConvertUTF16toUTF8(url).get());          \
+      }                                                                        \
+      MOZ_ASSERT(false, "destroying " #name_ " style struct still present "    \
+                        "in style context tree");                              \
+    }
+#define STYLE_STRUCT_RESET(name_, checkdata_cb)
+
+#include "nsStyleStructList.h"
+
+#undef STYLE_STRUCT_INHERITED
+#undef STYLE_STRUCT_RESET
+
+    if (mCachedResetData) {
+      nsResetStyleData* destroyingResetData =
+        aDestroyingContext->mCachedResetData;
+      if (destroyingResetData) {
+#define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)
+#define STYLE_STRUCT_RESET(name_, checkdata_cb)                                \
+        data = destroyingResetData->mStyleStructs[eStyleStruct_##name_];       \
+        if (data &&                                                            \
+            !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) &&      \
+            (mCachedResetData->mStyleStructs[eStyleStruct_##name_] == data)) { \
+          printf_stderr("style struct %p found on style context %p\n", data,   \
+                        this);                                                 \
+          nsString url;                                                        \
+          nsresult rv = PresContext()->Document()->GetURL(url);                \
+          if (NS_SUCCEEDED(rv)) {                                              \
+            printf_stderr("  in %s\n", NS_ConvertUTF16toUTF8(url).get());      \
+          }                                                                    \
+          MOZ_ASSERT(false, "destroying " #name_ " style struct still present "\
+                            "in style context tree");                          \
+        }
+
+#include "nsStyleStructList.h"
+
+#undef STYLE_STRUCT_INHERITED
+#undef STYLE_STRUCT_RESET
+      }
+    }
+  }
+
   if (mChild) {
     const GeckoStyleContext* child = mChild;
     do {
       child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
       child = child->mNextSibling;
     } while (child != mChild);
   }
 
@@ -512,16 +649,17 @@ GeckoStyleContext::AssertChildStructsNot
     do {
       child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
       child = child->mNextSibling;
     } while (child != mEmptyChild);
   }
 }
 #endif
 
+
 void
 GeckoStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup)
 {
 #define GET_UNIQUE_STYLE_DATA(name_) \
   static_cast<nsStyle##name_*>(GetUniqueStyleData(eStyleStruct_##name_))
 
   // CSS Inline Layout Level 3 - 3.5 Sizing Initial Letters:
   // For an N-line drop initial in a Western script, the cap-height of the
@@ -809,8 +947,65 @@ GeckoStyleContext::StyleData(nsStyleStru
     // always cache inherited data on the style context; the rule
     // node set the bit in mBits for us if needed.
     mCachedInheritedData.mStyleStructs[aSID] = const_cast<void*>(newData);
   }
 
   return newData;
 }
 
+void
+GeckoStyleContext::DestroyCachedStructs(nsPresContext* aPresContext)
+{
+  mCachedInheritedData.DestroyStructs(mBits, aPresContext);
+  if (mCachedResetData) {
+    mCachedResetData->Destroy(mBits, aPresContext);
+  }
+}
+
+
+void
+GeckoStyleContext::SwapStyleData(GeckoStyleContext* aNewContext, uint32_t aStructs)
+{
+  static_assert(nsStyleStructID_Length <= 32, "aStructs is not big enough");
+
+  for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
+       i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
+       i = nsStyleStructID(i + 1)) {
+    uint32_t bit = nsCachedStyleData::GetBitForSID(i);
+    if (!(aStructs & bit)) {
+      continue;
+    }
+    void*& thisData = mCachedInheritedData.mStyleStructs[i];
+    void*& otherData = aNewContext->mCachedInheritedData.mStyleStructs[i];
+    if (mBits & bit) {
+      if (thisData == otherData) {
+        thisData = nullptr;
+      }
+    } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
+      std::swap(thisData, otherData);
+    }
+  }
+
+  for (nsStyleStructID i = nsStyleStructID_Reset_Start;
+       i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
+       i = nsStyleStructID(i + 1)) {
+    uint32_t bit = nsCachedStyleData::GetBitForSID(i);
+    if (!(aStructs & bit)) {
+      continue;
+    }
+    if (!mCachedResetData) {
+      mCachedResetData = new (PresContext()) nsResetStyleData;
+    }
+    if (!aNewContext->mCachedResetData) {
+      aNewContext->mCachedResetData = new (PresContext()) nsResetStyleData;
+    }
+    void*& thisData = mCachedResetData->mStyleStructs[i];
+    void*& otherData = aNewContext->mCachedResetData->mStyleStructs[i];
+    if (mBits & bit) {
+      if (thisData == otherData) {
+        thisData = nullptr;
+      }
+    } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
+      std::swap(thisData, otherData);
+    }
+  }
+}
--- a/layout/style/GeckoStyleContext.h
+++ b/layout/style/GeckoStyleContext.h
@@ -74,52 +74,119 @@ public:
    *
    * The typesafe functions below are preferred to the use of this
    * function, both because they're easier to read and because they're
    * faster.
    */
   const void* NS_FASTCALL StyleData(nsStyleStructID aSID) MOZ_NONNULL_RETURN;
 
 #ifdef DEBUG
-  void AssertChildStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext,
-                                          int32_t aLevels) const;
   void ListDescendants(FILE* out, int32_t aIndent);
 
 #endif
 
 #ifdef RESTYLE_LOGGING
-  void LogChildStyleContextTree(uint32_t aStructs) const;
+
+  // This only gets called under call trees where we've already checked
+  // that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
+  // It exists here just to satisfy LOG_RESTYLE's expectations.
+  bool ShouldLogRestyle() { return true; }
+  void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs);
+  void LogStyleContextTree(bool aFirst, uint32_t aStructs);
+  int32_t& LoggingDepth();
+  nsCString GetCachedStyleDataAsString(uint32_t aStructs);
 #endif
 
   // Only called for Gecko-backed nsStyleContexts.
   void ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup);
 
   bool HasNoChildren() const;
 
   nsRuleNode* RuleNode() const {
     MOZ_ASSERT(mRuleNode);
     return mRuleNode;
   }
 
   ~GeckoStyleContext() {
     Destructor();
   }
 
+  /**
+   * Swaps owned style struct pointers between this and aNewContext, on
+   * the assumption that aNewContext is the new style context for a frame
+   * and this is the old one.  aStructs indicates which structs to consider
+   * swapping; only those which are owned in both this and aNewContext
+   * will be swapped.
+   *
+   * Additionally, if there are identical struct pointers for one of the
+   * structs indicated by aStructs, and it is not an owned struct on this,
+   * then the cached struct slot on this will be set to null.  If the struct
+   * has been swapped on an ancestor, this style context (being the old one)
+   * will be left caching the struct pointer on the new ancestor, despite
+   * inheriting from the old ancestor.  This is not normally a problem, as
+   * this style context will usually be destroyed by being released at the
+   * end of ElementRestyler::Restyle; but for style contexts held on to outside
+   * of the frame, we need to clear out the cached pointer so that if we need
+   * it again we'll re-fetch it from the new ancestor.
+   */
+  void SwapStyleData(GeckoStyleContext* aNewContext, uint32_t aStructs);
+
+  void DestroyCachedStructs(nsPresContext* aPresContext);
+
+  /**
+   * Return style data that is currently cached on the style context.
+   * Only returns the structs we cache ourselves; never consults the
+   * rule tree.
+   *
+   * For "internal" use only in nsStyleContext and nsRuleNode.
+   */
+  const void* GetCachedStyleData(nsStyleStructID aSID)
+  {
+    const void* cachedData;
+    if (nsCachedStyleData::IsReset(aSID)) {
+      if (mCachedResetData) {
+        cachedData = mCachedResetData->mStyleStructs[aSID];
+      } else {
+        cachedData = nullptr;
+      }
+    } else {
+      cachedData = mCachedInheritedData.mStyleStructs[aSID];
+    }
+    return cachedData;
+  }
+
+  // mCachedInheritedData and mCachedResetData point to both structs that
+  // are owned by this style context and structs that are owned by one of
+  // this style context's ancestors (which are indirectly owned since this
+  // style context owns a reference to its parent).  If the bit in |mBits|
+  // is set for a struct, that means that the pointer for that struct is
+  // owned by an ancestor or by the rule node rather than by this style context.
+  // Since style contexts typically have some inherited data but only sometimes
+  // have reset data, we always allocate the mCachedInheritedData, but only
+  // sometimes allocate the mCachedResetData.
+  nsResetStyleData*       mCachedResetData; // Cached reset style data.
+  nsInheritedStyleData    mCachedInheritedData; // Cached inherited style data
+
+#ifdef DEBUG
+  void AssertStructsNotUsedElsewhere(GeckoStyleContext* aDestroyingContext,
+                                     int32_t aLevels) const;
+#endif
+
 private:
   // Helper for ClearCachedInheritedStyleDataOnDescendants.
   void DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
 
   // Children are kept in two circularly-linked lists.  The list anchor
   // is not part of the list (null for empty), and we point to the first
   // child.
   // mEmptyChild for children whose rule node is the root rule node, and
   // mChild for other children.  The order of children is not
   // meaningful.
   GeckoStyleContext* mChild;
   GeckoStyleContext* mEmptyChild;
   GeckoStyleContext* mPrevSibling;
   GeckoStyleContext* mNextSibling;
   RefPtr<nsRuleNode> mRuleNode;
+
 };
-
 }
 
 #endif // mozilla_GeckoStyleContext_h
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -81,17 +81,16 @@ const uint32_t nsStyleContext::sDependen
 static bool sExpensiveStyleStructAssertionsEnabled;
 #endif
 
 nsStyleContext::nsStyleContext(nsStyleContext* aParent,
                                nsIAtom* aPseudoTag,
                                CSSPseudoElementType aPseudoType)
   : mParent(aParent)
   , mPseudoTag(aPseudoTag)
-  , mCachedResetData(nullptr)
   , mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT)
   , mRefCnt(0)
 #ifdef DEBUG
   , mFrameRefCnt(0)
   , mComputingStruct(nsStyleStructID_None)
 #endif
 {}
 
@@ -127,147 +126,60 @@ nsStyleContext::FinishConstruction()
   static_assert(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
                 "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
   #undef eStyleStruct_LastItem
 }
 
 void
 nsStyleContext::Destructor()
 {
+  GeckoStyleContext* gecko = GetAsGecko();
 #ifdef DEBUG
-  if (const GeckoStyleContext* gecko = GetAsGecko()) {
+  if (gecko) {
     NS_ASSERTION(gecko->HasNoChildren(), "destructing context with children");
-  }
-  MOZ_ASSERT(!IsServo() || !mCachedResetData);
-
-  if (IsServo()) {
-    MOZ_ASSERT(!mCachedResetData,
-               "Servo shouldn't cache reset structs in nsStyleContext");
-    for (const auto* data : mCachedInheritedData.mStyleStructs) {
-      MOZ_ASSERT(!data,
-                 "Servo shouldn't cache inherit structs in nsStyleContext");
+    if (sExpensiveStyleStructAssertionsEnabled) {
+      // Assert that the style structs we are about to destroy are not referenced
+      // anywhere else in the style context tree.  These checks are expensive,
+      // which is why they are not enabled by default.
+      GeckoStyleContext* root = gecko;
+      while (root->GetParent()) {
+        root = root->GetParent();
+      }
+      root->AssertStructsNotUsedElsewhere(gecko,
+                                          std::numeric_limits<int32_t>::max());
+    } else {
+      // In DEBUG builds when the pref is not enabled, we perform a more limited
+      // check just of the children of this style context.
+      gecko->AssertStructsNotUsedElsewhere(gecko, 2);
     }
   }
-
-  if (sExpensiveStyleStructAssertionsEnabled) {
-    // Assert that the style structs we are about to destroy are not referenced
-    // anywhere else in the style context tree.  These checks are expensive,
-    // which is why they are not enabled by default.
-    nsStyleContext* root = this;
-    while (root->mParent) {
-      root = root->mParent;
-    }
-    root->AssertStructsNotUsedElsewhere(this,
-                                        std::numeric_limits<int32_t>::max());
-  } else {
-    // In DEBUG builds when the pref is not enabled, we perform a more limited
-    // check just of the children of this style context.
-    AssertStructsNotUsedElsewhere(this, 2);
-  }
 #endif
 
   nsPresContext *presContext = PresContext();
   DebugOnly<nsStyleSet*> geckoStyleSet = presContext->PresShell()->StyleSet()->GetAsGecko();
   NS_ASSERTION(!geckoStyleSet ||
                geckoStyleSet->GetRuleTree() == AsGecko()->RuleNode()->RuleTree() ||
                geckoStyleSet->IsInRuleTreeReconstruct(),
                "destroying style context from old rule tree too late");
 
   if (mParent) {
     mParent->RemoveChild(this);
   } else {
     presContext->StyleSet()->RootStyleContextRemoved();
   }
 
   // Free up our data structs.
-  mCachedInheritedData.DestroyStructs(mBits, presContext);
-  if (mCachedResetData) {
-    mCachedResetData->Destroy(mBits, presContext);
+  if (gecko) {
+    gecko->DestroyCachedStructs(presContext);
   }
 
   // Free any ImageValues we were holding on to for CSS variable values.
   CSSVariableImageTable::RemoveAll(this);
 }
 
-#ifdef DEBUG
-void
-nsStyleContext::AssertStructsNotUsedElsewhere(
-                                       nsStyleContext* aDestroyingContext,
-                                       int32_t aLevels) const
-{
-  if (aLevels == 0) {
-    return;
-  }
-
-  void* data;
-
-  if (mBits & NS_STYLE_IS_GOING_AWAY) {
-    return;
-  }
-
-  if (this != aDestroyingContext) {
-    nsInheritedStyleData& destroyingInheritedData =
-      aDestroyingContext->mCachedInheritedData;
-#define STYLE_STRUCT_INHERITED(name_, checkdata_cb)                            \
-    data = destroyingInheritedData.mStyleStructs[eStyleStruct_##name_];        \
-    if (data &&                                                                \
-        !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) &&          \
-         (mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] == data)) { \
-      printf_stderr("style struct %p found on style context %p\n", data, this);\
-      nsString url;                                                            \
-      nsresult rv = PresContext()->Document()->GetURL(url);                    \
-      if (NS_SUCCEEDED(rv)) {                                                  \
-        printf_stderr("  in %s\n", NS_ConvertUTF16toUTF8(url).get());          \
-      }                                                                        \
-      MOZ_ASSERT(false, "destroying " #name_ " style struct still present "    \
-                        "in style context tree");                              \
-    }
-#define STYLE_STRUCT_RESET(name_, checkdata_cb)
-
-#include "nsStyleStructList.h"
-
-#undef STYLE_STRUCT_INHERITED
-#undef STYLE_STRUCT_RESET
-
-    if (mCachedResetData) {
-      nsResetStyleData* destroyingResetData =
-        aDestroyingContext->mCachedResetData;
-      if (destroyingResetData) {
-#define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)
-#define STYLE_STRUCT_RESET(name_, checkdata_cb)                                \
-        data = destroyingResetData->mStyleStructs[eStyleStruct_##name_];       \
-        if (data &&                                                            \
-            !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) &&      \
-            (mCachedResetData->mStyleStructs[eStyleStruct_##name_] == data)) { \
-          printf_stderr("style struct %p found on style context %p\n", data,   \
-                        this);                                                 \
-          nsString url;                                                        \
-          nsresult rv = PresContext()->Document()->GetURL(url);                \
-          if (NS_SUCCEEDED(rv)) {                                              \
-            printf_stderr("  in %s\n", NS_ConvertUTF16toUTF8(url).get());      \
-          }                                                                    \
-          MOZ_ASSERT(false, "destroying " #name_ " style struct still present "\
-                            "in style context tree");                          \
-        }
-
-#include "nsStyleStructList.h"
-
-#undef STYLE_STRUCT_INHERITED
-#undef STYLE_STRUCT_RESET
-      }
-    }
-  }
-
-  if (const GeckoStyleContext* gecko = GetAsGecko()) {
-    gecko->AssertChildStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
-  }
-}
-#endif
-
-
 void nsStyleContext::AddChild(nsStyleContext* aChild)
 {
   if (GeckoStyleContext* gecko = GetAsGecko()) {
     gecko->AddChild(aChild->AsGecko());
   }
 }
 
 void nsStyleContext::RemoveChild(nsStyleContext* aChild)
@@ -848,146 +760,16 @@ nsStyleContext::LookupStruct(const nsACS
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
   else
     return false;
   return true;
 }
 #endif
 
-void
-nsStyleContext::SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs)
-{
-  static_assert(nsStyleStructID_Length <= 32, "aStructs is not big enough");
-
-  for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
-       i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
-       i = nsStyleStructID(i + 1)) {
-    uint32_t bit = nsCachedStyleData::GetBitForSID(i);
-    if (!(aStructs & bit)) {
-      continue;
-    }
-    void*& thisData = mCachedInheritedData.mStyleStructs[i];
-    void*& otherData = aNewContext->mCachedInheritedData.mStyleStructs[i];
-    if (mBits & bit) {
-      if (thisData == otherData) {
-        thisData = nullptr;
-      }
-    } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
-      std::swap(thisData, otherData);
-    }
-  }
-
-  for (nsStyleStructID i = nsStyleStructID_Reset_Start;
-       i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
-       i = nsStyleStructID(i + 1)) {
-    uint32_t bit = nsCachedStyleData::GetBitForSID(i);
-    if (!(aStructs & bit)) {
-      continue;
-    }
-    if (!mCachedResetData) {
-      mCachedResetData = new (PresContext()) nsResetStyleData;
-    }
-    if (!aNewContext->mCachedResetData) {
-      aNewContext->mCachedResetData = new (PresContext()) nsResetStyleData;
-    }
-    void*& thisData = mCachedResetData->mStyleStructs[i];
-    void*& otherData = aNewContext->mCachedResetData->mStyleStructs[i];
-    if (mBits & bit) {
-      if (thisData == otherData) {
-        thisData = nullptr;
-      }
-    } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
-      std::swap(thisData, otherData);
-    }
-  }
-}
-
-#ifdef RESTYLE_LOGGING
-nsCString
-nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
-{
-  nsCString structs;
-  for (nsStyleStructID i = nsStyleStructID(0);
-       i < nsStyleStructID_Length;
-       i = nsStyleStructID(i + 1)) {
-    if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
-      const void* data = GetCachedStyleData(i);
-      if (!structs.IsEmpty()) {
-        structs.Append(' ');
-      }
-      structs.AppendPrintf("%s=%p", StructName(i), data);
-      if (HasCachedDependentStyleData(i)) {
-        structs.AppendLiteral("(dependent)");
-      } else {
-        structs.AppendLiteral("(owned)");
-      }
-    }
-  }
-  return structs;
-}
-
-int32_t&
-nsStyleContext::LoggingDepth()
-{
-  static int32_t depth = 0;
-  return depth;
-}
-
-void
-nsStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
-{
-  LoggingDepth() = aLoggingDepth;
-  LogStyleContextTree(true, aStructs);
-}
-
-void
-nsStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
-{
-  nsCString structs = GetCachedStyleDataAsString(aStructs);
-  if (!structs.IsEmpty()) {
-    structs.Append(' ');
-  }
-
-  nsCString pseudo;
-  if (mPseudoTag) {
-    nsAutoString pseudoTag;
-    mPseudoTag->ToString(pseudoTag);
-    AppendUTF16toUTF8(pseudoTag, pseudo);
-    pseudo.Append(' ');
-  }
-
-  nsCString flags;
-  if (IsStyleIfVisited()) {
-    flags.AppendLiteral("IS_STYLE_IF_VISITED ");
-  }
-  if (HasChildThatUsesGrandancestorStyle()) {
-    flags.AppendLiteral("CHILD_USES_GRANDANCESTOR_STYLE ");
-  }
-  if (IsShared()) {
-    flags.AppendLiteral("IS_SHARED ");
-  }
-
-  nsCString parent;
-  if (aFirst) {
-    parent.AppendPrintf("parent=%p ", mParent.get());
-  }
-
-  LOG_RESTYLE("%p(%d) %s%s%s%s",
-              this, mRefCnt,
-              structs.get(), pseudo.get(), flags.get(), parent.get());
-
-  LOG_RESTYLE_INDENT();
-
-  if (const GeckoStyleContext* gecko = GetAsGecko()) {
-    gecko->LogChildStyleContextTree(aStructs);
-  }
-}
-#endif
-
 #ifdef DEBUG
 /* static */ void
 nsStyleContext::Initialize()
 {
   Preferences::AddBoolVarCache(
       &sExpensiveStyleStructAssertionsEnabled,
       "layout.css.expensive-style-struct-assertions.enabled");
 }
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -379,70 +379,22 @@ public:
    * Moves this style context to a new parent.
    *
    * This function violates style context tree immutability, and
    * is a very low-level function and should only be used after verifying
    * many conditions that make it safe to call.
    */
   void MoveTo(nsStyleContext* aNewParent);
 
-  /**
-   * Swaps owned style struct pointers between this and aNewContext, on
-   * the assumption that aNewContext is the new style context for a frame
-   * and this is the old one.  aStructs indicates which structs to consider
-   * swapping; only those which are owned in both this and aNewContext
-   * will be swapped.
-   *
-   * Additionally, if there are identical struct pointers for one of the
-   * structs indicated by aStructs, and it is not an owned struct on this,
-   * then the cached struct slot on this will be set to null.  If the struct
-   * has been swapped on an ancestor, this style context (being the old one)
-   * will be left caching the struct pointer on the new ancestor, despite
-   * inheriting from the old ancestor.  This is not normally a problem, as
-   * this style context will usually be destroyed by being released at the
-   * end of ElementRestyler::Restyle; but for style contexts held on to outside
-   * of the frame, we need to clear out the cached pointer so that if we need
-   * it again we'll re-fetch it from the new ancestor.
-   */
-  void SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs);
-
 #ifdef DEBUG
   void List(FILE* out, int32_t aIndent, bool aListDescendants = true);
   static const char* StructName(nsStyleStructID aSID);
   static bool LookupStruct(const nsACString& aName, nsStyleStructID& aResult);
 #endif
 
-#ifdef RESTYLE_LOGGING
-  nsCString GetCachedStyleDataAsString(uint32_t aStructs);
-  void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs);
-  int32_t& LoggingDepth();
-#endif
-
-  /**
-   * Return style data that is currently cached on the style context.
-   * Only returns the structs we cache ourselves; never consults the
-   * rule tree.
-   *
-   * For "internal" use only in nsStyleContext and nsRuleNode.
-   */
-  const void* GetCachedStyleData(nsStyleStructID aSID)
-  {
-    const void* cachedData;
-    if (nsCachedStyleData::IsReset(aSID)) {
-      if (mCachedResetData) {
-        cachedData = mCachedResetData->mStyleStructs[aSID];
-      } else {
-        cachedData = nullptr;
-      }
-    } else {
-      cachedData = mCachedInheritedData.mStyleStructs[aSID];
-    }
-    return cachedData;
-  }
-
 protected:
   // protected destructor to discourage deletion outside of Release()
   ~nsStyleContext() {}
   // Where the actual destructor lives
   // We use this instead of a real destructor because we need
   // this to be called *before* the subclass fields are destroyed
   // by the subclass destructor
   void Destructor();
@@ -509,53 +461,27 @@ protected:
   #define STYLE_STRUCT_RESET(name_, checkdata_cb_)                      \
     template<bool aComputeData>                                         \
     const nsStyle##name_ * DoGetStyle##name_();
 
   #include "nsStyleStructList.h"
   #undef STYLE_STRUCT_RESET
   #undef STYLE_STRUCT_INHERITED
 
-#ifdef DEBUG
-  void AssertStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext,
-                                     int32_t aLevels) const;
-#endif
-
-#ifdef RESTYLE_LOGGING
-  void LogStyleContextTree(bool aFirst, uint32_t aStructs);
-
-  // This only gets called under call trees where we've already checked
-  // that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
-  // It exists here just to satisfy LOG_RESTYLE's expectations.
-  bool ShouldLogRestyle() { return true; }
-#endif
-
   RefPtr<nsStyleContext> mParent;
 
   // Style to be used instead for the R, G, and B components of color,
   // background-color, and border-*-color if the nearest ancestor link
   // element is visited (see RelevantLinkVisited()).
   RefPtr<nsStyleContext> mStyleIfVisited;
 
   // If this style context is for a pseudo-element or anonymous box,
   // the relevant atom.
   nsCOMPtr<nsIAtom> mPseudoTag;
 
-  // mCachedInheritedData and mCachedResetData point to both structs that
-  // are owned by this style context and structs that are owned by one of
-  // this style context's ancestors (which are indirectly owned since this
-  // style context owns a reference to its parent).  If the bit in |mBits|
-  // is set for a struct, that means that the pointer for that struct is
-  // owned by an ancestor or by the rule node rather than by this style context.
-  // Since style contexts typically have some inherited data but only sometimes
-  // have reset data, we always allocate the mCachedInheritedData, but only
-  // sometimes allocate the mCachedResetData.
-  nsResetStyleData*       mCachedResetData; // Cached reset style data.
-  nsInheritedStyleData    mCachedInheritedData; // Cached inherited style data
-
   // mBits stores a number of things:
   //  - It records (using the style struct bits) which structs are
   //    inherited from the parent context or owned by the rule node (i.e.,
   //    not owned by the style context).
   //  - It also stores the additional bits listed at the top of
   //    nsStyleStruct.h.
   uint64_t                mBits;
 
--- a/layout/style/nsStyleContextInlines.h
+++ b/layout/style/nsStyleContextInlines.h
@@ -57,32 +57,34 @@ const nsStyle##name_ * nsStyleContext::P
 
 // Helper functions for GetStyle* and PeekStyle*
 #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)                \
 template<bool aComputeData>                                         \
 const nsStyle##name_ * nsStyleContext::DoGetStyle##name_() {        \
   if (auto gecko = GetAsGecko()) {                                  \
     const nsStyle##name_ * cachedData =                             \
       static_cast<nsStyle##name_*>(                                 \
-        mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]);  \
+        gecko->mCachedInheritedData                                 \
+        .mStyleStructs[eStyleStruct_##name_]);                      \
     if (cachedData) /* Have it cached already, yay */               \
       return cachedData;                                            \
     if (!aComputeData) {                                            \
       /* We always cache inherited structs on the context when we */\
       /* compute them. */                                           \
       return nullptr;                                               \
     }                                                               \
     /* Have the rulenode deal */                                    \
     AUTO_CHECK_DEPENDENCY(eStyleStruct_##name_);                    \
     const nsStyle##name_ * newData =                                \
       gecko->RuleNode()->                                           \
         GetStyle##name_<aComputeData>(this->AsGecko(), mBits);      \
     /* always cache inherited data on the style context; the rule */\
     /* node set the bit in mBits for us if needed. */               \
-    mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] =      \
+    gecko->mCachedInheritedData                                     \
+      .mStyleStructs[eStyleStruct_##name_] =                        \
       const_cast<nsStyle##name_ *>(newData);                        \
     return newData;                                                 \
   }                                                                 \
   auto servo = AsServo();                                           \
   /**                                                               \
    * Also (conservatively) set the owning bit in the parent style   \
    * context if we're a text node.                                  \
    *                                                                \
@@ -127,20 +129,20 @@ const nsStyle##name_ * nsStyleContext::D
   }                                                                 \
   return data;                                                      \
 }
 
 #define STYLE_STRUCT_RESET(name_, checkdata_cb_)                              \
 template<bool aComputeData>                                                   \
 const nsStyle##name_ * nsStyleContext::DoGetStyle##name_() {                  \
   if (auto gecko = GetAsGecko()) {                                            \
-    if (mCachedResetData) {                                                   \
+    if (gecko->mCachedResetData) {                                            \
       const nsStyle##name_ * cachedData =                                     \
         static_cast<nsStyle##name_*>(                                         \
-          mCachedResetData->mStyleStructs[eStyleStruct_##name_]);             \
+          gecko->mCachedResetData->mStyleStructs[eStyleStruct_##name_]);      \
       if (cachedData) /* Have it cached already, yay */                       \
         return cachedData;                                                    \
     }                                                                         \
     /* Have the rulenode deal */                                              \
     AUTO_CHECK_DEPENDENCY(eStyleStruct_##name_);                              \
     return gecko->RuleNode()->GetStyle##name_<aComputeData>(this->AsGecko()); \
   }                                                                           \
   auto servo = AsServo();                                                     \