Bug 690970, part 3: fix black-gray edges in weak containers at start of CC. r=billm

This commit is contained in:
Andrew McCreight 2013-01-08 10:36:51 -08:00
parent 27baaa4757
commit ecb75d0a95
4 changed files with 80 additions and 6 deletions

View File

@ -473,6 +473,72 @@ TraceWeakMapping(js::WeakMapTracer *trc, JSObject *m,
}
}
// This is based on the logic in TraceWeakMapping.
struct FixWeakMappingGrayBitsTracer : public js::WeakMapTracer
{
FixWeakMappingGrayBitsTracer(JSRuntime *rt)
: js::WeakMapTracer(rt, FixWeakMappingGrayBits)
{}
void
FixAll()
{
do {
mAnyMarked = false;
js::TraceWeakMaps(this);
} while (mAnyMarked);
}
private:
static void
FixWeakMappingGrayBits(js::WeakMapTracer *trc, JSObject *m,
void *k, JSGCTraceKind kkind,
void *v, JSGCTraceKind vkind)
{
MOZ_ASSERT(!js::IsIncrementalBarrierNeeded(trc->runtime),
"Don't call FixWeakMappingGrayBits during a GC.");
FixWeakMappingGrayBitsTracer *tracer = static_cast<FixWeakMappingGrayBitsTracer*>(trc);
// If nothing that could be held alive by this entry is marked gray, return.
bool delegateMightNeedMarking = k && xpc_IsGrayGCThing(k);
bool valueMightNeedMarking = v && xpc_IsGrayGCThing(v) && vkind != JSTRACE_STRING;
if (!delegateMightNeedMarking && !valueMightNeedMarking)
return;
if (!AddToCCKind(kkind))
k = nullptr;
if (delegateMightNeedMarking && kkind == JSTRACE_OBJECT) {
JSObject *kdelegate = js::GetWeakmapKeyDelegate((JSObject *)k);
if (kdelegate && !xpc_IsGrayGCThing(kdelegate)) {
js::UnmarkGrayGCThingRecursively(k, JSTRACE_OBJECT);
tracer->mAnyMarked = true;
}
}
if (v && xpc_IsGrayGCThing(v) &&
(!k || !xpc_IsGrayGCThing(k)) &&
(!m || !xpc_IsGrayGCThing(m)) &&
vkind != JSTRACE_SHAPE)
{
js::UnmarkGrayGCThingRecursively(v, vkind);
tracer->mAnyMarked = true;
}
}
bool mAnyMarked;
};
void
nsXPConnect::FixWeakMappingGrayBits()
{
FixWeakMappingGrayBitsTracer fixer(GetRuntime()->GetJSRuntime());
fixer.FixAll();
}
nsresult
nsXPConnect::BeginCycleCollection(nsCycleCollectionTraversalCallback &cb)
{

View File

@ -525,7 +525,7 @@ public:
nsresult GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info);
nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info);
// nsCycleCollectionLanguageRuntime
// nsCycleCollectionJSRuntime
virtual bool NotifyLeaveMainThread();
virtual void NotifyEnterCycleCollectionThread();
virtual void NotifyLeaveCycleCollectionThread();
@ -533,6 +533,7 @@ public:
virtual nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb);
virtual nsresult FinishTraverse();
virtual nsCycleCollectionParticipant *GetParticipant();
virtual void FixWeakMappingGrayBits();
virtual bool NeedCollect();
virtual void Collect(uint32_t reason);

View File

@ -1070,7 +1070,7 @@ struct nsCycleCollector
// Prepare for and cleanup after one or more collection(s).
bool PrepareForCollection(nsCycleCollectorResults *aResults,
nsTArray<PtrInfo*> *aWhiteNodes);
void GCIfNeeded(bool aForceGC);
void FixGrayBits(bool aForceGC);
void CleanupAfterCollection();
// Start and finish an individual collection.
@ -2699,10 +2699,10 @@ nsCycleCollector::LogPurpleRemoval(void* aObject)
// and also when UnmarkGray has run out of stack. We also force GCs on shut
// down to collect cycles involving both DOM and JS.
void
nsCycleCollector::GCIfNeeded(bool aForceGC)
nsCycleCollector::FixGrayBits(bool aForceGC)
{
MOZ_ASSERT(NS_IsMainThread(),
"nsCycleCollector::GCIfNeeded() must be called on the main thread.");
"nsCycleCollector::FixGrayBits() must be called on the main thread.");
if (mParams.mDoNothing)
return;
@ -2711,6 +2711,8 @@ nsCycleCollector::GCIfNeeded(bool aForceGC)
return;
if (!aForceGC) {
mJSRuntime->FixWeakMappingGrayBits();
bool needGC = mJSRuntime->NeedCollect();
// Only do a telemetry ping for non-shutdown CCs.
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_NEED_GC, needGC);
@ -2811,7 +2813,7 @@ nsCycleCollector::Collect(bool aMergeCompartments,
uint32_t totalCollections = 0;
while (aTryCollections > totalCollections) {
// Synchronous cycle collection. Always force a JS GC beforehand.
GCIfNeeded(true);
FixGrayBits(true);
if (aListener && NS_FAILED(aListener->Begin()))
aListener = nullptr;
if (!(BeginCollection(aMergeCompartments, aListener) &&
@ -3272,7 +3274,7 @@ public:
if (aListener) {
aListener->GetWantAllTraces(&wantAllTraces);
}
mCollector->GCIfNeeded(wantAllTraces);
mCollector->FixGrayBits(wantAllTraces);
MutexAutoLock autoLock(mLock);

View File

@ -67,6 +67,11 @@ struct nsCycleCollectionJSRuntime
virtual void NotifyLeaveCycleCollectionThread() = 0;
virtual void NotifyEnterMainThread() = 0;
/**
* Unmark gray any weak map values, as needed.
*/
virtual void FixWeakMappingGrayBits() = 0;
/**
* Should we force a JavaScript GC before a CC?
*/