bug 574313 - checking that autoroots are conservatively scanned and aborting if not. The check is enabled in optimized build for better test coverage. r=anygregor

This commit is contained in:
Igor Bukanov 2010-07-26 10:24:27 +02:00
parent ce4483243e
commit d3c1879bc0
2 changed files with 67 additions and 6 deletions

View File

@ -2300,6 +2300,7 @@ class AutoGCRooter {
# pragma GCC visibility push(default)
#endif
friend void ::js_TraceContext(JSTracer *trc, JSContext *acx);
friend void ::js_TraceRuntime(JSTracer *trc);
#ifdef __GNUC__
# pragma GCC visibility pop
#endif
@ -2427,6 +2428,7 @@ class AutoValueRooter : private AutoGCRooter
}
friend void AutoGCRooter::trace(JSTracer *trc);
friend void ::js_TraceRuntime(JSTracer *trc);
private:
Value val;
@ -2455,6 +2457,7 @@ class AutoObjectRooter : private AutoGCRooter {
}
friend void AutoGCRooter::trace(JSTracer *trc);
friend void ::js_TraceRuntime(JSTracer *trc);
private:
JSObject *obj;
@ -2535,6 +2538,7 @@ class AutoScopePropertyRooter : private AutoGCRooter {
}
friend void AutoGCRooter::trace(JSTracer *trc);
friend void ::js_TraceRuntime(JSTracer *trc);
private:
JSScopeProperty * const sprop;
@ -2580,6 +2584,7 @@ class AutoIdRooter : private AutoGCRooter
}
friend void AutoGCRooter::trace(JSTracer *trc);
friend void ::js_TraceRuntime(JSTracer *trc);
private:
jsid id_;
@ -2678,6 +2683,7 @@ class AutoXMLRooter : private AutoGCRooter {
}
friend void AutoGCRooter::trace(JSTracer *trc);
friend void ::js_TraceRuntime(JSTracer *trc);
private:
JSXML * const xml;

View File

@ -2484,6 +2484,64 @@ js_TraceRuntime(JSTracer *trc)
{
JSRuntime *rt = trc->context->runtime;
if (rt->state != JSRTS_LANDING)
ConservativeGCStackMarker(trc).markRoots();
/*
* Verify that we do not have at this point unmarked GC things stored in
* autorooters. To maximize test coverage we abort even in non-debug
* builds for now, see bug 574313.
*/
JSContext *iter;
#if 1
iter = NULL;
while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter)) {
for (AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) {
#ifdef JS_THREADSAFE
JS_ASSERT(acx->outstandingRequests != 0);
#endif
void *thing;
switch (gcr->tag) {
default:
continue;
case AutoGCRooter::JSVAL: {
const Value &v = static_cast<AutoValueRooter *>(gcr)->val;
if (!v.isMarkable())
continue;
thing = v.asGCThing();
break;
}
case AutoGCRooter::XML:
thing = static_cast<AutoXMLRooter *>(gcr)->xml;
break;
case AutoGCRooter::OBJECT:
thing = static_cast<AutoObjectRooter *>(gcr)->obj;
if (!thing)
continue;
break;
case AutoGCRooter::ID: {
jsid id = static_cast<AutoIdRooter *>(gcr)->id();
if (!JSID_IS_GCTHING(id))
continue;
thing = JSID_TO_GCTHING(id);
break;
}
}
if (JSString::isStatic(thing))
continue;
if (!IsMarkedGCThing(thing)) {
fprintf(stderr,
"Conservative GC scanner has missed the root %p with tag %lu"
" on the stack. Aborting.\n", thing, (unsigned long) gcr->tag);
JS_ASSERT(false);
abort();
}
}
}
#endif
for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront())
gc_root_traversal(trc, r.front());
@ -2493,7 +2551,7 @@ js_TraceRuntime(JSTracer *trc)
js_TraceAtomState(trc);
js_MarkTraps(trc);
JSContext *iter = NULL;
iter = NULL;
while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter))
js_TraceContext(trc, acx);
@ -2501,12 +2559,9 @@ js_TraceRuntime(JSTracer *trc)
i.threadData()->mark(trc);
/*
* The conservative stack scanner runs before we mark extra roots,
* which may use additional colors to implement cycle collection.
* We mark extra roots at the last thing so it can use use additional
* colors to implement cycle collection.
*/
if (rt->state != JSRTS_LANDING)
ConservativeGCStackMarker(trc).markRoots();
if (rt->gcExtraRootsTraceOp)
rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);