зеркало из https://github.com/mozilla/gecko-dev.git
Bug 637242, patch 2 of 3: Make nsRuleNode::Sweep nonrecursive to avoid stack exhaustion crashes. r=dbaron
This commit is contained in:
Родитель
270cd1ba97
Коммит
6b3fa1ca1c
|
@ -1331,8 +1331,7 @@ SetFactor(const nsCSSValue& aValue, float& aField, bool& aCanStoreInRuleTree,
|
|||
NS_NOTREACHED("SetFactor: inappropriate unit");
|
||||
}
|
||||
|
||||
// Overloaded new operator. Initializes the memory to 0 and relies on an arena
|
||||
// (which comes from the presShell) to perform the allocation.
|
||||
// Overloaded new operator that allocates from a presShell arena.
|
||||
void*
|
||||
nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
|
||||
{
|
||||
|
@ -1415,6 +1414,7 @@ nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
|
|||
: mPresContext(aContext),
|
||||
mParent(aParent),
|
||||
mRule(aRule),
|
||||
mNextSibling(nullptr),
|
||||
mDependentBits((uint32_t(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
|
||||
(aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
|
||||
mNoneBits(0),
|
||||
|
@ -8920,18 +8920,8 @@ nsRuleNode::Mark()
|
|||
node->mDependentBits |= NS_RULE_NODE_GC_MARK;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
SweepRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
||||
uint32_t number, void *arg)
|
||||
{
|
||||
ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
|
||||
if (entry->mRuleNode->Sweep())
|
||||
return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
bool
|
||||
nsRuleNode::Sweep()
|
||||
nsRuleNode::DestroyIfNotMarked()
|
||||
{
|
||||
// If we're not marked, then we have to delete ourself.
|
||||
// However, we never allow the root node to GC itself, because nsStyleSet
|
||||
|
@ -8946,36 +8936,92 @@ nsRuleNode::Sweep()
|
|||
|
||||
// Clear our mark, for the next time around.
|
||||
mDependentBits &= ~NS_RULE_NODE_GC_MARK;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call sweep on the children, since some may not be marked, and
|
||||
// remove any deleted children from the child lists.
|
||||
if (HaveChildren()) {
|
||||
uint32_t childrenDestroyed;
|
||||
if (ChildrenAreHashed()) {
|
||||
PLDHashTable *children = ChildrenHash();
|
||||
uint32_t oldChildCount = children->entryCount;
|
||||
PL_DHashTableEnumerate(children, SweepRuleNodeChildren, nullptr);
|
||||
childrenDestroyed = oldChildCount - children->entryCount;
|
||||
} else {
|
||||
childrenDestroyed = 0;
|
||||
for (nsRuleNode **children = ChildrenListPtr(); *children; ) {
|
||||
nsRuleNode *next = (*children)->mNextSibling;
|
||||
if ((*children)->Sweep()) {
|
||||
// This rule node was destroyed, so implicitly advance by
|
||||
// making *children point to the next entry.
|
||||
*children = next;
|
||||
++childrenDestroyed;
|
||||
} else {
|
||||
// Advance.
|
||||
children = &(*children)->mNextSibling;
|
||||
}
|
||||
PLDHashOperator
|
||||
nsRuleNode::SweepHashEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
||||
uint32_t number, void *arg)
|
||||
{
|
||||
ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
|
||||
nsRuleNode* node = entry->mRuleNode;
|
||||
if (node->DestroyIfNotMarked()) {
|
||||
return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
|
||||
}
|
||||
if (node->HaveChildren()) {
|
||||
// When children are hashed mNextSibling is not normally used but we use it
|
||||
// here to build a list of children that needs to be swept.
|
||||
nsRuleNode** headQ = static_cast<nsRuleNode**>(arg);
|
||||
node->mNextSibling = *headQ;
|
||||
*headQ = node;
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsRuleNode::SweepChildren(nsTArray<nsRuleNode*>& aSweepQueue)
|
||||
{
|
||||
NS_ASSERTION(!(mDependentBits & NS_RULE_NODE_GC_MARK),
|
||||
"missing DestroyIfNotMarked() call");
|
||||
NS_ASSERTION(HaveChildren(),
|
||||
"why call SweepChildren with no children?");
|
||||
uint32_t childrenDestroyed = 0;
|
||||
nsRuleNode* survivorsWithChildren = nullptr;
|
||||
if (ChildrenAreHashed()) {
|
||||
PLDHashTable* children = ChildrenHash();
|
||||
uint32_t oldChildCount = children->entryCount;
|
||||
PL_DHashTableEnumerate(children, SweepHashEntry, &survivorsWithChildren);
|
||||
childrenDestroyed = oldChildCount - children->entryCount;
|
||||
if (childrenDestroyed == oldChildCount) {
|
||||
PL_DHashTableDestroy(children);
|
||||
mChildren.asVoid = nullptr;
|
||||
}
|
||||
} else {
|
||||
for (nsRuleNode** children = ChildrenListPtr(); *children; ) {
|
||||
nsRuleNode* next = (*children)->mNextSibling;
|
||||
if ((*children)->DestroyIfNotMarked()) {
|
||||
// This rule node was destroyed, unlink it from the list by
|
||||
// making *children point to the next entry.
|
||||
*children = next;
|
||||
++childrenDestroyed;
|
||||
} else {
|
||||
children = &(*children)->mNextSibling;
|
||||
}
|
||||
}
|
||||
survivorsWithChildren = ChildrenList();
|
||||
}
|
||||
if (survivorsWithChildren) {
|
||||
aSweepQueue.AppendElement(survivorsWithChildren);
|
||||
}
|
||||
NS_ASSERTION(childrenDestroyed <= mRefCnt, "wrong ref count");
|
||||
mRefCnt -= childrenDestroyed;
|
||||
NS_POSTCONDITION(IsRoot() || mRefCnt > 0,
|
||||
"We didn't get swept, so we'd better have style contexts "
|
||||
"pointing to us or to one of our descendants, which means "
|
||||
"we'd better have a nonzero mRefCnt here!");
|
||||
}
|
||||
|
||||
bool
|
||||
nsRuleNode::Sweep()
|
||||
{
|
||||
NS_ASSERTION(IsRoot(), "must start sweeping at a root");
|
||||
NS_ASSERTION(!mNextSibling, "root must not have mNextSibling");
|
||||
|
||||
if (DestroyIfNotMarked()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAutoTArray<nsRuleNode*, 70> sweepQueue;
|
||||
sweepQueue.AppendElement(this);
|
||||
while (!sweepQueue.IsEmpty()) {
|
||||
nsTArray<nsRuleNode*>::index_type last = sweepQueue.Length() - 1;
|
||||
nsRuleNode* ruleNode = sweepQueue[last];
|
||||
sweepQueue.RemoveElementAt(last);
|
||||
for (; ruleNode; ruleNode = ruleNode->mNextSibling) {
|
||||
if (ruleNode->HaveChildren()) {
|
||||
ruleNode->SweepChildren(sweepQueue);
|
||||
}
|
||||
}
|
||||
mRefCnt -= childrenDestroyed;
|
||||
NS_POSTCONDITION(IsRoot() || mRefCnt > 0,
|
||||
"We didn't get swept, so we'd better have style contexts "
|
||||
"pointing to us or to one of our descendants, which means "
|
||||
"we'd better have a nonzero mRefCnt here!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -306,6 +306,12 @@ private:
|
|||
const PLDHashEntryHdr *aHdr,
|
||||
const void *aKey);
|
||||
|
||||
static PLDHashOperator
|
||||
SweepHashEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
||||
uint32_t number, void *arg);
|
||||
void SweepChildren(nsTArray<nsRuleNode*>& aSweepQueue);
|
||||
bool DestroyIfNotMarked();
|
||||
|
||||
static const PLDHashTableOps ChildrenHashOps;
|
||||
|
||||
static PLDHashOperator
|
||||
|
@ -401,8 +407,7 @@ private:
|
|||
uint32_t mRefCnt;
|
||||
|
||||
public:
|
||||
// Overloaded new operator. Initializes the memory to 0 and relies on an arena
|
||||
// (which comes from the presShell) to perform the allocation.
|
||||
// Overloaded new operator that allocates from a presShell arena.
|
||||
void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW;
|
||||
void Destroy() { DestroyInternal(nullptr); }
|
||||
|
||||
|
@ -713,6 +718,8 @@ public:
|
|||
* ancestors until it reaches a marked one. Sweep recursively sweeps
|
||||
* the children, destroys any that are unmarked, and clears marks,
|
||||
* returning true if the node on which it was called was destroyed.
|
||||
* If children are hashed, the mNextSibling field on the children is
|
||||
* temporarily used internally by Sweep.
|
||||
*/
|
||||
void Mark();
|
||||
bool Sweep();
|
||||
|
|
Загрузка…
Ссылка в новой задаче