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

This commit is contained in:
L. David Baron 2008-07-13 13:57:38 -07:00
parent f43140a296
commit bb92a0b039
2 changed files with 57 additions and 23 deletions

View File

@ -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<ChildrenHashEntry*>(hdr);
nsRuleNode ***destroyQueueTail = static_cast<nsRuleNode***>(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<ChildrenHashEntry*>(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);
}

View File

@ -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);