Bug 787905 - GC: SweepBackgroundThings can be called with freed compartments in list r=billm

This commit is contained in:
Jon Coppeard 2012-09-12 10:52:19 +01:00
parent 5a2eb2a9cd
commit fb88cce090

View File

@ -3204,10 +3204,10 @@ ReleaseObservedTypes(JSRuntime *rt)
}
static void
SweepCompartments(FreeOp *fop, gcreason::Reason gcReason)
SweepCompartments(FreeOp *fop, bool lastGC)
{
JSRuntime *rt = fop->runtime();
JS_ASSERT_IF(gcReason == gcreason::LAST_CONTEXT, !rt->hasContexts());
JS_ASSERT_IF(lastGC, !rt->hasContexts());
JSDestroyCompartmentCallback callback = rt->destroyCompartmentCallback;
@ -3222,7 +3222,7 @@ SweepCompartments(FreeOp *fop, gcreason::Reason gcReason)
JSCompartment *compartment = *read++;
if (!compartment->hold && compartment->wasGCStarted() &&
(compartment->arenas.arenaListsAreEmpty() || gcReason == gcreason::LAST_CONTEXT))
(compartment->arenas.arenaListsAreEmpty() || lastGC))
{
compartment->arenas.checkEmptyFreeLists();
if (callback)
@ -3899,11 +3899,13 @@ SweepAtomsCompartment(JSRuntime *rt)
}
static void
EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, gcreason::Reason gcReason)
EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC)
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP);
FreeOp fop(rt, rt->gcSweepOnBackgroundThread);
JS_ASSERT_IF(lastGC, !rt->gcSweepOnBackgroundThread);
JS_ASSERT(rt->gcMarker.isDrained());
rt->gcMarker.stop();
@ -3911,23 +3913,9 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, gcreason::Reason gcReaso
PropertyTree::dumpShapes(rt);
#endif
/*
* Set up list of compartments for sweeping of background things.
*/
JS_ASSERT(!rt->gcSweepingCompartments);
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
c->gcNextCompartment = rt->gcSweepingCompartments;
rt->gcSweepingCompartments = c;
}
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DESTROY);
if (!rt->gcSweepOnBackgroundThread) {
rt->freeLifoAlloc.freeAll();
SweepBackgroundThings(rt, false);
}
/*
* Sweep script filenames after sweeping functions in the generic loop
* above. In this way when a scripted function's finalizer destroys the
@ -3941,7 +3929,8 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, gcreason::Reason gcReaso
* This removes compartments from rt->compartment, so we do it last to make
* sure we don't miss sweeping any compartments.
*/
SweepCompartments(&fop, gcReason);
if (!lastGC)
SweepCompartments(&fop, lastGC);
#ifndef JS_THREADSAFE
/*
@ -3961,6 +3950,26 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, gcreason::Reason gcReaso
arena->unsetAllocDuringSweep();
}
/* Set up list of compartments for sweeping of background things. */
JS_ASSERT(!rt->gcSweepingCompartments);
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
c->gcNextCompartment = rt->gcSweepingCompartments;
rt->gcSweepingCompartments = c;
}
/* If not sweeping on background thread then we must do it here. */
if (!rt->gcSweepOnBackgroundThread) {
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DESTROY);
SweepBackgroundThings(rt, false);
rt->freeLifoAlloc.freeAll();
/* Ensure the compartments get swept if it's the last GC. */
if (lastGC)
SweepCompartments(&fop, lastGC);
}
for (CompartmentsIter c(rt); !c.done(); c.next()) {
c->setGCLastBytes(c->gcBytes, c->gcMallocAndFreeBytes, gckind);
if (c->wasGCStarted())
@ -4305,7 +4314,7 @@ IncrementalCollectSlice(JSRuntime *rt,
break;
}
EndSweepPhase(rt, gckind, reason);
EndSweepPhase(rt, gckind, reason == gcreason::LAST_CONTEXT);
if (rt->gcSweepOnBackgroundThread)
rt->gcHelperThread.startBackgroundSweep(gckind == GC_SHRINK);