diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index 5e419df06932..cf8ba07ea20d 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -810,10 +810,30 @@ RuleProcessorData::~RuleProcessorData() { MOZ_COUNT_DTOR(RuleProcessorData); - if (mPreviousSiblingData) - mPreviousSiblingData->Destroy(mPresContext); - if (mParentData) - mParentData->Destroy(mPresContext); + // Destroy potentially long chains of previous sibling and parent data + // without more than one level of recursion. + if (mPreviousSiblingData || mParentData) { + nsAutoVoidArray destroyQueue; + destroyQueue.AppendElement(this); + + do { + RuleProcessorData *d = NS_STATIC_CAST(RuleProcessorData*, + destroyQueue.FastElementAt(destroyQueue.Count() - 1)); + destroyQueue.RemoveElementAt(destroyQueue.Count() - 1); + + if (d->mPreviousSiblingData) { + destroyQueue.AppendElement(d->mPreviousSiblingData); + d->mPreviousSiblingData = nsnull; + } + if (d->mParentData) { + destroyQueue.AppendElement(d->mParentData); + d->mParentData = nsnull; + } + + if (d != this) + d->Destroy(mPresContext); + } while (destroyQueue.Count()); + } delete mLanguage; } diff --git a/layout/style/nsIStyleRuleProcessor.h b/layout/style/nsIStyleRuleProcessor.h index fe7e8209f8f9..e473f559c7dd 100644 --- a/layout/style/nsIStyleRuleProcessor.h +++ b/layout/style/nsIStyleRuleProcessor.h @@ -99,6 +99,9 @@ struct RuleProcessorData { PRInt32 mEventState; // if content, eventStateMgr->GetContentState() PRInt32 mNameSpaceID; // if content, content->GetNameSapce() const nsAttrValue* mClasses; // if styled content, styledcontent->GetClasses() + // mPreviousSiblingData and mParentData are always RuleProcessorData + // and never a derived class. They are allocated lazily, when + // selectors require matching of prior siblings or ancestors. RuleProcessorData* mPreviousSiblingData; RuleProcessorData* mParentData;