Bug 1329876 - Don't maintain a TreeMatchContext for Servo. r=bz
authorBobby Holley <bobbyholley@gmail.com>
Thu, 18 May 2017 12:11:59 +0200
changeset 359779 7e2357039f4af46d978a03dc0adcac60f1f980d6
parent 359778 fcf1321d8d677ad38239f5d39116148b99eb59ef
child 359780 6b8c59fc67a45fe7698e12b5d5a462b3cbb7e1b7
push id31857
push userphilringnalda@gmail.com
push dateSun, 21 May 2017 20:00:29 +0000
treeherdermozilla-central@cf9f9525e4d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1329876
milestone55.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 1329876 - Don't maintain a TreeMatchContext for Servo. r=bz
layout/base/GeckoRestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/style/StyleSetHandle.h
layout/style/StyleSetHandleInlines.h
layout/style/nsRuleProcessorData.h
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -3115,17 +3115,17 @@ void
 ElementRestyler::RestyleUndisplayedNodes(nsRestyleHint      aChildRestyleHint,
                                          UndisplayedNode*   aUndisplayed,
                                          nsIContent*        aUndisplayedParent,
                                          nsStyleContext*    aParentContext,
                                          const StyleDisplay aDisplay)
 {
   nsIContent* undisplayedParent = aUndisplayedParent;
   UndisplayedNode* undisplayed = aUndisplayed;
-  TreeMatchContext::AutoAncestorPusher pusher(mTreeMatchContext);
+  TreeMatchContext::AutoAncestorPusher pusher(&mTreeMatchContext);
   if (undisplayed) {
     pusher.PushAncestorAndStyleScope(undisplayedParent);
   }
   for (; undisplayed; undisplayed = undisplayed->getNext()) {
     NS_ASSERTION(undisplayedParent ||
                  undisplayed->mContent ==
                    mPresContext->Document()->GetRootElement(),
                  "undisplayed node child of null must be root");
@@ -3135,17 +3135,17 @@ ElementRestyler::RestyleUndisplayedNodes
 
     LOG_RESTYLE("RestyleUndisplayedChildren: undisplayed->mContent = %p",
                 undisplayed->mContent.get());
 
     // Get the parent of the undisplayed content and check if it is a XBL
     // children element. Push the children element as an ancestor here because it does
     // not have a frame and would not otherwise be pushed as an ancestor.
     nsIContent* parent = undisplayed->mContent->GetParent();
-    TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
+    TreeMatchContext::AutoAncestorPusher insertionPointPusher(&mTreeMatchContext);
     if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
       insertionPointPusher.PushAncestorAndStyleScope(parent);
     }
 
     nsRestyleHint thisChildHint = aChildRestyleHint;
     nsAutoPtr<RestyleTracker::RestyleData> undisplayedRestyleData;
     Element* element = undisplayed->mContent->AsElement();
     if (mRestyleTracker.GetRestyleData(element,
@@ -3343,17 +3343,17 @@ ElementRestyler::InitializeAccessibility
 // If you update this method, you probably want to update that one too.
 void
 ElementRestyler::RestyleContentChildren(nsIFrame* aParent,
                                         nsRestyleHint aChildRestyleHint)
 {
   LOG_RESTYLE("RestyleContentChildren");
 
   nsIFrame::ChildListIterator lists(aParent);
-  TreeMatchContext::AutoAncestorPusher ancestorPusher(mTreeMatchContext);
+  TreeMatchContext::AutoAncestorPusher ancestorPusher(&mTreeMatchContext);
   if (!lists.IsDone()) {
     ancestorPusher.PushAncestorAndStyleScope(mContent);
   }
   for (; !lists.IsDone(); lists.Next()) {
     for (nsIFrame* child : lists.CurrentList()) {
       // Out-of-flows are reached through their placeholders.  Continuations
       // and block-in-inline splits are reached through those chains.
       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
@@ -3361,17 +3361,17 @@ ElementRestyler::RestyleContentChildren(
         // Get the parent of the child frame's content and check if it
         // is a XBL children element. Push the children element as an
         // ancestor here because it does not have a frame and would not
         // otherwise be pushed as an ancestor.
 
         // Check if the frame has a content because |child| may be a
         // nsPageFrame that does not have a content.
         nsIContent* parent = child->GetContent() ? child->GetContent()->GetParent() : nullptr;
-        TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
+        TreeMatchContext::AutoAncestorPusher insertionPointPusher(&mTreeMatchContext);
         if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
           insertionPointPusher.PushAncestorAndStyleScope(parent);
         }
 
         // only do frames that are in flow
         if (child->IsPlaceholderFrame()) { // placeholder
           // get out of flow frame and recur there
           nsIFrame* outOfFlowFrame =
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -325,16 +325,42 @@ NS_NewScrollbarButtonFrame (nsIPresShell
 #ifdef NOISY_FINDFRAME
 static int32_t FFWC_totalCount=0;
 static int32_t FFWC_doLoop=0;
 static int32_t FFWC_doSibling=0;
 static int32_t FFWC_recursions=0;
 static int32_t FFWC_nextInFlows=0;
 #endif
 
+// Wrapper class to handle stack-construction a TreeMatchContext only if we're
+// using the Gecko style system.
+class MOZ_STACK_CLASS TreeMatchContextHolder
+{
+public:
+  explicit TreeMatchContextHolder(nsIDocument* aDocument)
+  {
+    if (!aDocument->IsStyledByServo()) {
+      mMaybeTreeMatchContext.emplace(aDocument,
+                                     TreeMatchContext::ForFrameConstruction);
+    }
+  }
+
+  bool Exists() const { return mMaybeTreeMatchContext.isSome(); }
+  operator TreeMatchContext*() { return mMaybeTreeMatchContext.ptrOr(nullptr); }
+
+  TreeMatchContext* operator ->()
+  {
+    MOZ_ASSERT(mMaybeTreeMatchContext.isSome());
+    return mMaybeTreeMatchContext.ptr();
+  }
+
+private:
+  Maybe<TreeMatchContext> mMaybeTreeMatchContext;
+};
+
 // Returns true if aFrame is an anonymous flex/grid item.
 static inline bool
 IsAnonymousFlexOrGridItem(const nsIFrame* aFrame)
 {
   const nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
   return pseudoType == nsCSSAnonBoxes::anonymousFlexItem ||
          pseudoType == nsCSSAnonBoxes::anonymousGridItem;
 }
@@ -798,36 +824,45 @@ public:
   // yet.  The mCreatingExtraFrames == true mode is meant to be used for
   // construction of random "extra" frames for elements via normal frame
   // construction APIs (e.g. replication of things across pages in paginated
   // mode).
   bool                      mCreatingExtraFrames;
 
   nsCOMArray<nsIContent>    mGeneratedTextNodesWithInitializer;
 
-  TreeMatchContext&         mTreeMatchContext;
+  // Selector matching context for. This is null when we're using the Servo style
+  // system.
+  TreeMatchContext*         mTreeMatchContext;
 
   // Constructor
   // Use the passed-in history state.
+  //
+  // aTreeMatchContext is null when we're using the Servo style system.
   nsFrameConstructorState(
     nsIPresShell* aPresShell,
-    TreeMatchContext& aTreeMatchContext,
+    TreeMatchContext* aTreeMatchContext,
     nsContainerFrame* aFixedContainingBlock,
     nsContainerFrame* aAbsoluteContainingBlock,
     nsContainerFrame* aFloatContainingBlock,
     already_AddRefed<nsILayoutHistoryState> aHistoryState);
   // Get the history state from the pres context's pres shell.
   nsFrameConstructorState(nsIPresShell* aPresShell,
-                          TreeMatchContext& aTreeMatchContext,
+                          TreeMatchContext* aTreeMatchContext,
                           nsContainerFrame* aFixedContainingBlock,
                           nsContainerFrame* aAbsoluteContainingBlock,
                           nsContainerFrame* aFloatContainingBlock);
 
   ~nsFrameConstructorState();
 
+  bool HasAncestorFilter()
+  {
+    return mTreeMatchContext && mTreeMatchContext->mAncestorFilter.HasFilter();
+  }
+
   // Function to push the existing absolute containing block state and
   // create a new scope. Code that uses this function should get matching
   // logic in GetAbsoluteContainingBlock.
   // Also makes aNewAbsoluteContainingBlock the containing block for
   // fixed-pos elements if necessary.
   // aPositionedFrame is the frame whose style actually makes
   // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable element
   // aPositionedFrame is the element's primary frame and
@@ -967,17 +1002,17 @@ protected:
   // AddToAttachedQueue on all of them, in order.
   LinkedList<PendingBinding> mPendingBindings;
 
   PendingBinding* mCurrentPendingBindingInsertionPoint;
 };
 
 nsFrameConstructorState::nsFrameConstructorState(
   nsIPresShell* aPresShell,
-  TreeMatchContext& aTreeMatchContext,
+  TreeMatchContext* aTreeMatchContext,
   nsContainerFrame* aFixedContainingBlock,
   nsContainerFrame* aAbsoluteContainingBlock,
   nsContainerFrame* aFloatContainingBlock,
   already_AddRefed<nsILayoutHistoryState> aHistoryState)
   : mPresContext(aPresShell->GetPresContext()),
     mPresShell(aPresShell),
     mFrameManager(aPresShell->FrameManager()),
 #ifdef MOZ_XUL
@@ -1007,17 +1042,17 @@ nsFrameConstructorState::nsFrameConstruc
   if (rootBox) {
     mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
   }
 #endif
   MOZ_COUNT_CTOR(nsFrameConstructorState);
 }
 
 nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
-                                                 TreeMatchContext& aTreeMatchContext,
+                                                 TreeMatchContext* aTreeMatchContext,
                                                  nsContainerFrame* aFixedContainingBlock,
                                                  nsContainerFrame* aAbsoluteContainingBlock,
                                                  nsContainerFrame* aFloatContainingBlock)
   : nsFrameConstructorState(aPresShell,
                             aTreeMatchContext,
                             aFixedContainingBlock,
                             aAbsoluteContainingBlock,
                             aFloatContainingBlock,
@@ -2422,20 +2457,22 @@ nsCSSFrameConstructor::ConstructDocEleme
   if (nsPresContext* presContext = mPresShell->GetPresContext()) {
     propagatedScrollFrom = presContext->UpdateViewportScrollbarStylesOverride();
   }
 
   SetUpDocElementContainingBlock(aDocElement);
 
   NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
 
-  TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
+  TreeMatchContextHolder matchContext(mDocument);
   // Initialize the ancestor filter with null for now; we'll push
   // aDocElement once we finish resolving style for it.
-  matchContext.InitAncestors(nullptr);
+  if (matchContext.Exists()) {
+    matchContext->InitAncestors(nullptr);
+  }
   nsFrameConstructorState state(mPresShell,
                                 matchContext,
                                 GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
                                 nullptr,
                                 nullptr, do_AddRef(aFrameState));
 
   // XXXbz why, exactly?
   if (!mTempFrameTreeState)
@@ -2871,17 +2908,17 @@ nsCSSFrameConstructor::SetUpDocElementCo
   // propagated
   NS_ASSERTION(!isScrollable || !isXUL,
                "XUL documents should never be scrollable - see above");
 
   nsContainerFrame* newFrame = rootFrame;
   RefPtr<nsStyleContext> rootPseudoStyle;
   // we must create a state because if the scrollbars are GFX it needs the
   // state to build the scrollbar frames.
-  TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
+  TreeMatchContextHolder matchContext(mDocument);
   nsFrameConstructorState state(mPresShell, matchContext, nullptr, nullptr, nullptr);
 
   // Start off with the viewport as parent; we'll adjust it as needed.
   nsContainerFrame* parentFrame = viewportFrame;
 
   StyleSetHandle styleSet = mPresShell->StyleSet();
   // If paginated, make sure we don't put scrollbars in
   if (!isScrollable) {
@@ -3849,46 +3886,51 @@ nsCSSFrameConstructor::ConstructFrameFro
   {
     return;
   }
 
   nsIContent* const content = aItem.mContent;
   nsIContent* parent = content->GetParent();
 
   // Push display:contents ancestors.
-  AutoDisplayContentsAncestorPusher adcp(aState.mTreeMatchContext,
-                                         aState.mPresContext, parent);
+  Maybe<AutoDisplayContentsAncestorPusher> adcp;
+  if (aState.mTreeMatchContext) {
+    adcp.emplace(*aState.mTreeMatchContext, aState.mPresContext, parent);
+  } else {
+    MOZ_ASSERT(content->IsStyledByServo());
+  }
 
   // Get the parent of the content and check if it is a XBL children element.
   // Push the children element as an ancestor here because it does
   // not have a frame and would not otherwise be pushed as an ancestor. It is
   // necessary to do so in order to correctly handle style resolution on
   // descendants.  (If !adcp.IsEmpty() then it was already pushed by
   // AutoDisplayContentsAncestorPusher above.)
   TreeMatchContext::AutoAncestorPusher
     insertionPointPusher(aState.mTreeMatchContext);
-  if (adcp.IsEmpty() && parent && nsContentUtils::IsContentInsertionPoint(parent)) {
-    if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
+  if (adcp.isSome() && adcp->IsEmpty() && parent &&
+      nsContentUtils::IsContentInsertionPoint(parent)) {
+    if (aState.mTreeMatchContext->mAncestorFilter.HasFilter()) {
       insertionPointPusher.PushAncestorAndStyleScope(parent);
     } else {
       insertionPointPusher.PushStyleScope(parent);
     }
   }
 
   // Push the content as a style ancestor now, so we don't have to do
   // it in our various full-constructor functions.  In particular,
   // since a number of full-constructor functions don't actually call
   // ProcessChildren in some cases (e.g. for CSS anonymous table boxes
   // or for situations where only anonymouse children are having
   // frames constructed), this is the best place to bottleneck the
   // pushing of the content instead of having to do it in multiple
   // places.
   TreeMatchContext::AutoAncestorPusher
     ancestorPusher(aState.mTreeMatchContext);
-  if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
+  if (aState.HasAncestorFilter()) {
     ancestorPusher.PushAncestorAndStyleScope(content);
   } else {
     ancestorPusher.PushStyleScope(content);
   }
 
   nsIFrame* newFrame;
   nsIFrame* primaryFrame;
   nsStyleContext* const styleContext = aItem.mStyleContext;
@@ -4596,17 +4638,17 @@ nsCSSFrameConstructor::BeginBuildingScro
   // We can't take the normal ProcessChildren path, because the NAC needs to
   // be parented to the scrollframe, and everything else needs to be parented
   // to the scrolledframe.
   AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC;
   DebugOnly<nsresult> rv = GetAnonymousContent(aContent, gfxScrollFrame, scrollNAC);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   if (scrollNAC.Length() > 0) {
     TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
-    if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
+    if (aState.HasAncestorFilter()) {
       ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement());
     } else {
       ancestorPusher.PushStyleScope(aContent->AsElement());
     }
 
     FrameConstructionItemList items;
     AddFCItemsForAnonymousContent(aState, gfxScrollFrame, scrollNAC, items);
     ConstructFramesFromItemList(aState, items, gfxScrollFrame, anonymousItems);
@@ -5960,17 +6002,17 @@ nsCSSFrameConstructor::AddFrameConstruct
       MOZ_ASSERT(styleContext->GetPseudo() || !isGeneratedContent,
                  "Should have had pseudo type");
       aState.mFrameManager->SetDisplayContents(aContent, styleContext);
     } else {
       aState.mFrameManager->ChangeDisplayContents(aContent, styleContext);
     }
 
     TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
-    if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
+    if (aState.HasAncestorFilter()) {
       ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement());
     } else {
       ancestorPusher.PushStyleScope(aContent->AsElement());
     }
 
     if (aParentFrame) {
       aParentFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
     }
@@ -5987,17 +6029,17 @@ nsCSSFrameConstructor::AddFrameConstruct
       // (if the content is a children element then parent != aContent because the
       // FlattenedChildIterator will transitively iterate through <xbl:children>
       // for default content). Push the children element as an ancestor here because
       // it does not have a frame and would not otherwise be pushed as an ancestor.
       nsIContent* parent = child->GetParent();
       MOZ_ASSERT(parent, "Parent must be non-null because we are iterating children.");
       TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
       if (parent != aContent && parent->IsElement()) {
-        if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
+        if (aState.HasAncestorFilter()) {
           ancestorPusher.PushAncestorAndStyleScope(parent->AsElement());
         } else {
           ancestorPusher.PushStyleScope(parent->AsElement());
         }
       }
 
       RefPtr<nsStyleContext> childContext =
         ResolveStyleContext(styleContext, child, &aState);
@@ -7173,16 +7215,17 @@ nsCSSFrameConstructor::MaybeConstructLaz
   return true;
 }
 
 void
 nsCSSFrameConstructor::CreateNeededFrames(
     nsIContent* aContent,
     TreeMatchContext& aTreeMatchContext)
 {
+  MOZ_ASSERT(!aContent->IsStyledByServo());
   NS_ASSERTION(!aContent->HasFlag(NODE_NEEDS_FRAME),
     "shouldn't get here with a content node that has needs frame bit set");
   NS_ASSERTION(aContent->HasFlag(NODE_DESCENDANTS_NEED_FRAMES),
     "should only get here with a content node that has descendants needing frames");
   MOZ_ASSERT(aTreeMatchContext.mAncestorFilter.HasFilter(),
              "The whole point of having the tree match context is optimizing "
              "the ancestor filter usage!");
 
@@ -7234,25 +7277,25 @@ nsCSSFrameConstructor::CreateNeededFrame
                     &aTreeMatchContext);
   }
 
   // Now descend.
   FlattenedChildIterator iter(aContent);
   for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
     if (child->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
       TreeMatchContext::AutoAncestorPusher insertionPointPusher(
-          aTreeMatchContext);
+          &aTreeMatchContext);
 
       // Handle stuff like xbl:children.
       if (child->GetParent() != aContent && child->GetParent()->IsElement()) {
         insertionPointPusher.PushAncestorAndStyleScope(
             child->GetParent()->AsElement());
       }
 
-      TreeMatchContext::AutoAncestorPusher pusher(aTreeMatchContext);
+      TreeMatchContext::AutoAncestorPusher pusher(&aTreeMatchContext);
       pusher.PushAncestorAndStyleScope(child);
 
       CreateNeededFrames(child, aTreeMatchContext);
     }
   }
 }
 
 void nsCSSFrameConstructor::CreateNeededFrames()
@@ -7617,23 +7660,22 @@ nsCSSFrameConstructor::ContentAppended(n
     ::AdjustAppendParentForAfterContent(this, insertion.mContainer, parentFrame,
                                         aFirstNewContent, &parentAfterFrame);
 
   // Create some new frames
   //
   // We use the provided tree match context, or create a new one on the fly
   // otherwise.
   Maybe<TreeMatchContext> matchContext;
-  if (!aProvidedTreeMatchContext) {
+  if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
     matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
     matchContext->InitAncestors(aContainer->AsElement());
   }
   nsFrameConstructorState state(mPresShell,
-                                aProvidedTreeMatchContext
-                                  ? *aProvidedTreeMatchContext : *matchContext,
+                                matchContext.ptrOr(aProvidedTreeMatchContext),
                                 GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
                                 GetAbsoluteContainingBlock(parentFrame, ABS_POS),
                                 GetFloatContainingBlock(parentFrame));
 
   // See if the containing block has :first-letter style applied.
   bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
   nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock;
   if (containingBlock) {
@@ -8124,23 +8166,22 @@ nsCSSFrameConstructor::ContentRangeInser
     LAYOUT_PHASE_TEMP_EXIT();
     RecreateFramesForContent(insertion.mParentFrame->GetContent(), false,
                              REMOVE_FOR_RECONSTRUCTION, nullptr);
     LAYOUT_PHASE_TEMP_REENTER();
     return;
   }
 
   Maybe<TreeMatchContext> matchContext;
-  if (!aProvidedTreeMatchContext) {
+  if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
     matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
     matchContext->InitAncestors(aContainer ? aContainer->AsElement() : nullptr);
   }
   nsFrameConstructorState state(mPresShell,
-                                aProvidedTreeMatchContext
-                                  ? *aProvidedTreeMatchContext : *matchContext,
+                                matchContext.ptrOr(aProvidedTreeMatchContext),
                                 GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
                                 GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
                                 GetFloatContainingBlock(insertion.mParentFrame),
                                 do_AddRef(aFrameState));
 
   // Recover state for the containing block - we need to know if
   // it has :first-letter or :first-line style applied to it. The
   // reason we care is that the internal structure in these cases
@@ -9090,17 +9131,17 @@ nsCSSFrameConstructor::CreateContinuingT
     if (rgNextInFlow) {
       rowGroupFrame->SetRepeatable(false);
     }
     else if (rowGroupFrame->IsRepeatable()) {
       // Replicate the header/footer frame.
       nsTableRowGroupFrame*   headerFooterFrame;
       nsFrameItems            childItems;
 
-      TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
+      TreeMatchContextHolder matchContext(mDocument);
       nsFrameConstructorState state(mPresShell,
                                     matchContext,
                                     GetAbsoluteContainingBlock(newFrame, FIXED_POS),
                                     GetAbsoluteContainingBlock(newFrame, ABS_POS),
                                     nullptr);
       state.mCreatingExtraFrames = true;
 
       nsStyleContext* const headerFooterStyleContext = rowGroupFrame->StyleContext();
@@ -9365,17 +9406,17 @@ nsCSSFrameConstructor::ReplicateFixedFra
   if (!firstFixed) {
     return NS_OK;
   }
 
   // Don't allow abs-pos descendants of the fixed content to escape the content.
   // This should not normally be possible (because fixed-pos elements should
   // be absolute containers) but fixed-pos tables currently aren't abs-pos
   // containers.
-  TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
+  TreeMatchContextHolder matchContext(mDocument);
   nsFrameConstructorState state(mPresShell,
                                 matchContext,
                                 aParentFrame,
                                 nullptr,
                                 mRootElementFrame);
   state.mCreatingExtraFrames = true;
 
   // We can't use an ancestor filter here, because we're not going to
@@ -10911,18 +10952,22 @@ nsCSSFrameConstructor::AddFCItemsForAnon
                "Should not be marked as needing frames");
     MOZ_ASSERT(!content->GetPrimaryFrame(),
                "Should have no existing frame");
     MOZ_ASSERT(!content->IsNodeOfType(nsINode::eCOMMENT) &&
                !content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION),
                "Why is someone creating garbage anonymous content");
 
     RefPtr<nsStyleContext> styleContext;
-    TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper
-      parentDisplayBasedStyleFixupSkipper(aState.mTreeMatchContext);
+    Maybe<TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper>
+      parentDisplayBasedStyleFixupSkipper;
+    MOZ_ASSERT_IF(!aState.mTreeMatchContext, content->IsStyledByServo());
+    if (aState.mTreeMatchContext) {
+      parentDisplayBasedStyleFixupSkipper.emplace(*aState.mTreeMatchContext);
+    }
 
     // Make sure we eagerly performed the servo cascade when the anonymous
     // nodes were created.
     MOZ_ASSERT_IF(content->IsStyledByServo() && content->IsElement(),
                   content->AsElement()->HasServoData());
 
     // Determine whether this NAC is pseudo-implementing.
     nsIAtom* pseudo = nullptr;
@@ -11133,18 +11178,19 @@ nsCSSFrameConstructor::ProcessChildren(n
     if (!addChildItems) {
       NS_WARNING("ProcessChildren max depth exceeded");
     }
 
     // Don't blockify 'display' in ApplyStyleFixups unless aFrame really is
     // a flex/grid container frame, not just has display:flex/grid.
     Maybe<TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper>
       parentDisplayBasedStyleFixupSkipper;
-    if (!isFlexOrGridContainer) {
-      parentDisplayBasedStyleFixupSkipper.emplace(aState.mTreeMatchContext);
+    MOZ_ASSERT_IF(!aState.mTreeMatchContext, aContent->IsStyledByServo());
+    if (!isFlexOrGridContainer && aState.mTreeMatchContext) {
+      parentDisplayBasedStyleFixupSkipper.emplace(*aState.mTreeMatchContext);
     }
 
     InsertionPoint insertion(aFrame, nullptr);
     FlattenedChildIterator iter(aContent);
     for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
       // Get the parent of the content and check if it is a XBL children element
       // (if the content is a children element then parent != aContent because the
       // FlattenedChildIterator will transitively iterate through <xbl:children>
@@ -11152,17 +11198,17 @@ nsCSSFrameConstructor::ProcessChildren(n
       // it does not have a frame and would not otherwise be pushed as an ancestor.
       insertion.mContainer = aContent;
       nsIContent* parent = child->GetParent();
       MOZ_ASSERT(parent, "Parent must be non-null because we are iterating children.");
       TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
       if (parent != aContent && parent->IsElement()) {
         insertion.mContainer = child->GetFlattenedTreeParent();
         MOZ_ASSERT(insertion.mContainer == GetInsertionPoint(parent, child).mContainer);
-        if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
+        if (aState.HasAncestorFilter()) {
           ancestorPusher.PushAncestorAndStyleScope(parent->AsElement());
         } else {
           ancestorPusher.PushStyleScope(parent->AsElement());
         }
       }
 
       // Frame construction item construction should not post
       // restyles, so removing restyle flags here is safe.
@@ -11676,18 +11722,17 @@ nsCSSFrameConstructor::CreateLetterFrame
     // frame.
     // XXXbz it would be really nice to destroy the old frame _first_,
     // then create the new one, so we could avoid this hack.
     aTextContent->SetPrimaryFrame(nullptr);
     nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
 
     NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
                  "Containing block is confused");
-    TreeMatchContext matchContext(mDocument,
-                                  TreeMatchContext::ForFrameConstruction);
+    TreeMatchContextHolder matchContext(mDocument);
     nsFrameConstructorState state(mPresShell,
                                   matchContext,
                                   GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
                                   GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
                                   aBlockContinuation);
 
     // Create the right type of first-letter frame
     const nsStyleDisplay* display = sc->StyleDisplay();
@@ -12053,17 +12098,17 @@ nsCSSFrameConstructor::CreateListBoxCont
                                             nsIContent*            aChild,
                                             nsIFrame**             aNewFrame,
                                             bool                   aIsAppend)
 {
 #ifdef MOZ_XUL
   // Construct a new frame
   if (nullptr != aParentFrame) {
     nsFrameItems            frameItems;
-    TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
+    TreeMatchContextHolder matchContext(mDocument);
     nsFrameConstructorState state(mPresShell,
                                   matchContext,
                                   GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
                                   GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
                                   GetFloatContainingBlock(aParentFrame),
                                   do_AddRef(mTempFrameTreeState.get()));
 
     // If we ever initialize the ancestor filter on |state|, make sure
@@ -12402,17 +12447,17 @@ nsCSSFrameConstructor::BuildInlineChildI
   // length?  Maybe even to parentContent->GetChildCount()?
   nsFrameConstructorState::PendingBindingAutoPusher
     pusher(aState, aParentItem.mPendingBinding);
 
   nsStyleContext* const parentStyleContext = aParentItem.mStyleContext;
   nsIContent* const parentContent = aParentItem.mContent;
 
   TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
-  if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
+  if (aState.HasAncestorFilter()) {
     ancestorPusher.PushAncestorAndStyleScope(parentContent->AsElement());
   } else {
     ancestorPusher.PushStyleScope(parentContent->AsElement());
   }
 
   if (!aItemIsWithinSVGText) {
     // Probe for generated content before
     CreateGeneratedContentItem(aState, nullptr, parentContent, parentStyleContext,
@@ -12443,17 +12488,17 @@ nsCSSFrameConstructor::BuildInlineChildI
       // (if the content is a children element then contentParent != parentContent because the
       // FlattenedChildIterator will transitively iterate through <xbl:children>
       // for default content). Push the children element as an ancestor here because
       // it does not have a frame and would not otherwise be pushed as an ancestor.
       nsIContent* contentParent = content->GetParent();
       MOZ_ASSERT(contentParent, "Parent must be non-null because we are iterating children.");
       TreeMatchContext::AutoAncestorPusher insertionPointPusher(aState.mTreeMatchContext);
       if (contentParent != parentContent && contentParent->IsElement()) {
-        if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
+        if (aState.HasAncestorFilter()) {
           insertionPointPusher.PushAncestorAndStyleScope(contentParent->AsElement());
         } else {
           insertionPointPusher.PushStyleScope(contentParent->AsElement());
         }
       }
 
       // Manually check for comments/PIs, since we don't have a frame to pass to
       // AddFrameConstructionItems.  We know our parent is a non-replaced inline,
@@ -12940,17 +12985,17 @@ nsCSSFrameConstructor::ReframeContaining
 void
 nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
 {
   {
     nsAutoScriptBlocker scriptBlocker;
     BeginUpdate();
 
     nsFrameItems childItems;
-    TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
+    TreeMatchContextHolder matchContext(mDocument);
     nsFrameConstructorState state(mPresShell, matchContext, nullptr, nullptr, nullptr);
     // We don't have a parent frame with a pending binding constructor here,
     // so no need to worry about ordering of the kids' constructors with it.
     // Pass null for the PendingBinding.
     ProcessChildren(state, aFrame->GetContent(), aFrame->StyleContext(),
                     aFrame, false, childItems, false,
                     nullptr);
 
--- a/layout/style/StyleSetHandle.h
+++ b/layout/style/StyleSetHandle.h
@@ -118,17 +118,17 @@ public:
     inline already_AddRefed<nsStyleContext>
     ResolveStyleFor(dom::Element* aElement,
                     nsStyleContext* aParentContext,
                     LazyComputeBehavior aMayCompute);
     inline already_AddRefed<nsStyleContext>
     ResolveStyleFor(dom::Element* aElement,
                     nsStyleContext* aParentContext,
                     LazyComputeBehavior aMayCompute,
-                    TreeMatchContext& aTreeMatchContext);
+                    TreeMatchContext* aTreeMatchContext);
     inline already_AddRefed<nsStyleContext>
     ResolveStyleForText(nsIContent* aTextNode,
                         nsStyleContext* aParentContext);
     inline already_AddRefed<nsStyleContext>
     ResolveStyleForFirstLetterContinuation(nsStyleContext* aParentContext);
     inline already_AddRefed<nsStyleContext>
     ResolveStyleForPlaceholder();
     inline already_AddRefed<nsStyleContext>
@@ -156,17 +156,17 @@ public:
     inline already_AddRefed<nsStyleContext>
     ProbePseudoElementStyle(dom::Element* aParentElement,
                             mozilla::CSSPseudoElementType aType,
                             nsStyleContext* aParentContext);
     inline already_AddRefed<nsStyleContext>
     ProbePseudoElementStyle(dom::Element* aParentElement,
                             mozilla::CSSPseudoElementType aType,
                             nsStyleContext* aParentContext,
-                            TreeMatchContext& aTreeMatchContext,
+                            TreeMatchContext* aTreeMatchContext,
                             dom::Element* aPseudoElement = nullptr);
     inline nsRestyleHint HasStateDependentStyle(dom::Element* aElement,
                                                 EventStates aStateMask);
     inline nsRestyleHint HasStateDependentStyle(
         dom::Element* aElement,
         mozilla::CSSPseudoElementType aPseudoType,
         dom::Element* aPseudoElement,
         EventStates aStateMask);
--- a/layout/style/StyleSetHandleInlines.h
+++ b/layout/style/StyleSetHandleInlines.h
@@ -84,20 +84,21 @@ StyleSetHandle::Ptr::ResolveStyleFor(dom
 {
   FORWARD(ResolveStyleFor, (aElement, aParentContext, aMayCompute));
 }
 
 already_AddRefed<nsStyleContext>
 StyleSetHandle::Ptr::ResolveStyleFor(dom::Element* aElement,
                                      nsStyleContext* aParentContext,
                                      LazyComputeBehavior aMayCompute,
-                                     TreeMatchContext& aTreeMatchContext)
+                                     TreeMatchContext* aTreeMatchContext)
 {
   if (IsGecko()) {
-    return AsGecko()->ResolveStyleFor(aElement, aParentContext, aMayCompute, aTreeMatchContext);
+    MOZ_ASSERT(aTreeMatchContext);
+    return AsGecko()->ResolveStyleFor(aElement, aParentContext, aMayCompute, *aTreeMatchContext);
   } else {
     return AsServo()->ResolveStyleFor(aElement, aParentContext, aMayCompute);
   }
 }
 
 already_AddRefed<nsStyleContext>
 StyleSetHandle::Ptr::ResolveStyleForText(nsIContent* aTextNode,
                                          nsStyleContext* aParentContext)
@@ -227,22 +228,23 @@ StyleSetHandle::Ptr::ProbePseudoElementS
 {
   FORWARD(ProbePseudoElementStyle, (aParentElement, aType, aParentContext));
 }
 
 already_AddRefed<nsStyleContext>
 StyleSetHandle::Ptr::ProbePseudoElementStyle(dom::Element* aParentElement,
                                              CSSPseudoElementType aType,
                                              nsStyleContext* aParentContext,
-                                             TreeMatchContext& aTreeMatchContext,
+                                             TreeMatchContext* aTreeMatchContext,
                                              dom::Element* aPseudoElement)
 {
   if (IsGecko()) {
+    MOZ_ASSERT(aTreeMatchContext);
     return AsGecko()->ProbePseudoElementStyle(aParentElement, aType, aParentContext,
-                                              aTreeMatchContext, aPseudoElement);
+                                              *aTreeMatchContext, aPseudoElement);
   } else {
     return AsServo()->ProbePseudoElementStyle(aParentElement, aType, aParentContext,
                                               aPseudoElement);
   }
 }
 
 nsRestyleHint
 StyleSetHandle::Ptr::HasStateDependentStyle(dom::Element* aElement,
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -221,74 +221,99 @@ struct MOZ_STACK_CLASS TreeMatchContext 
 
   bool IsWithinStyleScopeForSelectorMatching() const
   {
     NS_ASSERTION(mForScopedStyle, "only call IsWithinScopeForSelectorMatching "
                                   "when mForScopedStyle is true");
     return mCurrentStyleScope;
   }
 
-  /* Helper class for maintaining the ancestor state */
+  /*
+   * Helper class for maintaining the ancestor state.
+   *
+   * This class does nothing if aTreeMatchContext is null, which is the case for
+   * the Servo style system.
+   */
   class MOZ_RAII AutoAncestorPusher {
   public:
-    explicit AutoAncestorPusher(TreeMatchContext& aTreeMatchContext
+    explicit AutoAncestorPusher(TreeMatchContext* aTreeMatchContext
                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : mPushedAncestor(false)
       , mPushedStyleScope(false)
       , mTreeMatchContext(aTreeMatchContext)
       , mElement(nullptr)
     {
       MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     void PushAncestorAndStyleScope(mozilla::dom::Element* aElement) {
+      if (!mTreeMatchContext) {
+        MOZ_ASSERT_IF(aElement, aElement->IsStyledByServo());
+        return;
+      }
+
       MOZ_ASSERT(!mElement);
       if (aElement) {
         mElement = aElement;
         mPushedAncestor = true;
         mPushedStyleScope = true;
-        mTreeMatchContext.mAncestorFilter.PushAncestor(aElement);
-        mTreeMatchContext.PushStyleScope(aElement);
+        mTreeMatchContext->mAncestorFilter.PushAncestor(aElement);
+        mTreeMatchContext->PushStyleScope(aElement);
       }
     }
 
     void PushAncestorAndStyleScope(nsIContent* aContent) {
+      if (!mTreeMatchContext) {
+        MOZ_ASSERT_IF(aContent, aContent->IsStyledByServo());
+        return;
+      }
+
       if (aContent && aContent->IsElement()) {
         PushAncestorAndStyleScope(aContent->AsElement());
       }
     }
 
     void PushStyleScope(mozilla::dom::Element* aElement) {
+      if (!mTreeMatchContext) {
+        MOZ_ASSERT_IF(aElement, aElement->IsStyledByServo());
+        return;
+      }
+
       MOZ_ASSERT(!mElement);
       if (aElement) {
         mElement = aElement;
         mPushedStyleScope = true;
-        mTreeMatchContext.PushStyleScope(aElement);
+        mTreeMatchContext->PushStyleScope(aElement);
       }
     }
 
     void PushStyleScope(nsIContent* aContent) {
+      if (!mTreeMatchContext) {
+        MOZ_ASSERT_IF(aContent, aContent->IsStyledByServo());
+        return;
+      }
+
       if (aContent && aContent->IsElement()) {
         PushStyleScope(aContent->AsElement());
       }
     }
 
     ~AutoAncestorPusher() {
       if (mPushedAncestor) {
-        mTreeMatchContext.mAncestorFilter.PopAncestor();
+        mTreeMatchContext->mAncestorFilter.PopAncestor();
       }
       if (mPushedStyleScope) {
-        mTreeMatchContext.PopStyleScope(mElement);
+        mTreeMatchContext->PopStyleScope(mElement);
       }
     }
 
   private:
     bool mPushedAncestor;
     bool mPushedStyleScope;
-    TreeMatchContext& mTreeMatchContext;
+    TreeMatchContext* mTreeMatchContext;
     mozilla::dom::Element* mElement;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   };
 
   /* Helper class for tracking whether we're skipping the ApplyStyleFixups
    * code for special cases where child element style is modified based on
    * parent display value.
    *