Backed out 2 changesets (bug 1428491) for crashes (bug 1431474) a=backout on a CLOSED TREE DEVEDITION_59_0b3_BUILD1 DEVEDITION_59_0b3_RELEASE
authorCosmin Sabou <csabou@mozilla.com>
Mon, 22 Jan 2018 16:46:57 +0200
changeset 454461 6b6e017f5974d0034b31531f44bc3907a637b5b3
parent 454460 0ae49758d6c5114514a2cffedf6ce4cd472aac0d
child 454462 406174f727182874fd518afb96f9088e1f7f5d5e
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)
reviewersbackout
bugs1428491, 1431474
milestone59.0
backs out030453672f86258c0973943180c03b3c0a60db13
d96bbef4fdb60126d731c5bbfb8e75903bdc1d92
Backed out 2 changesets (bug 1428491) for crashes (bug 1431474) a=backout on a CLOSED TREE Backed out changeset 030453672f86 (bug 1428491) Backed out changeset d96bbef4fdb6 (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
@@ -4020,19 +4020,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)
 {
@@ -1391,24 +1369,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()
 {
@@ -1435,18 +1414,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);