From a5af270e47cca4720245dcf277196ffad6003b01 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Wed, 25 Apr 2012 08:10:09 -0700 Subject: [PATCH] Bug 678615 - remove ExplainLiveExpectedGarbage. r=smaug sr=peterv --- js/xpconnect/src/XPCDebug.cpp | 10 + js/xpconnect/src/nsXPConnect.cpp | 115 +---- js/xpconnect/src/xpcprivate.h | 9 +- xpcom/base/nsCycleCollector.cpp | 488 +--------------------- xpcom/base/nsCycleCollector.h | 8 +- xpcom/glue/nsCycleCollectionParticipant.h | 4 - 6 files changed, 34 insertions(+), 600 deletions(-) diff --git a/js/xpconnect/src/XPCDebug.cpp b/js/xpconnect/src/XPCDebug.cpp index 4d31c1456af..cfcd4aa6de8 100644 --- a/js/xpconnect/src/XPCDebug.cpp +++ b/js/xpconnect/src/XPCDebug.cpp @@ -475,3 +475,13 @@ xpc_DumpJSObject(JSObject* obj) return true; } + +#ifdef DEBUG +void +xpc_PrintAllReferencesTo(void *p) +{ + /* p must be a JS object */ + XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); + JS_DumpHeap(rt->GetJSRuntime(), stdout, nsnull, JSTRACE_OBJECT, p, 0x7fffffff, nsnull); +} +#endif diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index eb93c104481..58b4e9d5717 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -119,9 +119,6 @@ nsXPConnect::nsXPConnect() mRuntime = XPCJSRuntime::newXPCJSRuntime(this); nsCycleCollector_registerRuntime(nsIProgrammingLanguage::JAVASCRIPT, this); -#ifdef DEBUG_CC - mJSRoots.ops = nsnull; -#endif char* reportableEnv = PR_GetEnv("MOZ_REPORT_ALL_JS_EXCEPTIONS"); if (reportableEnv && *reportableEnv) @@ -399,14 +396,14 @@ nsXPConnect::Collect(PRUint32 reason, PRUint32 kind) // JS objects that are part of cycles the cycle collector breaks will be // collected by the next JS. // - // If DEBUG_CC is not defined the cycle collector will not traverse roots + // If WantAllTraces() is false the cycle collector will not traverse roots // from category 1 or any JS objects held by them. Any JS objects they hold // will already be marked by the JS GC and will thus be colored black // themselves. Any C++ objects they hold will have a missing (untraversed) // edge from the JS object to the C++ object and so it will be marked black // too. This decreases the number of objects that the cycle collector has to // deal with. - // To improve debugging, if DEBUG_CC is defined all JS objects are + // To improve debugging, if WantAllTraces() is true all JS objects are // traversed. MOZ_ASSERT(reason < js::gcreason::NUM_REASONS); @@ -431,37 +428,6 @@ nsXPConnect::GarbageCollect(PRUint32 reason, PRUint32 kind) return NS_OK; } -#ifdef DEBUG_CC -struct NoteJSRootTracer : public JSTracer -{ - NoteJSRootTracer(PLDHashTable *aObjects, - nsCycleCollectionTraversalCallback& cb) - : mObjects(aObjects), - mCb(cb) - { - } - PLDHashTable* mObjects; - nsCycleCollectionTraversalCallback& mCb; -}; - -static void -NoteJSRoot(JSTracer *trc, void *thing, JSGCTraceKind kind) -{ - if (AddToCCKind(kind)) { - NoteJSRootTracer *tracer = static_cast(trc); - PLDHashEntryHdr *entry = PL_DHashTableOperate(tracer->mObjects, thing, - PL_DHASH_ADD); - if (entry && !reinterpret_cast(entry)->key) { - reinterpret_cast(entry)->key = thing; - tracer->mCb.NoteRoot(nsIProgrammingLanguage::JAVASCRIPT, thing, - nsXPConnect::GetXPConnect()); - } - } else if (kind != JSTRACE_STRING) { - JS_TraceChildren(trc, thing, kind); - } -} -#endif - struct NoteWeakMapChildrenTracer : public JSTracer { NoteWeakMapChildrenTracer(nsCycleCollectionTraversalCallback &cb) @@ -538,8 +504,7 @@ TraceWeakMapping(js::WeakMapTracer *trc, JSObject *m, } nsresult -nsXPConnect::BeginCycleCollection(nsCycleCollectionTraversalCallback &cb, - bool explainLiveExpectedGarbage) +nsXPConnect::BeginCycleCollection(nsCycleCollectionTraversalCallback &cb) { // It is important not to call GetSafeJSContext while on the // cycle-collector thread since this context will be destroyed @@ -565,31 +530,6 @@ nsXPConnect::BeginCycleCollection(nsCycleCollectionTraversalCallback &cb, gcHasRun = true; } -#ifdef DEBUG_CC - NS_ASSERTION(!mJSRoots.ops, "Didn't call FinishCycleCollection?"); - - if (explainLiveExpectedGarbage) { - // Being called from nsCycleCollector::ExplainLiveExpectedGarbage. - - // Record all objects held by the JS runtime. This avoids doing a - // complete GC if we're just tracing to explain (from - // ExplainLiveExpectedGarbage), which makes the results of cycle - // collection identical for DEBUG_CC and non-DEBUG_CC builds. - if (!PL_DHashTableInit(&mJSRoots, PL_DHashGetStubOps(), nsnull, - sizeof(PLDHashEntryStub), PL_DHASH_MIN_SIZE)) { - mJSRoots.ops = nsnull; - - return NS_ERROR_OUT_OF_MEMORY; - } - - NoteJSRootTracer trc(&mJSRoots, cb); - JS_TracerInit(&trc, mCycleCollectionContext->GetJSContext(), NoteJSRoot); - JS_TraceRuntime(&trc); - } -#else - NS_ASSERTION(!explainLiveExpectedGarbage, "Didn't call nsXPConnect::Collect()?"); -#endif - GetRuntime()->AddXPConnectRoots(cb); NoteWeakMapsTracer trc(GetRuntime()->GetJSRuntime(), TraceWeakMapping, cb); @@ -641,13 +581,6 @@ nsXPConnect::FinishTraverse() nsresult nsXPConnect::FinishCycleCollection() { -#ifdef DEBUG_CC - if (mJSRoots.ops) { - PL_DHashTableFinish(&mJSRoots); - mJSRoots.ops = nsnull; - } -#endif - return NS_OK; } @@ -665,19 +598,6 @@ nsXPConnect::Root(void *p) return NS_OK; } -#ifdef DEBUG_CC -void -nsXPConnect::PrintAllReferencesTo(void *p) -{ -#ifdef DEBUG - XPCCallContext ccx(NATIVE_CALLER); - if (ccx.IsValid()) - JS_DumpHeap(ccx.GetJSContext(), stdout, nsnull, 0, p, - 0x7fffffff, nsnull); -#endif -} -#endif - NS_IMETHODIMP nsXPConnect::Unlink(void *p) { @@ -909,30 +829,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) } } - bool isMarked; - -#ifdef DEBUG_CC - // Note that the conditions under which we specify GCMarked vs. - // GCUnmarked are different between ExplainLiveExpectedGarbage and - // the normal case. In the normal case, we're saying that anything - // reachable from a JS runtime root is itself such a root. This - // doesn't actually break anything; it really just does some of the - // cycle collector's work for it. However, when debugging, we - // (1) actually need to know what the root is and (2) don't want to - // do an extra GC, so we use mJSRoots, built from JS_TraceRuntime, - // which produces a different result because we didn't call - // JS_TraceChildren to trace everything that was reachable. - if (mJSRoots.ops) { - // ExplainLiveExpectedGarbage codepath - PLDHashEntryHdr* entry = - PL_DHashTableOperate(&mJSRoots, p, PL_DHASH_LOOKUP); - isMarked = markJSObject || PL_DHASH_ENTRY_IS_BUSY(entry); - } else -#endif - { - // Normal codepath (matches non-DEBUG_CC codepath). - isMarked = markJSObject || !xpc_IsGrayGCThing(p); - } + bool isMarked = markJSObject || !xpc_IsGrayGCThing(p); if (cb.WantDebugInfo()) { char name[72]; @@ -982,8 +879,8 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) // There's no need to trace objects that have already been marked by the JS // GC. Any JS objects hanging from them will already be marked. Only do this - // if DEBUG_CC is not defined, else we do want to know about all JS objects - // to get better graphs and explanations. + // if cb.WantAllTraces() is false, otherwise we do want to know about all JS + // objects to get better graphs and explanations. if (!cb.WantAllTraces() && isMarked) return NS_OK; diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index b576bbdfb52..2bf27625e1f 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -537,16 +537,12 @@ public: virtual void NotifyEnterCycleCollectionThread(); virtual void NotifyLeaveCycleCollectionThread(); virtual void NotifyEnterMainThread(); - virtual nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb, - bool explainExpectedLiveGarbage); + virtual nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb); virtual nsresult FinishTraverse(); virtual nsresult FinishCycleCollection(); virtual nsCycleCollectionParticipant *ToParticipant(void *p); virtual bool NeedCollect(); virtual void Collect(PRUint32 reason, PRUint32 kind); -#ifdef DEBUG_CC - virtual void PrintAllReferencesTo(void *p); -#endif XPCCallContext *GetCycleCollectionContext() { @@ -598,9 +594,6 @@ private: // an 'after' notification without getting an 'on' notification. If we don't // watch out for this, we'll do an unmatched |pop| on the context stack. PRUint16 mEventDepth; -#ifdef DEBUG_CC - PLDHashTable mJSRoots; -#endif nsAutoPtr mCycleCollectionContext; typedef nsBaseHashtable, nsISupports*, nsISupports*> ScopeSet; diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 69120f07ed9..36424adea9f 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -500,17 +500,6 @@ public: }; -#ifdef DEBUG_CC - -struct ReversedEdge { - PtrInfo *mTarget; - nsCString *mEdgeName; - ReversedEdge *mNext; -}; - -#endif - - enum NodeColor { black, white, grey }; // This structure should be kept as small as possible; we may expect @@ -532,18 +521,6 @@ public: size_t mBytes; char *mName; PRUint32 mLangID; - - // For finding roots in ExplainLiveExpectedGarbage (when there are - // missing calls to suspect or failures to unlink). - PRUint32 mSCCIndex; // strongly connected component - - // For finding roots in ExplainLiveExpectedGarbage (when nodes - // expected to be garbage are black). - ReversedEdge* mReversedEdges; // linked list - PtrInfo* mShortestPathToExpectedGarbage; - nsCString* mShortestPathToExpectedGarbageEdgeName; - - nsTArray mEdgeNames; #endif PtrInfo(void *aPointer, nsCycleCollectionParticipant *aParticipant @@ -558,11 +535,7 @@ public: #ifdef DEBUG_CC , mBytes(0), mName(nsnull), - mLangID(aLangID), - mSCCIndex(0), - mReversedEdges(nsnull), - mShortestPathToExpectedGarbage(nsnull), - mShortestPathToExpectedGarbageEdgeName(nsnull) + mLangID(aLangID) #endif { } @@ -570,7 +543,6 @@ public: #ifdef DEBUG_CC void Destroy() { PL_strfree(mName); - mEdgeNames.~nsTArray(); } #endif @@ -766,9 +738,6 @@ struct GCGraph EdgePool mEdges; nsTArray mWeakMaps; PRUint32 mRootCount; -#ifdef DEBUG_CC - ReversedEdge *mReversedEdges; -#endif GCGraph() : mRootCount(0) { } @@ -911,8 +880,6 @@ public: void RemoveSkippable(bool removeChildlessNodes); #ifdef DEBUG_CC - void NoteAll(GCGraphBuilder &builder); - bool Exists(void *p) const { return mNormalObjects.GetEntry(p) || mCompatObjects.GetEntry(p); @@ -1086,8 +1053,7 @@ nsPurpleBuffer::SelectPointers(GCGraphBuilder &aBuilder) struct nsCycleCollectionXPCOMRuntime : public nsCycleCollectionLanguageRuntime { - nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb, - bool explainLiveExpectedGarbage) + nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb) { return NS_OK; } @@ -1103,10 +1069,6 @@ struct nsCycleCollectionXPCOMRuntime : } inline nsCycleCollectionParticipant *ToParticipant(void *p); - -#ifdef DEBUG_CC - virtual void PrintAllReferencesTo(void *p) {} -#endif }; struct nsCycleCollector @@ -1131,11 +1093,11 @@ struct nsCycleCollector PRUint32 mVisitedRefCounted; PRUint32 mVisitedGCed; - nsPurpleBuffer mPurpleBuf; - CC_BeforeUnlinkCallback mBeforeUnlinkCB; CC_ForgetSkippableCallback mForgetSkippableCB; + nsPurpleBuffer mPurpleBuf; + void RegisterRuntime(PRUint32 langID, nsCycleCollectionLanguageRuntime *rt); void ForgetRuntime(PRUint32 langID); @@ -1187,20 +1149,16 @@ struct nsCycleCollector #ifdef DEBUG_CC nsCycleCollectorStats mStats; - FILE *mPtrLog; + PointerSet mExpectedGarbage; void Allocated(void *n, size_t sz); void Freed(void *n); void LogPurpleRemoval(void* aObject); - void ExplainLiveExpectedGarbage(); - bool CreateReversedEdges(); - void DestroyReversedEdges(); void ShouldBeFreed(nsISupports *n); void WasFreed(nsISupports *n); - PointerSet mExpectedGarbage; #endif }; @@ -1780,9 +1738,6 @@ private: if (!childPi) return; mEdgeBuilder.Add(childPi); -#ifdef DEBUG_CC - mCurrPi->mEdgeNames.AppendElement(edgeName); -#endif if (mListener) { mListener->NoteEdge((PRUint64)child, edgeName.get()); } @@ -2183,33 +2138,6 @@ nsPurpleBuffer::RemoveSkippable(bool removeChildlessNodes) } } -#ifdef DEBUG_CC -static PLDHashOperator -noteAllCallback(nsPtrHashKey* key, void* userArg) -{ - GCGraphBuilder *builder = static_cast(userArg); - builder->NoteXPCOMRoot( - static_cast(const_cast(key->GetKey()))); - return PL_DHASH_NEXT; -} - -void -nsPurpleBuffer::NoteAll(GCGraphBuilder &builder) -{ - mCompatObjects.EnumerateEntries(noteAllCallback, &builder); - - for (Block *b = &mFirstBlock; b; b = b->mNext) { - for (nsPurpleBufferEntry *e = b->mEntries, - *eEnd = ArrayEnd(b->mEntries); - e != eEnd; ++e) { - if (!(uintptr_t(e->mObject) & uintptr_t(1)) && e->mObject) { - builder.NoteXPCOMRoot(e->mObject); - } - } - } -} -#endif - void nsCycleCollector::SelectPurple(GCGraphBuilder &builder) { @@ -2485,11 +2413,11 @@ nsCycleCollector::CollectWhite(nsICycleCollectorListener *aListener) // free. This stuff is disabled unless you set an environment variable. //////////////////////////////////////////////////////////////////////// -static bool hookedMalloc = false; - #if defined(__GLIBC__) && !defined(__UCLIBC__) #include +static bool hookedMalloc = false; + static void* (*old_memalign_hook)(size_t, size_t, const void *); static void* (*old_realloc_hook)(void *, size_t, const void *); static void* (*old_malloc_hook)(size_t, const void *); @@ -2615,6 +2543,8 @@ InitMemHook(void) #elif defined(WIN32) #ifndef __MINGW32__ +static bool hookedMalloc = false; + static int AllocHook(int allocType, void *userData, size_t size, int blockType, long requestNumber, const unsigned char *filename, int @@ -2639,6 +2569,8 @@ static void InitMemHook(void) #include +static bool hookedMalloc = false; + static void (*old_free)(struct _malloc_zone_t *zone, void *ptr); static void @@ -2684,14 +2616,14 @@ nsCycleCollector::nsCycleCollector() : mWhiteNodeCount(0), mVisitedRefCounted(0), mVisitedGCed(0), + mBeforeUnlinkCB(nsnull), + mForgetSkippableCB(nsnull), #ifdef DEBUG_CC mPurpleBuf(mParams, mStats), - mPtrLog(nsnull), + mPtrLog(nsnull) #else - mPurpleBuf(mParams), + mPurpleBuf(mParams) #endif - mBeforeUnlinkCB(nsnull), - mForgetSkippableCB(nsnull) { #ifdef DEBUG_CC mExpectedGarbage.Init(); @@ -3125,10 +3057,6 @@ nsCycleCollector::CleanupAfterCollection() Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_VISITED_REF_COUNTED, mVisitedRefCounted); Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_VISITED_GCED, mVisitedGCed); Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_COLLECTED, mWhiteNodeCount); - -#ifdef DEBUG_CC - ExplainLiveExpectedGarbage(); -#endif } void @@ -3172,7 +3100,7 @@ nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener) for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) { if (mRuntimes[i]) - mRuntimes[i]->BeginCycleCollection(builder, false); + mRuntimes[i]->BeginCycleCollection(builder); } timeLog.Checkpoint("mRuntimes[*]->BeginCycleCollection()"); @@ -3348,390 +3276,6 @@ nsCycleCollector::Shutdown() } #ifdef DEBUG_CC - -static PLDHashOperator -AddExpectedGarbage(nsPtrHashKey *p, void *arg) -{ - GCGraphBuilder *builder = static_cast(arg); - nsISupports *root = - static_cast(const_cast(p->GetKey())); - builder->NoteXPCOMRoot(root); - return PL_DHASH_NEXT; -} - -struct SetSCCVisitor -{ - SetSCCVisitor(PRUint32 aIndex) : mIndex(aIndex) {} - bool ShouldVisitNode(PtrInfo const *pi) { return pi->mSCCIndex == 0; } - void VisitNode(PtrInfo *pi) { pi->mSCCIndex = mIndex; } -private: - PRUint32 mIndex; -}; - -struct SetNonRootGreyVisitor -{ - bool ShouldVisitNode(PtrInfo const *pi) { return pi->mColor == white; } - void VisitNode(PtrInfo *pi) { pi->mColor = grey; } -}; - -static void -PrintPathToExpectedGarbage(PtrInfo *pi) -{ - printf(" An object expected to be garbage could be " - "reached from it by the path:\n"); - for (PtrInfo *path = pi, *prev = nsnull; prev != path; - prev = path, - path = path->mShortestPathToExpectedGarbage) { - if (prev) { - nsCString *edgeName = prev - ->mShortestPathToExpectedGarbageEdgeName; - printf(" via %s\n", - edgeName->IsEmpty() ? "" - : edgeName->get()); - } - printf(" %s %p\n", path->mName, path->mPointer); - } -} - -void -nsCycleCollector::ExplainLiveExpectedGarbage() -{ - if (mScanInProgress || mCollectionInProgress) - Fault("can't explain expected garbage during collection itself"); - - if (mParams.mDoNothing) { - printf("nsCycleCollector: not explaining expected garbage since\n" - " cycle collection disabled\n"); - return; - } - - mCollectionInProgress = true; - mScanInProgress = true; - - { - GCGraphBuilder builder(mGraph, mRuntimes, nsnull); - - // Instead of adding roots from the purple buffer, we add them - // from the list of nodes we were expected to collect. - // Put the expected garbage in *before* calling - // BeginCycleCollection so that we can separate the expected - // garbage from the NoteRoot calls in such a way that something - // that's in both is considered expected garbage. - mExpectedGarbage.EnumerateEntries(&AddExpectedGarbage, &builder); - - PRUint32 expectedGarbageCount = builder.Count(); - - for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) { - if (mRuntimes[i]) - mRuntimes[i]->BeginCycleCollection(builder, true); - } - - // But just for extra information, add entries from the purple - // buffer too, since it may give us extra information about - // traversal deficiencies. - mPurpleBuf.NoteAll(builder); - - MarkRoots(builder); - ScanRoots(); - - mScanInProgress = false; - - for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) { - if (mRuntimes[i]) { - mRuntimes[i]->FinishTraverse(); - } - } - - bool describeExtraRefcounts = false; - bool findCycleRoots = false; - { - NodePool::Enumerator queue(mGraph.mNodes); - PRUint32 i = 0; - while (!queue.IsDone()) { - PtrInfo *pi = queue.GetNext(); - if (pi->mColor == white) { - findCycleRoots = true; - } - - if (pi->mInternalRefs != pi->mRefCount && - (i < expectedGarbageCount || i >= mGraph.mRootCount)) { - // This check isn't particularly useful anymore - // given that we need to enter this part for i >= - // mGraph.mRootCount and there are plenty of - // NoteRoot roots. - describeExtraRefcounts = true; - } - ++i; - } - } - - if ((describeExtraRefcounts || findCycleRoots) && - CreateReversedEdges()) { - // Note that the external references may have been external - // to a different node in the cycle collection that just - // happened, if that different node was purple and then - // black. - - // Use mSCCIndex temporarily to track whether we've reached - // nodes in the breadth-first search. - const PRUint32 INDEX_UNREACHED = 0; - const PRUint32 INDEX_REACHED = 1; - NodePool::Enumerator etor_clear(mGraph.mNodes); - while (!etor_clear.IsDone()) { - PtrInfo *pi = etor_clear.GetNext(); - pi->mSCCIndex = INDEX_UNREACHED; - } - - nsDeque queue; // for breadth-first search - NodePool::Enumerator etor_roots(mGraph.mNodes); - for (PRUint32 i = 0; i < mGraph.mRootCount; ++i) { - PtrInfo *root_pi = etor_roots.GetNext(); - if (i < expectedGarbageCount) { - root_pi->mSCCIndex = INDEX_REACHED; - root_pi->mShortestPathToExpectedGarbage = root_pi; - queue.Push(root_pi); - } - } - - while (queue.GetSize() > 0) { - PtrInfo *pi = (PtrInfo*)queue.PopFront(); - for (ReversedEdge *e = pi->mReversedEdges; e; e = e->mNext) { - if (e->mTarget->mSCCIndex == INDEX_UNREACHED) { - e->mTarget->mSCCIndex = INDEX_REACHED; - PtrInfo *target = e->mTarget; - if (!target->mShortestPathToExpectedGarbage) { - target->mShortestPathToExpectedGarbage = pi; - target->mShortestPathToExpectedGarbageEdgeName = - e->mEdgeName; - } - queue.Push(target); - } - } - - if (pi->mRefCount == PR_UINT32_MAX || - (pi->mInternalRefs != pi->mRefCount && pi->mRefCount > 0)) { - if (pi->mRefCount == PR_UINT32_MAX) { - printf("nsCycleCollector: %s %p was not collected due " - "to \n" - " external references\n", - pi->mName, pi->mPointer); - } - else { - printf("nsCycleCollector: %s %p was not collected due " - "to %d\n" - " external references (%d total - %d known)\n", - pi->mName, pi->mPointer, - pi->mRefCount - pi->mInternalRefs, - pi->mRefCount, pi->mInternalRefs); - } - - PrintPathToExpectedGarbage(pi); - - if (pi->mRefCount == PR_UINT32_MAX) { - printf(" The known references to it were from:\n"); - } - else { - printf(" The %d known references to it were from:\n", - pi->mInternalRefs); - } - for (ReversedEdge *e = pi->mReversedEdges; - e; e = e->mNext) { - printf(" %s %p", - e->mTarget->mName, e->mTarget->mPointer); - if (!e->mEdgeName->IsEmpty()) { - printf(" via %s", e->mEdgeName->get()); - } - printf("\n"); - } - mRuntimes[pi->mLangID]->PrintAllReferencesTo(pi->mPointer); - } - } - - 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_TRAVERSING = 1; - const PRUint32 INDEX_NUMBERED = 2; - - NodePool::Enumerator etor_clear(mGraph.mNodes); - while (!etor_clear.IsDone()) { - PtrInfo *pi = etor_clear.GetNext(); - pi->mSCCIndex = INDEX_UNREACHED; - } - - nsDeque stack; - - NodePool::Enumerator etor_roots(mGraph.mNodes); - for (PRUint32 i = 0; i < mGraph.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_TRAVERSING; - for (EdgePool::Iterator child = pi->FirstChild(), - child_end = pi->LastChild(); - 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). - // This happens if a node is pushed on the stack - // a second time while it is on the stack in - // UNREACHED state. - if (pi->mSCCIndex == INDEX_TRAVERSING) { - pi->mSCCIndex = INDEX_NUMBERED; - DFSPostOrder.Push(pi); - } - } - } - } - - // Put the nodes into strongly-connected components. - { - NodePool::Enumerator etor_clear(mGraph.mNodes); - while (!etor_clear.IsDone()) { - PtrInfo *pi = etor_clear.GetNext(); - pi->mSCCIndex = 0; - } - - PRUint32 currentSCC = 1; - - while (DFSPostOrder.GetSize() > 0) { - GraphWalker(SetSCCVisitor(currentSCC)).Walk((PtrInfo*)DFSPostOrder.PopFront()); - ++currentSCC; - } - } - - // Mark any white nodes reachable from other components as - // grey. - { - NodePool::Enumerator queue(mGraph.mNodes); - while (!queue.IsDone()) { - PtrInfo *pi = queue.GetNext(); - if (pi->mColor != white) - continue; - for (EdgePool::Iterator child = pi->FirstChild(), - child_end = pi->LastChild(); - child != child_end; ++child) { - if ((*child)->mSCCIndex != pi->mSCCIndex) { - GraphWalker(SetNonRootGreyVisitor()).Walk(*child); - } - } - } - } - - { - NodePool::Enumerator queue(mGraph.mNodes); - while (!queue.IsDone()) { - PtrInfo *pi = queue.GetNext(); - if (pi->mColor == white) { - if (pi->mLangID == - nsIProgrammingLanguage::CPLUSPLUS && - mPurpleBuf.Exists(pi->mPointer)) { - printf( -"nsCycleCollector: %s %p in component %d\n" -" which was reference counted during the root/unlink/unroot phase of the\n" -" last collection was not collected due to failure to unlink (see other\n" -" warnings) or deficiency in traverse that causes cycles referenced only\n" -" from other cycles to require multiple rounds of cycle collection in which\n" -" this object was likely the reachable object\n", - pi->mName, pi->mPointer, pi->mSCCIndex); - } else { - printf( -"nsCycleCollector: %s %p in component %d\n" -" was not collected due to missing call to suspect, failure to unlink (see\n" -" other warnings), or deficiency in traverse that causes cycles referenced\n" -" only from other cycles to require multiple rounds of cycle collection\n", - pi->mName, pi->mPointer, pi->mSCCIndex); - } - if (pi->mShortestPathToExpectedGarbage) - PrintPathToExpectedGarbage(pi); - } - } - } - } - - DestroyReversedEdges(); - } - } - - ClearGraph(); - - mCollectionInProgress = false; - - for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) { - if (mRuntimes[i]) - mRuntimes[i]->FinishCycleCollection(); - } -} - -bool -nsCycleCollector::CreateReversedEdges() -{ - // Count the edges in the graph. - PRUint32 edgeCount = 0; - NodePool::Enumerator countQueue(mGraph.mNodes); - while (!countQueue.IsDone()) { - PtrInfo *pi = countQueue.GetNext(); - for (EdgePool::Iterator e = pi->FirstChild(), e_end = pi->LastChild(); - e != e_end; ++e, ++edgeCount) { - } - } - - // Allocate a pool to hold all of the edges. - mGraph.mReversedEdges = new ReversedEdge[edgeCount]; - if (mGraph.mReversedEdges == nsnull) { - NS_NOTREACHED("allocation failure creating reversed edges"); - return false; - } - - // Fill in the reversed edges by scanning all forward edges. - ReversedEdge *current = mGraph.mReversedEdges; - NodePool::Enumerator buildQueue(mGraph.mNodes); - while (!buildQueue.IsDone()) { - PtrInfo *pi = buildQueue.GetNext(); - PRInt32 i = 0; - for (EdgePool::Iterator e = pi->FirstChild(), e_end = pi->LastChild(); - e != e_end; ++e) { - current->mTarget = pi; - current->mEdgeName = &pi->mEdgeNames[i]; - current->mNext = (*e)->mReversedEdges; - (*e)->mReversedEdges = current; - ++current; - ++i; - } - } - NS_ASSERTION(current - mGraph.mReversedEdges == ptrdiff_t(edgeCount), - "misallocation"); - return true; -} - -void -nsCycleCollector::DestroyReversedEdges() -{ - NodePool::Enumerator queue(mGraph.mNodes); - while (!queue.IsDone()) { - PtrInfo *pi = queue.GetNext(); - pi->mReversedEdges = nsnull; - } - - delete mGraph.mReversedEdges; - mGraph.mReversedEdges = nsnull; -} - void nsCycleCollector::ShouldBeFreed(nsISupports *n) { diff --git a/xpcom/base/nsCycleCollector.h b/xpcom/base/nsCycleCollector.h index 76f4536f6d8..693dec480d4 100644 --- a/xpcom/base/nsCycleCollector.h +++ b/xpcom/base/nsCycleCollector.h @@ -38,8 +38,6 @@ #ifndef nsCycleCollector_h__ #define nsCycleCollector_h__ -// NOTE: If you use header files to define DEBUG_CC, you must do so here -// *and* in nsCycleCollectionParticipant.h //#define DEBUG_CC class nsISupports; @@ -52,14 +50,10 @@ class nsCycleCollectionTraversalCallback; struct nsCycleCollectionLanguageRuntime { - virtual nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb, - bool explainLiveExpectedGarbage) = 0; + virtual nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb) = 0; virtual nsresult FinishTraverse() = 0; virtual nsresult FinishCycleCollection() = 0; virtual nsCycleCollectionParticipant *ToParticipant(void *p) = 0; -#ifdef DEBUG_CC - virtual void PrintAllReferencesTo(void *p) = 0; -#endif }; // Contains various stats about the cycle collection. diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index 3d9fad6b66c..bd56f7e9d28 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -40,10 +40,6 @@ #include "nsISupports.h" -// NOTE: If you use header files to define DEBUG_CC, you must do so here -// *and* in nsCycleCollector.h -//#define DEBUG_CC - #define NS_CYCLECOLLECTIONPARTICIPANT_IID \ { \ 0x9674489b, \