Print the warning message for failure to suspect or unlink only for the objects that are the roots of what would have been collected. b=385549 r=graydon

This commit is contained in:
dbaron%dbaron.org 2007-06-25 20:36:24 +00:00
Родитель 564958fdf2
Коммит ff5099f1c4
1 изменённых файлов: 117 добавлений и 4 удалений

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

@ -435,6 +435,7 @@ struct PtrInfo
#ifdef DEBUG_CC
size_t mBytes;
char *mName;
PRUint32 mSCCIndex; // strongly connected component
#endif
PtrInfo(void *aPointer, nsCycleCollectionParticipant *aParticipant)
@ -448,7 +449,8 @@ struct PtrInfo
mLastChild()
#ifdef DEBUG_CC
, mBytes(0),
mName(nsnull)
mName(nsnull),
mSCCIndex(0)
#endif
{
}
@ -2139,6 +2141,21 @@ AddExpectedGarbage(nsVoidPtrHashKey *p, void *arg)
return PL_DHASH_NEXT;
}
struct SetSCCWalker : public GraphWalker
{
SetSCCWalker(PRUint32 aIndex) : mIndex(aIndex) {}
PRBool ShouldVisitNode(PtrInfo const *pi) { return pi->mSCCIndex == 0; }
void VisitNode(PtrInfo *pi) { pi->mSCCIndex = mIndex; }
private:
PRUint32 mIndex;
};
struct SetNonRootGreyWalker : public GraphWalker
{
PRBool ShouldVisitNode(PtrInfo const *pi) { return pi->mColor == white; }
void VisitNode(PtrInfo *pi) { pi->mColor = grey; }
};
void
nsCycleCollector::ExplainLiveExpectedGarbage()
{
@ -2173,14 +2190,13 @@ nsCycleCollector::ExplainLiveExpectedGarbage()
mScanInProgress = PR_FALSE;
PRBool giveKnownReferences = PR_FALSE;
PRBool findCycleRoots = PR_FALSE;
{
NodePool::Enumerator queue(graph.mNodes);
while (!queue.IsDone()) {
PtrInfo *pi = queue.GetNext();
if (pi->mColor == white) {
printf("nsCycleCollector: %s %p was not collected due to\n"
" missing call to suspect or failure to unlink\n",
pi->mName, pi->mPointer);
findCycleRoots = PR_TRUE;
}
if (pi->mInternalRefs != pi->mRefCount) {
@ -2213,6 +2229,103 @@ nsCycleCollector::ExplainLiveExpectedGarbage()
}
}
}
if (findCycleRoots) {
// NOTE: This code changes the white nodes that are not
// roots to gray.
// Put the nodes in post-order traversal order from a
// depth-first search.
nsDeque DFSPostOrder;
{
// Use mSCCIndex temporarily to track the DFS numbering:
const PRUint32 INDEX_UNREACHED = 0;
const PRUint32 INDEX_REACHED = 1;
const PRUint32 INDEX_NUMBERED = 2;
NodePool::Enumerator etor_clear(graph.mNodes);
while (!etor_clear.IsDone()) {
PtrInfo *pi = etor_clear.GetNext();
pi->mSCCIndex = INDEX_UNREACHED;
}
nsDeque stack;
NodePool::Enumerator etor_roots(graph.mNodes);
for (PRUint32 i = 0; i < graph.mRootCount; ++i) {
PtrInfo *root_pi = etor_roots.GetNext();
stack.Push(root_pi);
}
while (stack.GetSize() > 0) {
PtrInfo *pi = (PtrInfo*)stack.Peek();
if (pi->mSCCIndex == INDEX_UNREACHED) {
pi->mSCCIndex = INDEX_REACHED;
for (EdgePool::Iterator child = pi->mFirstChild,
child_end = pi->mLastChild;
child != child_end; ++child) {
stack.Push(*child);
}
} else {
stack.Pop();
// Somebody else might have numbered it already
// (since this is depth-first, not breadth-first).
if (pi->mSCCIndex == INDEX_REACHED) {
pi->mSCCIndex = INDEX_NUMBERED;
DFSPostOrder.Push(pi);
}
}
}
}
// Put the nodes into strongly-connected components.
{
NodePool::Enumerator etor_clear(graph.mNodes);
while (!etor_clear.IsDone()) {
PtrInfo *pi = etor_clear.GetNext();
pi->mSCCIndex = 0;
}
PRUint32 currentSCC = 1;
while (DFSPostOrder.GetSize() > 0) {
SetSCCWalker(currentSCC).Walk((PtrInfo*)DFSPostOrder.PopFront());
++currentSCC;
}
}
// Mark any white nodes reachable from other components as
// grey.
{
NodePool::Enumerator queue(graph.mNodes);
while (!queue.IsDone()) {
PtrInfo *pi = queue.GetNext();
if (pi->mColor != white)
continue;
for (EdgePool::Iterator child = pi->mFirstChild,
child_end = pi->mLastChild;
child != child_end; ++child) {
if ((*child)->mSCCIndex != pi->mSCCIndex) {
SetNonRootGreyWalker().Walk(*child);
}
}
}
}
{
NodePool::Enumerator queue(graph.mNodes);
while (!queue.IsDone()) {
PtrInfo *pi = queue.GetNext();
if (pi->mColor == white) {
printf("nsCycleCollector: %s %p in component %d\n"
" was not collected due to missing call to "
"suspect or failure to unlink\n",
pi->mName, pi->mPointer, pi->mSCCIndex);
}
}
}
}
}
mCollectionInProgress = PR_FALSE;