Bug 1318238 - Clear all ServoNodeData during style set shutdown. r=bholley
MozReview-Commit-ID: 9MvBTAWeawC
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -148,16 +148,17 @@ nsINode::nsSlots::Unlink()
//----------------------------------------------------------------------
nsINode::~nsINode()
{
MOZ_ASSERT(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
MOZ_ASSERT(mSubtreeRoot == this, "Didn't restore state properly?");
#ifdef MOZ_STYLO
+ NS_ASSERTION(!HasServoData(), "expected ServoNodeData to be cleared earlier");
ClearServoData();
#endif
}
void*
nsINode::GetProperty(uint16_t aCategory, nsIAtom *aPropertyName,
nsresult *aStatus) const
{
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -83,16 +83,29 @@ MarkSelfAndDescendantsAsNotDirtyForServo
StyleChildrenIterator it(aContent);
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
MarkSelfAndDescendantsAsNotDirtyForServo(n);
}
}
}
+/* static */ void
+ServoRestyleManager::ClearServoDataFromSubtree(nsIContent* aContent)
+{
+ aContent->ClearServoData();
+ aContent->SetIsDirtyForServo();
+ aContent->UnsetHasDirtyDescendantsForServo();
+
+ AllChildrenIterator it(aContent, nsIContent::eAllChildren);
+ for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
+ ClearServoDataFromSubtree(n);
+ }
+}
+
void
ServoRestyleManager::RecreateStyleContexts(nsIContent* aContent,
nsStyleContext* aParentContext,
ServoStyleSet* aStyleSet,
nsStyleChangeList& aChangeListToProcess)
{
MOZ_ASSERT(aContent->IsElement() || aContent->IsNodeOfType(nsINode::eTEXT));
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -88,16 +88,23 @@ public:
* Gets the appropriate frame given a content and a pseudo-element tag.
*
* Right now only supports a null tag, before or after. If the pseudo-element
* is not null, the content needs to be an element.
*/
static nsIFrame* FrameForPseudoElement(const nsIContent* aContent,
nsIAtom* aPseudoTagOrNull);
+ /**
+ * Clears the ServoNodeData from all content nodes in the subtree rooted
+ * at aContent, and sets the IsDirtyForServo bit and clears the
+ * HasDirtyDescendantsForServo bit on them too.
+ */
+ static void ClearServoDataFromSubtree(nsIContent* aContent);
+
protected:
~ServoRestyleManager() {}
private:
ServoElementSnapshot* SnapshotForElement(Element* aElement);
/**
* The element-to-element snapshot table to compute restyle hints.
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -29,16 +29,31 @@ void
ServoStyleSet::Init(nsPresContext* aPresContext)
{
mPresContext = aPresContext;
}
void
ServoStyleSet::BeginShutdown()
{
+ // It's important to do this before mRawSet is released, since that will cause
+ // a RuleTree GC, which needs to happen after we have dropped all of the
+ // document's strong references to RuleNodes. We also need to do it here,
+ // in BeginShutdown, and not in Shutdown, since Shutdown happens after the
+ // frame tree has been destroyed, but before the script runners that delete
+ // native anonymous content (which also could be holding on the RuleNodes)
+ // have run. By clearing style here, before the frame tree is destroyed,
+ // the AllChildrenIterator will find the anonymous content.
+ //
+ // Note that this is pretty bad for performance; we should find a way to
+ // get by with the ServoNodeDatas being dropped as part of the document
+ // going away.
+ if (Element* root = mPresContext->Document()->GetRootElement()) {
+ ServoRestyleManager::ClearServoDataFromSubtree(root);
+ }
}
void
ServoStyleSet::Shutdown()
{
mRawSet = nullptr;
}