Backed out 2 changesets (bug 1428491) for failing browser chrome mochitest at /builds/worker/workspace/build/src/layout/style/ServoStyleSet.cpp:941 on a CLOSED TREE
authorAndreea Pavel <apavel@mozilla.com>
Tue, 16 Jan 2018 14:26:41 +0200
changeset 453715 da9adac5500fca2ee893ebe1c363ffd24cceb969
parent 453714 1565e46c84799fbf3c8a1b609d649446a205796a
child 453716 3b7efb332de3425cae2606ada7f923fb3f3670d2
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1428491
milestone59.0a1
backs out308e79e6c98f0f38c3c7c1652fd6ceae35a12955
dbfd798e491b86e55ec11b8d5cccc260e885f619
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
Backed out 2 changesets (bug 1428491) for failing browser chrome mochitest at /builds/worker/workspace/build/src/layout/style/ServoStyleSet.cpp:941 on a CLOSED TREE Backed out changeset 308e79e6c98f (bug 1428491) Backed out changeset dbfd798e491b (bug 1428491)
dom/base/nsDocument.cpp
layout/base/PresShell.cpp
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
layout/style/StyleSetHandle.h
layout/style/StyleSetHandleInlines.h
layout/style/nsStyleSet.cpp
layout/style/nsStyleSet.h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -4019,19 +4019,20 @@ nsDocument::CreateShell(nsPresContext* a
       if (node->IsElement()) {
         MOZ_ASSERT(!node->AsElement()->HasServoData());
       }
     }
 #endif
   }
 
   RefPtr<PresShell> shell = new PresShell;
+  shell->Init(this, aContext, aViewManager, aStyleSet);
+
   // Note: we don't hold a ref to the shell (it holds a ref to us)
   mPresShell = shell;
-  shell->Init(this, aContext, aViewManager, aStyleSet);
 
   // Make sure to never paint if we belong to an invisible DocShell.
   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
   if (docShell && docShell->IsInvisible())
     shell->SetNeverPainting(true);
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p with PressShell %p and DocShell %p",
                                                 this, shell.get(), docShell.get()));
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -954,17 +954,17 @@ PresShell::Init(nsIDocument* aDocument,
   // Bind the context to the presentation shell.
   mPresContext = aPresContext;
   mPresContext->AttachShell(this, aStyleSet->BackendType());
 
   // Now we can initialize the style set. Make sure to set the member before
   // calling Init, since various subroutines need to find the style set off
   // the PresContext during initialization.
   mStyleSet = aStyleSet;
-  mStyleSet->Init(aPresContext);
+  mStyleSet->Init(aPresContext, mDocument->BindingManager());
 
   // Notify our prescontext that it now has a compatibility mode.  Note that
   // this MUST happen after we set up our style set but before we create any
   // frames.
   mPresContext->CompatibilityModeChanged();
 
   // Add the preference style sheet.
   UpdatePreferenceStyles();
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -76,32 +76,32 @@ private:
 // Sets up for one or more calls to Servo_TraverseSubtree.
 class MOZ_RAII AutoPrepareTraversal
 {
 public:
   explicit AutoPrepareTraversal(ServoStyleSet* aSet)
     // For markers for animations, we have already set the markers in
     // ServoRestyleManager::PostRestyleEventForAnimations so that we don't need
     // to care about animation restyles here.
-    : mTimelineMarker(aSet->mDocument->GetDocShell(), false)
+    : mTimelineMarker(aSet->mPresContext->GetDocShell(), false)
     , mSetInServoTraversal(aSet)
   {
     MOZ_ASSERT(!aSet->StylistNeedsUpdate());
   }
 
 private:
   AutoRestyleTimelineMarker mTimelineMarker;
   AutoSetInServoTraversal mSetInServoTraversal;
 };
 
 } // namespace mozilla
 
 ServoStyleSet::ServoStyleSet(Kind aKind)
   : mKind(aKind)
-  , mDocument(nullptr)
+  , mPresContext(nullptr)
   , mAuthorStyleDisabled(false)
   , mStylistState(StylistState::NotDirty)
   , mUserFontSetUpdateGeneration(0)
   , mUserFontCacheUpdateGeneration(0)
   , mNeedsRestyleAfterEnsureUniqueInner(false)
 {
 }
 
@@ -115,60 +115,45 @@ ServoStyleSet::~ServoStyleSet()
 }
 
 UniquePtr<ServoStyleSet>
 ServoStyleSet::CreateXBLServoStyleSet(
   nsPresContext* aPresContext,
   const nsTArray<RefPtr<ServoStyleSheet>>& aNewSheets)
 {
   auto set = MakeUnique<ServoStyleSet>(Kind::ForXBL);
-  set->Init(aPresContext);
+  set->Init(aPresContext, nullptr);
 
   // The XBL style sheets aren't document level sheets, but we need to
   // decide a particular SheetType to add them to style set. This type
   // doesn't affect the place where we pull those rules from
   // stylist::push_applicable_declarations_as_xbl_only_stylist().
   set->ReplaceSheets(SheetType::Doc, aNewSheets);
 
   // Update stylist immediately.
   set->UpdateStylist();
 
-  // XBL resources are shared for a given URL, even across documents, so we
-  // can't safely keep this reference.
-  set->mDocument = nullptr;
+  // The PresContext of the bound document could be destroyed anytime later,
+  // which shouldn't be used for XBL styleset, so we clear it here to avoid
+  // dangling pointer.
+  set->mPresContext = nullptr;
 
   return set;
 }
 
-nsPresContext*
-ServoStyleSet::GetPresContext()
+void
+ServoStyleSet::Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager)
 {
-  if (!mDocument) {
-    return nullptr;
-  }
-
-  auto* shell = mDocument->GetShell();
-  if (!shell) {
-    return nullptr;
-  }
-
-  return shell->GetPresContext();
-}
-
-void
-ServoStyleSet::Init(nsPresContext* aPresContext)
-{
-  mDocument = aPresContext->Document();
-  MOZ_ASSERT(GetPresContext() == aPresContext);
-
+  mPresContext = aPresContext;
   mLastPresContextUsesXBLStyleSet = aPresContext;
 
   mRawSet.reset(Servo_StyleSet_Init(aPresContext));
+  mBindingManager = aBindingManager;
 
-  aPresContext->DeviceContext()->InitFontCache();
+  mPresContext->DeviceContext()->InitFontCache();
 
   // Now that we have an mRawSet, go ahead and notify about whatever stylesheets
   // we have so far.
   for (auto& sheetArray : mSheets) {
     for (auto& sheet : sheetArray) {
       // There's no guarantee this will create a list on the servo side whose
       // ordering matches the list that would have been created had all those
       // sheets been appended/prepended/etc after we had mRawSet. That's okay
@@ -189,25 +174,29 @@ ServoStyleSet::Init(nsPresContext* aPres
 void
 ServoStyleSet::Shutdown()
 {
   // Make sure we drop our cached style contexts before the presshell arena
   // starts going away.
   ClearNonInheritingStyleContexts();
   mRawSet = nullptr;
   mStyleRuleMap = nullptr;
+
+  // Also drop the reference to the pres context to avoid notifications from our
+  // stylesheets to dereference a null restyle manager, see bug 1422634.
+  //
+  // We should really fix bug 154199...
+  mPresContext = nullptr;
 }
 
 void
 ServoStyleSet::InvalidateStyleForCSSRuleChanges()
 {
   MOZ_ASSERT(StylistNeedsUpdate());
-  if (nsPresContext* pc = GetPresContext()) {
-    pc->RestyleManager()->AsServo()->PostRestyleEventForCSSRuleChanges();
-  }
+  mPresContext->RestyleManager()->AsServo()->PostRestyleEventForCSSRuleChanges();
 }
 
 bool
 ServoStyleSet::SetPresContext(nsPresContext* aPresContext)
 {
   MOZ_ASSERT(IsForXBL(), "Only XBL styleset can set PresContext!");
 
   mLastPresContextUsesXBLStyleSet = aPresContext;
@@ -224,22 +213,20 @@ ServoStyleSet::SetPresContext(nsPresCont
 }
 
 nsRestyleHint
 ServoStyleSet::MediumFeaturesChanged(bool aViewportChanged)
 {
   bool viewportUnitsUsed = false;
   bool rulesChanged = MediumFeaturesChangedRules(&viewportUnitsUsed);
 
-  if (nsPresContext* pc = GetPresContext()) {
-    if (mDocument->BindingManager()->MediumFeaturesChanged(pc)) {
-      // TODO(emilio): We could technically just restyle the bound elements.
-      SetStylistXBLStyleSheetsDirty();
-      rulesChanged = true;
-    }
+  if (mBindingManager &&
+      mBindingManager->MediumFeaturesChanged(mPresContext)) {
+    SetStylistXBLStyleSheetsDirty();
+    rulesChanged = true;
   }
 
   if (rulesChanged) {
     return eRestyle_Subtree;
   }
 
   if (viewportUnitsUsed && aViewportChanged) {
     return eRestyle_ForceDescendants;
@@ -304,17 +291,17 @@ ServoStyleSet::AddSizeOfIncludingThis(ns
   }
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mSheets
   // - mNonInheritingStyleContexts
   //
   // The following members are not measured:
-  // - mDocument, because it a non-owning pointer
+  // - mPresContext, because it a non-owning pointer
 }
 
 bool
 ServoStyleSet::GetAuthorStyleDisabled() const
 {
   return mAuthorStyleDisabled;
 }
 
@@ -354,52 +341,48 @@ ServoStyleSet::ResolveStyleFor(Element* 
   }
 
   return ResolveServoStyle(aElement);
 }
 
 const ServoElementSnapshotTable&
 ServoStyleSet::Snapshots()
 {
-  MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
-  return GetPresContext()->RestyleManager()->AsServo()->Snapshots();
+  return mPresContext->RestyleManager()->AsServo()->Snapshots();
 }
 
 void
 ServoStyleSet::ResolveMappedAttrDeclarationBlocks()
 {
-  if (nsHTMLStyleSheet* sheet = mDocument->GetAttributeStyleSheet()) {
+  if (nsHTMLStyleSheet* sheet = mPresContext->Document()->GetAttributeStyleSheet()) {
     sheet->CalculateMappedServoDeclarations();
   }
 
-  mDocument->ResolveScheduledSVGPresAttrs();
+  mPresContext->Document()->ResolveScheduledSVGPresAttrs();
 }
 
 void
 ServoStyleSet::PreTraverseSync()
 {
   // Get the Document's root element to ensure that the cache is valid before
   // calling into the (potentially-parallel) Servo traversal, where a cache hit
   // is necessary to avoid a data race when updating the cache.
-  mozilla::Unused << mDocument->GetRootElement();
+  mozilla::Unused << mPresContext->Document()->GetRootElement();
 
   ResolveMappedAttrDeclarationBlocks();
 
   nsMediaFeatures::InitSystemMetrics();
 
   LookAndFeel::NativeInit();
 
-  nsPresContext* presContext = GetPresContext();
-  MOZ_ASSERT(presContext,
-             "For now, we don't call into here without a pres context");
-  if (gfxUserFontSet* userFontSet = mDocument->GetUserFontSet()) {
+  if (gfxUserFontSet* userFontSet = mPresContext->Document()->GetUserFontSet()) {
     // Ensure that the @font-face data is not stale
     uint64_t generation = userFontSet->GetGeneration();
     if (generation != mUserFontSetUpdateGeneration) {
-      presContext->DeviceContext()->UpdateFontCacheUserFonts(userFontSet);
+      mPresContext->DeviceContext()->UpdateFontCacheUserFonts(userFontSet);
       mUserFontSetUpdateGeneration = generation;
     }
 
     // Ensure that the FontFaceSet's cached document principal is up to date.
     FontFaceSet* fontFaceSet =
       static_cast<FontFaceSet::UserFontSet*>(userFontSet)->GetFontFaceSet();
     fontFaceSet->UpdateStandardFontLoadPrincipal();
     bool principalChanged = fontFaceSet->HasStandardFontLoadPrincipalChanged();
@@ -412,39 +395,39 @@ ServoStyleSet::PreTraverseSync()
     }
     if (cacheGeneration != mUserFontCacheUpdateGeneration || principalChanged) {
       gfxUserFontSet::UserFontCache::UpdateAllowedFontSets(userFontSet);
       mUserFontCacheUpdateGeneration = cacheGeneration;
     }
   }
 
   UpdateStylistIfNeeded();
-  presContext->CacheAllLangs();
+  mPresContext->CacheAllLangs();
 }
 
 void
 ServoStyleSet::PreTraverse(ServoTraversalFlags aFlags, Element* aRoot)
 {
   PreTraverseSync();
 
   // Process animation stuff that we should avoid doing during the parallel
   // traversal.
   nsSMILAnimationController* smilController =
-    mDocument->HasAnimationController()
-    ? mDocument->GetAnimationController()
+    mPresContext->Document()->HasAnimationController()
+    ? mPresContext->Document()->GetAnimationController()
     : nullptr;
 
-  MOZ_ASSERT(GetPresContext());
   if (aRoot) {
-    GetPresContext()->EffectCompositor()->PreTraverseInSubtree(aFlags, aRoot);
+    mPresContext->EffectCompositor()
+                ->PreTraverseInSubtree(aFlags, aRoot);
     if (smilController) {
       smilController->PreTraverseInSubtree(aRoot);
     }
   } else {
-    GetPresContext()->EffectCompositor()->PreTraverse(aFlags);
+    mPresContext->EffectCompositor()->PreTraverse(aFlags);
     if (smilController) {
       smilController->PreTraverse();
     }
   }
 }
 
 static inline already_AddRefed<ServoStyleContext>
 ResolveStyleForTextOrFirstLetterContinuation(
@@ -826,18 +809,18 @@ ServoStyleSet::StyleSheetAt(SheetType aT
 {
   MOZ_ASSERT(IsCSSSheetType(aType));
   return mSheets[aType][aIndex];
 }
 
 void
 ServoStyleSet::AppendAllXBLStyleSheets(nsTArray<StyleSheet*>& aArray) const
 {
-  if (mDocument) {
-    mDocument->BindingManager()->AppendAllSheets(aArray);
+  if (mBindingManager) {
+    mBindingManager->AppendAllSheets(aArray);
   }
 }
 
 nsresult
 ServoStyleSet::RemoveDocStyleSheet(ServoStyleSheet* aSheet)
 {
   return RemoveStyleSheet(SheetType::Doc, aSheet);
 }
@@ -933,61 +916,60 @@ ServoStyleSet::ProbePseudoElementStyle(E
   }
 
   return computedValues.forget();
 }
 
 bool
 ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags)
 {
-  MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
-
-  if (!mDocument->GetServoRestyleRoot()) {
+  nsIDocument* doc = mPresContext->Document();
+  if (!doc->GetServoRestyleRoot()) {
     return false;
   }
 
   PreTraverse(aFlags);
   AutoPrepareTraversal guard(this);
   const SnapshotTable& snapshots = Snapshots();
 
   // Restyle the document from the root element and each of the document level
   // NAC subtree roots.
   bool postTraversalRequired = false;
 
-  Element* rootElement = mDocument->GetRootElement();
+  Element* rootElement = doc->GetRootElement();
   MOZ_ASSERT_IF(rootElement, rootElement->HasServoData());
 
   if (ShouldTraverseInParallel()) {
     aFlags |= ServoTraversalFlags::ParallelTraversal;
   }
 
   // Do the first traversal.
-  DocumentStyleRootIterator iter(mDocument->GetServoRestyleRoot());
+  DocumentStyleRootIterator iter(doc->GetServoRestyleRoot());
   while (Element* root = iter.GetNextStyleRoot()) {
     MOZ_ASSERT(MayTraverseFrom(root));
 
     Element* parent = root->GetFlattenedTreeParentElementForStyle();
     MOZ_ASSERT_IF(parent,
                   !parent->HasAnyOfFlags(Element::kAllServoDescendantBits));
 
     postTraversalRequired |=
       Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags);
     postTraversalRequired |=
       root->HasAnyOfFlags(Element::kAllServoDescendantBits | NODE_NEEDS_FRAME);
 
     if (parent) {
-      MOZ_ASSERT(root == mDocument->GetServoRestyleRoot());
+      MOZ_ASSERT(root == doc->GetServoRestyleRoot());
       if (parent->HasDirtyDescendantsForServo()) {
         // If any style invalidation was triggered in our siblings, then we may
         // need to post-traverse them, even if the root wasn't restyled after
         // all.
-        uint32_t existingBits = mDocument->GetServoRestyleRootDirtyBits();
+        uint32_t existingBits = doc->GetServoRestyleRootDirtyBits();
         // We need to propagate the existing bits to the parent.
         parent->SetFlags(existingBits);
-        mDocument->SetServoRestyleRoot(
+        doc->SetServoRestyleRoot(
             parent,
             existingBits | ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
         postTraversalRequired = true;
       }
     }
   }
 
   // If there are still animation restyles needed, trigger a second traversal to
@@ -997,33 +979,32 @@ ServoStyleSet::StyleDocument(ServoTraver
   // PreTraverse on the EffectCompositor might alter the style root. But we
   // don't need to worry about NAC, since document-level NAC shouldn't have
   // animations.
   //
   // We don't need to do this for SMIL since SMIL only updates its animation
   // values once at the begin of a tick. As a result, even if the previous
   // traversal caused, for example, the font-size to change, the SMIL style
   // won't be updated until the next tick anyway.
-  if (GetPresContext()->EffectCompositor()->PreTraverse(aFlags)) {
-    nsINode* styleRoot = mDocument->GetServoRestyleRoot();
+  if (mPresContext->EffectCompositor()->PreTraverse(aFlags)) {
+    nsINode* styleRoot = doc->GetServoRestyleRoot();
     Element* root = styleRoot->IsElement() ? styleRoot->AsElement() : rootElement;
 
     postTraversalRequired |=
       Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags);
     postTraversalRequired |=
       root->HasAnyOfFlags(Element::kAllServoDescendantBits | NODE_NEEDS_FRAME);
   }
 
   return postTraversalRequired;
 }
 
 void
 ServoStyleSet::StyleNewSubtree(Element* aRoot)
 {
-  MOZ_ASSERT(GetPresContext());
   MOZ_ASSERT(!aRoot->HasServoData());
   PreTraverseSync();
   AutoPrepareTraversal guard(this);
 
   // Do the traversal. The snapshots will not be used.
   const SnapshotTable& snapshots = Snapshots();
   auto flags = ServoTraversalFlags::Empty;
   if (ShouldTraverseInParallel()) {
@@ -1033,17 +1014,17 @@ ServoStyleSet::StyleNewSubtree(Element* 
   DebugOnly<bool> postTraversalRequired =
     Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots, flags);
   MOZ_ASSERT(!postTraversalRequired);
 
   // Annoyingly, the newly-styled content may have animations that need
   // starting, which requires traversing them again. Mark the elements
   // that need animation processing, then do a forgetful traversal to
   // update the styles and clear the animation bits.
-  if (GetPresContext()->EffectCompositor()->PreTraverseInSubtree(flags, aRoot)) {
+  if (mPresContext->EffectCompositor()->PreTraverseInSubtree(flags, aRoot)) {
     postTraversalRequired =
       Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots,
                             ServoTraversalFlags::AnimationOnly |
                             ServoTraversalFlags::Forgetful |
                             ServoTraversalFlags::ClearAnimationOnlyDirtyDescendants);
     MOZ_ASSERT(!postTraversalRequired);
   }
 }
@@ -1064,34 +1045,33 @@ ServoStyleSet::MarkOriginsDirty(OriginFl
 void
 ServoStyleSet::SetStylistStyleSheetsDirty()
 {
   mStylistState |= StylistState::StyleSheetsDirty;
 
   // We need to invalidate cached style in getComputedStyle for undisplayed
   // elements, since we don't know if any of the style sheet change that we
   // do would affect undisplayed elements.
-  if (nsPresContext* presContext = GetPresContext()) {
-    // XBL sheets don't have a pres context, but invalidating the restyle
-    // generation in that case is handled by SetXBLStyleSheetsDirty in the
-    // "master" stylist.
-    presContext->RestyleManager()->AsServo()->IncrementUndisplayedRestyleGeneration();
+  if (mPresContext) {
+    // XBL sheets don't have a pres context, but invalidating the restyle generation
+    // in that case is handled by SetXBLStyleSheetsDirty in the "master" stylist.
+    mPresContext->RestyleManager()->AsServo()->IncrementUndisplayedRestyleGeneration();
   }
 }
 
 void
 ServoStyleSet::SetStylistXBLStyleSheetsDirty()
 {
   mStylistState |= StylistState::XBLStyleSheetsDirty;
 
   // We need to invalidate cached style in getComputedStyle for undisplayed
   // elements, since we don't know if any of the style sheet change that we
   // do would affect undisplayed elements.
-  MOZ_ASSERT(GetPresContext());
-  GetPresContext()->RestyleManager()->AsServo()->IncrementUndisplayedRestyleGeneration();
+  MOZ_ASSERT(mPresContext);
+  mPresContext->RestyleManager()->AsServo()->IncrementUndisplayedRestyleGeneration();
 }
 
 void
 ServoStyleSet::RuleAdded(ServoStyleSheet& aSheet, css::Rule& aRule)
 {
   if (mStyleRuleMap) {
     mStyleRuleMap->RuleAdded(aSheet, aRule);
   }
@@ -1117,17 +1097,17 @@ ServoStyleSet::RuleChanged(ServoStyleShe
   // FIXME(emilio): Could be more granular based on aRule.
   MarkOriginsDirty(aSheet.GetOrigin());
 }
 
 #ifdef DEBUG
 void
 ServoStyleSet::AssertTreeIsClean()
 {
-  DocumentStyleRootIterator iter(mDocument);
+  DocumentStyleRootIterator iter(mPresContext->Document());
   while (Element* root = iter.GetNextStyleRoot()) {
     Servo_AssertTreeIsClean(root);
   }
 }
 #endif
 
 bool
 ServoStyleSet::GetKeyframesForName(nsAtom* aName,
@@ -1290,19 +1270,17 @@ ServoStyleSet::ClearNonInheritingStyleCo
   }
 }
 
 already_AddRefed<ServoStyleContext>
 ServoStyleSet::ResolveStyleLazilyInternal(Element* aElement,
                                           CSSPseudoElementType aPseudoType,
                                           StyleRuleInclusion aRuleInclusion)
 {
-  MOZ_ASSERT(GetPresContext(),
-             "For now, no style resolution without a pres context");
-  GetPresContext()->EffectCompositor()->PreTraverse(aElement, aPseudoType);
+  mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType);
   MOZ_ASSERT(!StylistNeedsUpdate());
 
   AutoSetInServoTraversal guard(this);
 
   /**
    * NB: This is needed because we process animations and transitions on the
    * pseudo-elements themselves, not on the parent's EagerPseudoStyles.
    *
@@ -1330,27 +1308,27 @@ ServoStyleSet::ResolveStyleLazilyInterna
   RefPtr<ServoStyleContext> computedValues =
     Servo_ResolveStyleLazily(elementForStyleResolution,
                              pseudoTypeForStyleResolution,
                              aRuleInclusion,
                              &Snapshots(),
                              mRawSet.get(),
                              /* aIgnoreExistingStyles = */ false).Consume();
 
-  if (GetPresContext()->EffectCompositor()->PreTraverse(aElement, aPseudoType)) {
+  if (mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType)) {
     computedValues =
       Servo_ResolveStyleLazily(elementForStyleResolution,
                                pseudoTypeForStyleResolution,
                                aRuleInclusion,
                                &Snapshots(),
                                mRawSet.get(),
                                /* aIgnoreExistingStyles = */ false).Consume();
   }
 
-  MOZ_DIAGNOSTIC_ASSERT(computedValues->PresContext() == GetPresContext() ||
+  MOZ_DIAGNOSTIC_ASSERT(computedValues->PresContext() == mPresContext ||
                         aElement->OwnerDoc()->GetBFCacheEntry());
 
   return computedValues.forget();
 }
 
 bool
 ServoStyleSet::AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray)
 {
@@ -1389,24 +1367,25 @@ void
 ServoStyleSet::UpdateStylist()
 {
   MOZ_ASSERT(StylistNeedsUpdate());
 
   if (mStylistState & StylistState::StyleSheetsDirty) {
     // There's no need to compute invalidations and such for an XBL styleset,
     // since they are loaded and unloaded synchronously, and they don't have to
     // deal with dynamic content changes.
-    Element* root = IsMaster() ? mDocument->GetRootElement() : nullptr;
+    Element* root =
+      IsMaster() ? mPresContext->Document()->GetDocumentElement() : nullptr;
+
     Servo_StyleSet_FlushStyleSheets(mRawSet.get(), root);
   }
 
   if (MOZ_UNLIKELY(mStylistState & StylistState::XBLStyleSheetsDirty)) {
     MOZ_ASSERT(IsMaster(), "Only master styleset can mark XBL stylesets dirty!");
-    MOZ_ASSERT(GetPresContext(), "How did they get dirty?");
-    mDocument->BindingManager()->UpdateBoundContentBindingsForServo(GetPresContext());
+    mBindingManager->UpdateBoundContentBindingsForServo(mPresContext);
   }
 
   mStylistState = StylistState::NotDirty;
 }
 
 void
 ServoStyleSet::MaybeGCRuleTree()
 {
@@ -1433,18 +1412,17 @@ ServoStyleSet::MayTraverseFrom(const Ele
   }
 
   return !Servo_Element_IsDisplayNone(parent->AsElement());
 }
 
 bool
 ServoStyleSet::ShouldTraverseInParallel() const
 {
-  MOZ_ASSERT(mDocument->GetShell(), "Styling a document without a shell?");
-  return mDocument->GetShell()->IsActive();
+  return mPresContext->PresShell()->IsActive();
 }
 
 void
 ServoStyleSet::PrependSheetOfType(SheetType aType,
                                   ServoStyleSheet* aSheet)
 {
   aSheet->AddStyleSet(this);
   mSheets[aType].InsertElementAt(0, aSheet);
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -127,17 +127,17 @@ public:
 
   explicit ServoStyleSet(Kind aKind);
   ~ServoStyleSet();
 
   static UniquePtr<ServoStyleSet>
   CreateXBLServoStyleSet(nsPresContext* aPresContext,
                          const nsTArray<RefPtr<ServoStyleSheet>>& aNewSheets);
 
-  void Init(nsPresContext* aPresContext);
+  void Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager);
   void BeginShutdown() {}
   void Shutdown();
 
   // Called when a rules in a stylesheet in this set, or a child sheet of that,
   // are mutated from CSSOM.
   void RuleAdded(ServoStyleSheet&, css::Rule&);
   void RuleRemoved(ServoStyleSheet&, css::Rule&);
   void RuleChanged(ServoStyleSheet& aSheet, css::Rule* aRule);
@@ -595,37 +595,23 @@ private:
                          ServoStyleSheet* aSheet,
                          ServoStyleSheet* aBeforeSheet);
 
   void RemoveSheetOfType(SheetType aType,
                          ServoStyleSheet* aSheet);
 
   const Kind mKind;
 
-  // The owner document of this style set. Null if this is an XBL style set.
-  //
-  // TODO(emilio): This should become a DocumentOrShadowRoot, and be owned by it
-  // directly instead of the shell, eventually.
-  nsIDocument* mDocument;
-
-  const nsPresContext* GetPresContext() const {
-    return const_cast<ServoStyleSet*>(this)->GetPresContext();
-  }
-
-  /**
-   * Return the associated pres context if we're the master style set and we
-   * have an associated pres shell.
-   */
-  nsPresContext* GetPresContext();
+  // Nullptr if this is an XBL style set, or if we've been already detached from
+  // our shell.
+  nsPresContext* MOZ_NON_OWNING_REF mPresContext = nullptr;
 
   // Because XBL style set could be used by multiple PresContext, we need to
   // store the last PresContext pointer which uses this XBL styleset for
   // computing medium rule changes.
-  //
-  // FIXME(emilio): This is a hack, and is broken. See bug 1406875.
   void* MOZ_NON_OWNING_REF mLastPresContextUsesXBLStyleSet = nullptr;
 
   UniquePtr<RawServoStyleSet> mRawSet;
   EnumeratedArray<SheetType, SheetType::Count,
                   nsTArray<RefPtr<ServoStyleSheet>>> mSheets;
   bool mAuthorStyleDisabled;
   StylistState mStylistState;
   uint64_t mUserFontSetUpdateGeneration;
@@ -644,16 +630,19 @@ private:
   // These are similar to Servo's SequentialTasks, except that they are
   // posted by C++ code running on style worker threads.
   nsTArray<PostTraversalTask> mPostTraversalTasks;
 
   // Map from raw Servo style rule to Gecko's wrapper object.
   // Constructed lazily when requested by devtools.
   UniquePtr<ServoStyleRuleMap> mStyleRuleMap;
 
+  // This can be null if we are used to hold XBL style sheets.
+  RefPtr<nsBindingManager> mBindingManager;
+
   static ServoStyleSet* sInServoTraversal;
 };
 
 class UACacheReporter final : public nsIMemoryReporter
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMEMORYREPORTER
 
--- a/layout/style/StyleSetHandle.h
+++ b/layout/style/StyleSetHandle.h
@@ -110,17 +110,17 @@ public:
     // These inline methods are defined in StyleSetHandleInlines.h.
     inline void Delete();
 
     // Style set interface.  These inline methods are defined in
     // StyleSetHandleInlines.h and just forward to the underlying
     // nsStyleSet or ServoStyleSet.  See corresponding comments in
     // nsStyleSet.h for descriptions of these methods.
 
-    inline void Init(nsPresContext* aPresContext);
+    inline void Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager);
     inline void BeginShutdown();
     inline void Shutdown();
     inline bool GetAuthorStyleDisabled() const;
     inline nsresult SetAuthorStyleDisabled(bool aStyleDisabled);
     inline void BeginUpdate();
     inline nsresult EndUpdate();
     inline already_AddRefed<nsStyleContext>
     ResolveStyleFor(dom::Element* aElement,
--- a/layout/style/StyleSetHandleInlines.h
+++ b/layout/style/StyleSetHandleInlines.h
@@ -39,19 +39,20 @@ StyleSetHandle::Ptr::Delete()
       delete AsGecko();
     } else {
       delete AsServo();
     }
   }
 }
 
 void
-StyleSetHandle::Ptr::Init(nsPresContext* aPresContext)
+StyleSetHandle::Ptr::Init(nsPresContext* aPresContext,
+                          nsBindingManager* aBindingManager)
 {
-  FORWARD(Init, (aPresContext));
+  FORWARD(Init, (aPresContext, aBindingManager));
 }
 
 void
 StyleSetHandle::Ptr::BeginShutdown()
 {
   FORWARD(BeginShutdown, ());
 }
 
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -269,25 +269,25 @@ nsStyleSet::AddSizeOfIncludingThis(nsWin
     n += mScopedDocSheetRuleProcessors[i]->SizeOfIncludingThis(mallocSizeOf);
   }
   n += mScopedDocSheetRuleProcessors.ShallowSizeOfExcludingThis(mallocSizeOf);
 
   aSizes.mLayoutGeckoStyleSets += n;
 }
 
 void
-nsStyleSet::Init(nsPresContext* aPresContext)
+nsStyleSet::Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager)
 {
   mFirstLineRule = new nsEmptyStyleRule;
   mFirstLetterRule = new nsEmptyStyleRule;
   mPlaceholderRule = new nsEmptyStyleRule;
   mDisableTextZoomStyleRule = new nsDisableTextZoomStyleRule;
-  mBindingManager = aPresContext->Document()->BindingManager();
 
   mRuleTree = nsRuleNode::CreateRootNode(aPresContext);
+  mBindingManager = aBindingManager;
 
   // Make an explicit GatherRuleProcessors call for the levels that
   // don't have style sheets.  The other levels will have their calls
   // triggered by DirtyRuleProcessors.
   GatherRuleProcessors(SheetType::PresHint);
   GatherRuleProcessors(SheetType::StyleAttr);
   GatherRuleProcessors(SheetType::Animation);
   GatherRuleProcessors(SheetType::Transition);
@@ -2697,16 +2697,19 @@ nsStyleSet::EnsureUniqueInnerOnCSSSheets
   for (SheetType type : gCSSSheetTypes) {
     for (StyleSheet* sheet : mSheets[type]) {
       queue.AppendElement(sheet);
     }
   }
 
   if (mBindingManager) {
     AutoTArray<StyleSheet*, 32> sheets;
+    // XXXheycam stylo: AppendAllSheets will need to be able to return either
+    // CSSStyleSheets or ServoStyleSheets, on request (and then here requesting
+    // CSSStyleSheets).
     mBindingManager->AppendAllSheets(sheets);
     for (StyleSheet* sheet : sheets) {
       MOZ_ASSERT(sheet->IsGecko(), "stylo: AppendAllSheets shouldn't give us "
                                    "ServoStyleSheets yet");
       queue.AppendElement(sheet->AsGecko());
     }
   }
 
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -105,17 +105,17 @@ public:
 class nsStyleSet final
 {
  public:
   nsStyleSet();
   ~nsStyleSet();
 
   void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
 
-  void Init(nsPresContext* aPresContext);
+  void Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager);
 
   nsRuleNode* GetRuleTree() { return mRuleTree; }
 
   // get a style context for a non-pseudo frame.
   already_AddRefed<mozilla::GeckoStyleContext>
   ResolveStyleFor(mozilla::dom::Element* aElement,
                   mozilla::GeckoStyleContext* aParentContext);