From bb92a0b0393a9e68937cfc594c7f68468621166f Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Sun, 13 Jul 2008 13:57:38 -0700 Subject: [PATCH] Make rule node children destruction happen in a queue from the root rule node (or root of the subtree being destroyed) rather than using recursion. (Bug 439184.) r+sr=bzbarsky --- layout/style/nsRuleNode.cpp | 73 ++++++++++++++++++++++++++----------- layout/style/nsRuleNode.h | 7 +++- 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index f707b6bbe6ea..f03ea0b8736c 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -400,11 +400,61 @@ nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW return aPresContext->AllocateFromShell(sz); } +/* static */ PR_CALLBACK PLDHashOperator +nsRuleNode::EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + ChildrenHashEntry *entry = static_cast(hdr); + nsRuleNode ***destroyQueueTail = static_cast(arg); + **destroyQueueTail = entry->mRuleNode; + *destroyQueueTail = &entry->mRuleNode->mNextSibling; + return PL_DHASH_NEXT; +} + // Overridden to prevent the global delete from being called, since the memory // came out of an nsIArena instead of the global delete operator's heap. void -nsRuleNode::Destroy() +nsRuleNode::DestroyInternal(nsRuleNode ***aDestroyQueueTail) { + nsRuleNode *destroyQueue, **destroyQueueTail; + if (aDestroyQueueTail) { + destroyQueueTail = *aDestroyQueueTail; + } else { + destroyQueue = nsnull; + destroyQueueTail = &destroyQueue; + } + + if (ChildrenAreHashed()) { + PLDHashTable *children = ChildrenHash(); + PL_DHashTableEnumerate(children, EnqueueRuleNodeChildren, + &destroyQueueTail); + *destroyQueueTail = nsnull; // ensure null-termination + PL_DHashTableDestroy(children); + } else if (HaveChildren()) { + *destroyQueueTail = ChildrenList(); + do { + destroyQueueTail = &(*destroyQueueTail)->mNextSibling; + } while (*destroyQueueTail); + } + mChildrenTaggedPtr = nsnull; + + if (aDestroyQueueTail) { + // Our caller destroys the queue. + *aDestroyQueueTail = destroyQueueTail; + } else { + // We have to do destroy the queue. When we destroy each node, it + // will add its children to the queue. + while (destroyQueue) { + nsRuleNode *cur = destroyQueue; + destroyQueue = destroyQueue->mNextSibling; + if (!destroyQueue) { + NS_ASSERTION(destroyQueueTail == &cur->mNextSibling, "mangled list"); + destroyQueueTail = &destroyQueue; + } + cur->DestroyInternal(&destroyQueueTail); + } + } + // Destroy ourselves. this->~nsRuleNode(); @@ -439,32 +489,11 @@ nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent, NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes"); } -PR_STATIC_CALLBACK(PLDHashOperator) -DeleteRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr, - PRUint32 number, void *arg) -{ - ChildrenHashEntry *entry = static_cast(hdr); - entry->mRuleNode->Destroy(); - return PL_DHASH_NEXT; -} - nsRuleNode::~nsRuleNode() { MOZ_COUNT_DTOR(nsRuleNode); if (mStyleData.mResetData || mStyleData.mInheritedData) mStyleData.Destroy(0, mPresContext); - if (ChildrenAreHashed()) { - PLDHashTable *children = ChildrenHash(); - PL_DHashTableEnumerate(children, DeleteRuleNodeChildren, nsnull); - PL_DHashTableDestroy(children); - } else if (HaveChildren()) { - nsRuleNode *node = ChildrenList(); - do { - nsRuleNode *next = node->mNextSibling; - node->Destroy(); - node = next; - } while (node); - } NS_IF_RELEASE(mRule); } diff --git a/layout/style/nsRuleNode.h b/layout/style/nsRuleNode.h index 1217e2d4d33d..343df4dc24f5 100644 --- a/layout/style/nsRuleNode.h +++ b/layout/style/nsRuleNode.h @@ -371,6 +371,10 @@ private: static PLDHashTableOps ChildrenHashOps; + static PR_CALLBACK PLDHashOperator + EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg); + Key GetKey() const { return Key(mRule, GetLevel(), IsImportantRule()); } @@ -447,10 +451,11 @@ public: // Overloaded new operator. Initializes the memory to 0 and relies on an arena // (which comes from the presShell) to perform the allocation. NS_HIDDEN_(void*) operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW; - NS_HIDDEN_(void) Destroy(); + NS_HIDDEN_(void) Destroy() { DestroyInternal(nsnull); } static NS_HIDDEN_(nsILanguageAtomService*) gLangService; protected: + NS_HIDDEN_(void) DestroyInternal(nsRuleNode ***aDestroyQueueTail); NS_HIDDEN_(void) PropagateDependentBit(PRUint32 aBit, nsRuleNode* aHighestNode); NS_HIDDEN_(void) PropagateNoneBit(PRUint32 aBit, nsRuleNode* aHighestNode);