From 5ffb98df92a5bfb878ecde00551f2b951c51aa45 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 13 Jun 2011 13:24:23 -0700 Subject: [PATCH] Bug 663532 - Run GC from cycle collector in main thread, not CC thread. r=bent --- xpcom/base/nsCycleCollector.cpp | 66 ++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 3e2897b4c3b..317ef6f7b8a 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -1047,12 +1047,12 @@ struct nsCycleCollector nsICycleCollectorListener *aListener); // Prepare for and cleanup after one or more collection(s). - PRBool PrepareForCollection(nsTPtrArray *aWhiteNodes); + PRBool PrepareForCollection(nsTPtrArray *aWhiteNodes, + PRBool aForceGC); void CleanupAfterCollection(); // Start and finish an individual collection. - PRBool BeginCollection(PRBool aForceGC, - nsICycleCollectorListener *aListener); + PRBool BeginCollection(nsICycleCollectorListener *aListener); PRBool FinishCollection(); PRUint32 SuspectedCount(); @@ -2499,8 +2499,12 @@ nsCycleCollector::Freed(void *n) #endif PRBool -nsCycleCollector::PrepareForCollection(nsTPtrArray *aWhiteNodes) +nsCycleCollector::PrepareForCollection(nsTPtrArray *aWhiteNodes, + PRBool aForceGC) { + NS_ASSERTION(NS_IsMainThread(), + "PrepareForCollection must be called on the main thread."); + #if defined(DEBUG_CC) && !defined(__MINGW32__) if (!mParams.mDoNothing && mParams.mHookMalloc) InitMemHook(); @@ -2529,6 +2533,29 @@ nsCycleCollector::PrepareForCollection(nsTPtrArray *aWhiteNodes) mWhiteNodes = aWhiteNodes; + // The cycle collector uses the mark bitmap to discover what JS objects + // were reachable only from XPConnect roots that might participate in + // cycles. We ask the JS runtime whether we need to force a GC before + // this CC. It returns true on startup (before the mark bits have been set), + // and also when UnmarkGray has run out of stack. + if (mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]) { + nsCycleCollectionJSRuntime* rt = + static_cast + (mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]); + if (rt->NeedCollect() || aForceGC) { +#ifdef COLLECT_TIME_DEBUG + PRTime start = PR_Now(); +#endif + // rt->Collect() must be called from the main thread, + // because it invokes XPCJSRuntime::GCCallback(cx, JSGC_BEGIN) + // which returns false if not in the main thread. + rt->Collect(); +#ifdef COLLECT_TIME_DEBUG + printf("cc: GC() took %lldms\n", (PR_Now() - start) / PR_USEC_PER_MSEC); +#endif + } + } + return PR_TRUE; } @@ -2563,13 +2590,13 @@ nsCycleCollector::Collect(PRUint32 aTryCollections, { nsAutoTPtrArray whiteNodes; - if (!PrepareForCollection(&whiteNodes)) + if (!PrepareForCollection(&whiteNodes, PR_TRUE)) return 0; PRUint32 totalCollections = 0; while (aTryCollections > totalCollections) { // Synchronous cycle collection. Always force a JS GC as well. - if (!(BeginCollection(PR_TRUE, aListener) && FinishCollection())) + if (!(BeginCollection(aListener) && FinishCollection())) break; ++totalCollections; @@ -2581,32 +2608,11 @@ nsCycleCollector::Collect(PRUint32 aTryCollections, } PRBool -nsCycleCollector::BeginCollection(PRBool aForceGC, - nsICycleCollectorListener *aListener) +nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener) { if (mParams.mDoNothing) return PR_FALSE; - // The cycle collector uses the mark bitmap to discover what JS objects - // were reachable only from XPConnect roots that might participate in - // cycles. We ask the JS runtime whether we need to force a GC before - // this CC. It returns true on startup (before the mark bits have been set), - // and also when UnmarkGray has run out of stack. - if (mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]) { - nsCycleCollectionJSRuntime* rt = - static_cast - (mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]); - if (rt->NeedCollect() || aForceGC) { -#ifdef COLLECT_TIME_DEBUG - PRTime start = PR_Now(); -#endif - rt->Collect(); -#ifdef COLLECT_TIME_DEBUG - printf("cc: GC() took %lldms\n", (PR_Now() - start) / PR_USEC_PER_MSEC); -#endif - } - } - if (aListener && NS_FAILED(aListener->Begin())) { aListener = nsnull; } @@ -3358,7 +3364,7 @@ public: return NS_OK; } - mCollected = mCollector->BeginCollection(PR_FALSE, mListener); + mCollected = mCollector->BeginCollection(mListener); mReply.Notify(); } @@ -3389,7 +3395,7 @@ public: return 0; nsAutoTPtrArray whiteNodes; - if (!mCollector->PrepareForCollection(&whiteNodes)) + if (!mCollector->PrepareForCollection(&whiteNodes, PR_FALSE)) return 0; NS_ASSERTION(!mListener, "Should have cleared this already!");