Bug 903548 - GC: What do we do for UnmarkGray on a Nursery GCThing? r=billm

This commit is contained in:
Jon Coppeard 2013-08-19 14:48:35 +01:00
parent 9552f14f02
commit d54dda2c97
5 changed files with 53 additions and 20 deletions

View File

@ -256,7 +256,7 @@ class ObjectPtr
* Unsets the gray bit for anything reachable from |thing|. |kind| should not be * Unsets the gray bit for anything reachable from |thing|. |kind| should not be
* JSTRACE_SHAPE. |thing| should be non-null. * JSTRACE_SHAPE. |thing| should be non-null.
*/ */
extern JS_FRIEND_API(void) extern JS_FRIEND_API(bool)
UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind); UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind);
/* /*

View File

@ -128,6 +128,16 @@ GetObjectZone(JSObject *obj)
static JS_ALWAYS_INLINE bool static JS_ALWAYS_INLINE bool
GCThingIsMarkedGray(void *thing) GCThingIsMarkedGray(void *thing)
{ {
#ifdef JSGC_GENERATIONAL
/*
* GC things residing in the nursery cannot be gray: they have no mark bits.
* All live objects in the nursery are moved to tenured at the beginning of
* each GC slice, so the gray marker never sees nursery things.
*/
JS::shadow::Runtime *rt = js::gc::GetGCThingRuntime(thing);
if (uintptr_t(thing) >= rt->gcNurseryStart_ && uintptr_t(thing) < rt->gcNurseryEnd_)
return false;
#endif
uintptr_t *word, mask; uintptr_t *word, mask;
js::gc::GetGCThingMarkWordAndMask(thing, js::gc::GRAY, &word, &mask); js::gc::GetGCThingMarkWordAndMask(thing, js::gc::GRAY, &word, &mask);
return *word & mask; return *word & mask;

View File

@ -651,10 +651,15 @@ ShouldMarkCrossCompartment(JSTracer *trc, JSObject *src, Cell *cell)
if (!IS_GC_MARKING_TRACER(trc)) if (!IS_GC_MARKING_TRACER(trc))
return true; return true;
JS::Zone *zone = cell->tenuredZone();
uint32_t color = AsGCMarker(trc)->getMarkColor(); uint32_t color = AsGCMarker(trc)->getMarkColor();
JS_ASSERT(color == BLACK || color == GRAY); JS_ASSERT(color == BLACK || color == GRAY);
if (IsInsideNursery(trc->runtime, cell)) {
JS_ASSERT(color == BLACK);
return false;
}
JS::Zone *zone = cell->tenuredZone();
if (color == BLACK) { if (color == BLACK) {
/* /*
* Having black->gray edges violates our promise to the cycle * Having black->gray edges violates our promise to the cycle
@ -1578,14 +1583,14 @@ struct UnmarkGrayTracer : public JSTracer
* up any color mismatches involving weakmaps when it runs. * up any color mismatches involving weakmaps when it runs.
*/ */
UnmarkGrayTracer(JSRuntime *rt) UnmarkGrayTracer(JSRuntime *rt)
: tracingShape(false), previousShape(NULL) : tracingShape(false), previousShape(NULL), unmarkedAny(false)
{ {
JS_TracerInit(this, rt, UnmarkGrayChildren); JS_TracerInit(this, rt, UnmarkGrayChildren);
eagerlyTraceWeakMaps = DoNotTraceWeakMaps; eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
} }
UnmarkGrayTracer(JSTracer *trc, bool tracingShape) UnmarkGrayTracer(JSTracer *trc, bool tracingShape)
: tracingShape(tracingShape), previousShape(NULL) : tracingShape(tracingShape), previousShape(NULL), unmarkedAny(false)
{ {
JS_TracerInit(this, trc->runtime, UnmarkGrayChildren); JS_TracerInit(this, trc->runtime, UnmarkGrayChildren);
eagerlyTraceWeakMaps = DoNotTraceWeakMaps; eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
@ -1596,6 +1601,9 @@ struct UnmarkGrayTracer : public JSTracer
/* If tracingShape, shape child or NULL. Otherwise, NULL. */ /* If tracingShape, shape child or NULL. Otherwise, NULL. */
void *previousShape; void *previousShape;
/* Whether we unmarked anything. */
bool unmarkedAny;
}; };
/* /*
@ -1642,10 +1650,14 @@ UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind)
return; return;
} }
if (!JS::GCThingIsMarkedGray(thing)) UnmarkGrayTracer *tracer = static_cast<UnmarkGrayTracer *>(trc);
return; if (!IsInsideNursery(trc->runtime, thing)) {
if (!JS::GCThingIsMarkedGray(thing))
return;
UnmarkGrayGCThing(thing); UnmarkGrayGCThing(thing);
tracer->unmarkedAny = true;
}
/* /*
* Trace children of |thing|. If |thing| and its parent are both shapes, * Trace children of |thing|. If |thing| and its parent are both shapes,
@ -1654,12 +1666,12 @@ UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind)
* depth during shape tracing. It is safe to do because a shape can only * depth during shape tracing. It is safe to do because a shape can only
* have one child that is a shape. * have one child that is a shape.
*/ */
UnmarkGrayTracer *tracer = static_cast<UnmarkGrayTracer *>(trc);
UnmarkGrayTracer childTracer(tracer, kind == JSTRACE_SHAPE); UnmarkGrayTracer childTracer(tracer, kind == JSTRACE_SHAPE);
if (kind != JSTRACE_SHAPE) { if (kind != JSTRACE_SHAPE) {
JS_TraceChildren(&childTracer, thing, kind); JS_TraceChildren(&childTracer, thing, kind);
JS_ASSERT(!childTracer.previousShape); JS_ASSERT(!childTracer.previousShape);
tracer->unmarkedAny |= childTracer.unmarkedAny;
return; return;
} }
@ -1675,19 +1687,27 @@ UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind)
thing = childTracer.previousShape; thing = childTracer.previousShape;
childTracer.previousShape = NULL; childTracer.previousShape = NULL;
} while (thing); } while (thing);
tracer->unmarkedAny |= childTracer.unmarkedAny;
} }
JS_FRIEND_API(void) JS_FRIEND_API(bool)
JS::UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind) JS::UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind)
{ {
JS_ASSERT(kind != JSTRACE_SHAPE); JS_ASSERT(kind != JSTRACE_SHAPE);
if (!JS::GCThingIsMarkedGray(thing))
return;
UnmarkGrayGCThing(thing);
JSRuntime *rt = static_cast<Cell *>(thing)->runtimeFromMainThread(); JSRuntime *rt = static_cast<Cell *>(thing)->runtimeFromMainThread();
bool unmarkedArg = false;
if (!IsInsideNursery(rt, thing)) {
if (!JS::GCThingIsMarkedGray(thing))
return false;
UnmarkGrayGCThing(thing);
unmarkedArg = true;
}
UnmarkGrayTracer trc(rt); UnmarkGrayTracer trc(rt);
JS_TraceChildren(&trc, thing, kind); JS_TraceChildren(&trc, thing, kind);
return unmarkedArg || trc.unmarkedAny;
} }

View File

@ -591,10 +591,11 @@ js::GCThingTraceKind(void *thing)
JS_FRIEND_API(void) JS_FRIEND_API(void)
js::VisitGrayWrapperTargets(Zone *zone, GCThingCallback callback, void *closure) js::VisitGrayWrapperTargets(Zone *zone, GCThingCallback callback, void *closure)
{ {
JSRuntime *rt = zone->runtimeFromMainThread();
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) { for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
gc::Cell *thing = e.front().key.wrapped; gc::Cell *thing = e.front().key.wrapped;
if (thing->isMarked(gc::GRAY)) if (!IsInsideNursery(rt, thing) && thing->isMarked(gc::GRAY))
callback(closure, thing); callback(closure, thing);
} }
} }

View File

@ -258,8 +258,9 @@ private:
if (delegateMightNeedMarking && kkind == JSTRACE_OBJECT) { if (delegateMightNeedMarking && kkind == JSTRACE_OBJECT) {
JSObject* kdelegate = js::GetWeakmapKeyDelegate((JSObject*)k); JSObject* kdelegate = js::GetWeakmapKeyDelegate((JSObject*)k);
if (kdelegate && !xpc_IsGrayGCThing(kdelegate)) { if (kdelegate && !xpc_IsGrayGCThing(kdelegate)) {
JS::UnmarkGrayGCThingRecursively(k, JSTRACE_OBJECT); if (JS::UnmarkGrayGCThingRecursively(k, JSTRACE_OBJECT)) {
tracer->mAnyMarked = true; tracer->mAnyMarked = true;
}
} }
} }
@ -267,8 +268,9 @@ private:
(!k || !xpc_IsGrayGCThing(k)) && (!k || !xpc_IsGrayGCThing(k)) &&
(!m || !xpc_IsGrayGCThing(m)) && (!m || !xpc_IsGrayGCThing(m)) &&
vkind != JSTRACE_SHAPE) { vkind != JSTRACE_SHAPE) {
JS::UnmarkGrayGCThingRecursively(v, vkind); if (JS::UnmarkGrayGCThingRecursively(v, vkind)) {
tracer->mAnyMarked = true; tracer->mAnyMarked = true;
}
} }
} }