Bug 514773. Don't trigger rulenode gc unless we have rulenodes to gc. r=dbaron

This commit is contained in:
Boris Zbarsky 2009-09-24 13:59:43 -04:00
Родитель b0feb8e6ff
Коммит 751e9657f6
5 изменённых файлов: 65 добавлений и 6 удалений

Просмотреть файл

@ -876,7 +876,8 @@ nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
mRule(aRule),
mDependentBits((PRUint32(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
(aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
mNoneBits(0)
mNoneBits(0),
mRefCnt(0)
{
mChildren.asVoid = nsnull;
MOZ_COUNT_CTOR(nsRuleNode);
@ -884,6 +885,13 @@ nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
/* If IsRoot(), then aContext->StyleSet() is typically null at this
point. In any case, we don't want to treat the root rulenode as
unused. */
if (!IsRoot()) {
mParent->AddRef();
aContext->StyleSet()->RuleNodeUnused();
}
}
nsRuleNode::~nsRuleNode()
@ -6192,22 +6200,32 @@ nsRuleNode::Sweep()
// Call sweep on the children, since some may not be marked, and
// remove any deleted children from the child lists.
if (HaveChildren()) {
PRUint32 childrenDestroyed;
if (ChildrenAreHashed()) {
PLDHashTable *children = ChildrenHash();
PRUint32 oldChildCount = children->entryCount;
PL_DHashTableEnumerate(children, SweepRuleNodeChildren, nsnull);
childrenDestroyed = children->entryCount - oldChildCount;
} 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;
}
}
}
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 PR_FALSE;
}

Просмотреть файл

@ -451,6 +451,11 @@ private:
// Compute*Data functions don't initialize from
// inherited data.
// Reference count. This just counts the style contexts that
// reference this rulenode. When this goes to 0 or stops being 0,
// we notify the style set.
PRUint32 mRefCnt;
public:
// Overloaded new operator. Initializes the memory to 0 and relies on an arena
// (which comes from the presShell) to perform the allocation.
@ -458,6 +463,12 @@ public:
NS_HIDDEN_(void) Destroy() { DestroyInternal(nsnull); }
static NS_HIDDEN_(nsILanguageAtomService*) gLangService;
// Implemented in nsStyleSet.h, since it needs to know about nsStyleSet.
inline NS_HIDDEN_(void) AddRef();
// Implemented in nsStyleSet.h, since it needs to know about nsStyleSet.
inline NS_HIDDEN_(void) Release();
protected:
NS_HIDDEN_(void) DestroyInternal(nsRuleNode ***aDestroyQueueTail);
NS_HIDDEN_(void) PropagateDependentBit(PRUint32 aBit,

Просмотреть файл

@ -91,6 +91,8 @@ nsStyleContext::nsStyleContext(nsStyleContext* aParent,
NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
"NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
#undef eStyleStruct_LastItem
mRuleNode->AddRef();
}
nsStyleContext::~nsStyleContext()
@ -99,6 +101,8 @@ nsStyleContext::~nsStyleContext()
nsPresContext *presContext = mRuleNode->GetPresContext();
mRuleNode->Release();
presContext->PresShell()->StyleSet()->
NotifyStyleContextDestroyed(presContext, this);

Просмотреть файл

@ -85,7 +85,7 @@ static const nsStyleSet::sheetType gCSSSheetTypes[] = {
nsStyleSet::nsStyleSet()
: mRuleTree(nsnull),
mRuleWalker(nsnull),
mDestroyedCount(0),
mUnusedRuleNodeCount(0),
mBatching(0),
mInShutdown(PR_FALSE),
mAuthorStyleDisabled(PR_FALSE),
@ -905,7 +905,7 @@ nsStyleSet::Shutdown(nsPresContext* aPresContext)
mDefaultStyleData.Destroy(0, aPresContext);
}
static const PRInt32 kGCInterval = 1000;
static const PRInt32 kGCInterval = 300;
void
nsStyleSet::NotifyStyleContextDestroyed(nsPresContext* aPresContext,
@ -925,7 +925,7 @@ nsStyleSet::NotifyStyleContextDestroyed(nsPresContext* aPresContext,
if (mInReconstruct)
return;
if (++mDestroyedCount == kGCInterval) {
if (mUnusedRuleNodeCount == kGCInterval) {
GCRuleTrees();
}
}
@ -933,7 +933,7 @@ nsStyleSet::NotifyStyleContextDestroyed(nsPresContext* aPresContext,
void
nsStyleSet::GCRuleTrees()
{
mDestroyedCount = 0;
mUnusedRuleNodeCount = 0;
// Mark the style context tree by marking all style contexts which
// have no parent, which will mark all descendants. This will reach

Просмотреть файл

@ -248,6 +248,17 @@ class nsStyleSet
PRBool HasCachedStyleData() const {
return (mRuleTree && mRuleTree->TreeHasCachedData()) || !mRoots.IsEmpty();
}
// Notify the style set that a rulenode is no longer in use, or was
// just created and is not in use yet.
void RuleNodeUnused() {
++mUnusedRuleNodeCount;
}
// Notify the style set that a rulenode that wasn't in use now is
void RuleNodeInUse() {
--mUnusedRuleNodeCount;
}
private:
// Not to be implemented
@ -322,7 +333,7 @@ class nsStyleSet
nsRuleWalker* mRuleWalker; // This is an instance of a rule walker that can
// be used to navigate through our tree.
PRInt32 mDestroyedCount; // used to batch style context GC
PRUint32 mUnusedRuleNodeCount; // used to batch rule node GC
nsTArray<nsStyleContext*> mRoots; // style contexts with no parent
// Empty style rules to force things that restrict which properties
@ -343,4 +354,19 @@ class nsStyleSet
};
inline
NS_HIDDEN_(void) nsRuleNode::AddRef()
{
if (mRefCnt++ == 0 && !IsRoot()) {
mPresContext->StyleSet()->RuleNodeInUse();
}
}
inline
NS_HIDDEN_(void) nsRuleNode::Release()
{
if (--mRefCnt == 0 && !IsRoot()) {
mPresContext->StyleSet()->RuleNodeUnused();
}
}
#endif