Bug 663532 - Run GC from cycle collector in main thread, not CC thread. r=bent

This commit is contained in:
Andrew McCreight 2011-06-13 13:24:23 -07:00
Родитель 38d068a45d
Коммит 81ec3bd93a
1 изменённых файлов: 36 добавлений и 30 удалений

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

@ -1047,12 +1047,12 @@ struct nsCycleCollector
nsICycleCollectorListener *aListener); nsICycleCollectorListener *aListener);
// Prepare for and cleanup after one or more collection(s). // Prepare for and cleanup after one or more collection(s).
PRBool PrepareForCollection(nsTPtrArray<PtrInfo> *aWhiteNodes); PRBool PrepareForCollection(nsTPtrArray<PtrInfo> *aWhiteNodes,
PRBool aForceGC);
void CleanupAfterCollection(); void CleanupAfterCollection();
// Start and finish an individual collection. // Start and finish an individual collection.
PRBool BeginCollection(PRBool aForceGC, PRBool BeginCollection(nsICycleCollectorListener *aListener);
nsICycleCollectorListener *aListener);
PRBool FinishCollection(); PRBool FinishCollection();
PRUint32 SuspectedCount(); PRUint32 SuspectedCount();
@ -2499,8 +2499,12 @@ nsCycleCollector::Freed(void *n)
#endif #endif
PRBool PRBool
nsCycleCollector::PrepareForCollection(nsTPtrArray<PtrInfo> *aWhiteNodes) nsCycleCollector::PrepareForCollection(nsTPtrArray<PtrInfo> *aWhiteNodes,
PRBool aForceGC)
{ {
NS_ASSERTION(NS_IsMainThread(),
"PrepareForCollection must be called on the main thread.");
#if defined(DEBUG_CC) && !defined(__MINGW32__) #if defined(DEBUG_CC) && !defined(__MINGW32__)
if (!mParams.mDoNothing && mParams.mHookMalloc) if (!mParams.mDoNothing && mParams.mHookMalloc)
InitMemHook(); InitMemHook();
@ -2529,6 +2533,29 @@ nsCycleCollector::PrepareForCollection(nsTPtrArray<PtrInfo> *aWhiteNodes)
mWhiteNodes = 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<nsCycleCollectionJSRuntime*>
(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; return PR_TRUE;
} }
@ -2563,13 +2590,13 @@ nsCycleCollector::Collect(PRUint32 aTryCollections,
{ {
nsAutoTPtrArray<PtrInfo, 4000> whiteNodes; nsAutoTPtrArray<PtrInfo, 4000> whiteNodes;
if (!PrepareForCollection(&whiteNodes)) if (!PrepareForCollection(&whiteNodes, PR_TRUE))
return 0; return 0;
PRUint32 totalCollections = 0; PRUint32 totalCollections = 0;
while (aTryCollections > totalCollections) { while (aTryCollections > totalCollections) {
// Synchronous cycle collection. Always force a JS GC as well. // Synchronous cycle collection. Always force a JS GC as well.
if (!(BeginCollection(PR_TRUE, aListener) && FinishCollection())) if (!(BeginCollection(aListener) && FinishCollection()))
break; break;
++totalCollections; ++totalCollections;
@ -2581,32 +2608,11 @@ nsCycleCollector::Collect(PRUint32 aTryCollections,
} }
PRBool PRBool
nsCycleCollector::BeginCollection(PRBool aForceGC, nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener)
nsICycleCollectorListener *aListener)
{ {
if (mParams.mDoNothing) if (mParams.mDoNothing)
return PR_FALSE; 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<nsCycleCollectionJSRuntime*>
(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())) { if (aListener && NS_FAILED(aListener->Begin())) {
aListener = nsnull; aListener = nsnull;
} }
@ -3358,7 +3364,7 @@ public:
return NS_OK; return NS_OK;
} }
mCollected = mCollector->BeginCollection(PR_FALSE, mListener); mCollected = mCollector->BeginCollection(mListener);
mReply.Notify(); mReply.Notify();
} }
@ -3389,7 +3395,7 @@ public:
return 0; return 0;
nsAutoTPtrArray<PtrInfo, 4000> whiteNodes; nsAutoTPtrArray<PtrInfo, 4000> whiteNodes;
if (!mCollector->PrepareForCollection(&whiteNodes)) if (!mCollector->PrepareForCollection(&whiteNodes, PR_FALSE))
return 0; return 0;
NS_ASSERTION(!mListener, "Should have cleared this already!"); NS_ASSERTION(!mListener, "Should have cleared this already!");