Bug 793823 - Exactly root Bindings when on the stack; r=billm

Currently, we rely on the marking of the origin script to keep the stack
binding's data live. This will not work with a moving GC.
This commit is contained in:
Terrence Cole 2012-09-24 15:18:34 -07:00
parent 8a1b0e1843
commit 7b707cf94e
4 changed files with 75 additions and 42 deletions

View File

@ -959,44 +959,47 @@ InFreeList(ArenaHeader *aheader, uintptr_t addr)
} }
#ifdef JSGC_USE_EXACT_ROOTING #ifdef JSGC_USE_EXACT_ROOTING
static inline void
MarkExactStackRooter(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind)
{
void **addr = (void **)rooter->address();
if (!*addr)
return;
switch (kind) {
case THING_ROOT_OBJECT: MarkObjectRoot(trc, (JSObject **)addr, "exact-object"); break;
case THING_ROOT_STRING: MarkStringRoot(trc, (JSSTring **)addr, "exact-string"); break;
case THING_ROOT_SCRIPT: MarkScriptRoot(trc, (JSScript **)addr, "exact-script"); break;
case THING_ROOT_SHAPE: MarkShapeRoot(trc, (Shape **)addr, "exact-shape"); break;
case THING_ROOT_BASE_SHAPE: MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact-baseshape"); break;
case THING_ROOT_TYPE: MarkTypeRoot(trc, (types::Type *)addr, "exact-type"); break;
case THING_ROOT_TYPE_OBJECT: MarkTypeObjectRoot(trc, (types::TypeObject **)addr, "exact-typeobject"); break;
case THING_ROOT_VALUE: MarkValueRoot(trc, (Value *)addr, "exact-value"); break;
case THING_ROOT_ID: MarkIdRoot(trc, (jsid *)addr, "exact-id"); break;
case THING_ROOT_PROPERTY_ID: MarkIdRoot(trc, &((js::PropertyId *)addr)->asId(), "exact-propertyid"); break;
case THING_ROOT_BINDINGS: ((Bindings *)addr)->trace(trc); break;
default: JS_NOT_REACHED("Invalid THING_ROOT kind"); break;
}
}
static inline void
MarkExactStackRooters(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind)
{
Rooted<void*> *rooter = cx->thingGCRooters[i];
while (rooter) {
MarkExactStackRoot(trc, rooter, ThingRootKind(i));
rooter = rooter->previous();
}
}
static void static void
MarkExactStackRoots(JSTracer *trc) MarkExactStackRoots(JSTracer *trc)
{ {
for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) { for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) { for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
Rooted<void*> *rooter = cx->thingGCRooters[i]; MarkExactStackRooters(trc, cx->thingGCRooters[i], ThingRootKind(i));
while (rooter) {
void **addr = (void **)rooter->address();
if (*addr) {
if (i == THING_ROOT_OBJECT) {
MarkObjectRoot(trc, (JSObject **)addr, "exact stackroot object");
} else if (i == THING_ROOT_STRING) {
MarkStringRoot(trc, (JSString **)addr, "exact stackroot string");
} else if (i == THING_ROOT_ID) {
MarkIdRoot(trc, (jsid *)addr, "exact stackroot id");
} else if (i == THING_ROOT_PROPERTY_ID) {
MarkIdRoot(trc, &((PropertyId *)addr)->asId(), "exact stackroot property id");
} else if (i == THING_ROOT_VALUE) {
MarkValueRoot(trc, (Value *)addr, "exact stackroot value");
} else if (i == THING_ROOT_TYPE) {
MarkTypeRoot(trc, (types::Type *)addr, "exact stackroot type");
} else if (i == THING_ROOT_SHAPE) {
MarkShapeRoot(trc, (Shape **)addr, "exact stackroot shape");
} else if (i == THING_ROOT_BASE_SHAPE) {
MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact stackroot baseshape");
} else if (i == THING_ROOT_TYPE_OBJECT) {
MarkTypeObjectRoot(trc, (types::TypeObject **)addr, "exact stackroot typeobject");
} else if (i == THING_ROOT_SCRIPT) {
MarkScriptRoot(trc, (JSScript **)addr, "exact stackroot script");
} else if (i == THING_ROOT_XML) {
MarkXMLRoot(trc, (JSXML **)addr, "exact stackroot xml");
} else {
JS_NOT_REACHED("Invalid thing root kind.");
}
}
rooter = rooter->previous();
}
} }
MarkExactStackRooters(trc, rt->thingGCRooters[i], ThingRootKind(i));
} }
} }
#endif /* JSGC_USE_EXACT_ROOTING */ #endif /* JSGC_USE_EXACT_ROOTING */
@ -4970,11 +4973,21 @@ SetValidateGC(JSContext *cx, bool enabled)
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) #if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
JS_ALWAYS_INLINE bool
CheckStackRootThing(uintptr_t *w, void *address, ThingRootKind kind)
{
if (kind != THING_ROOT_BINDINGS)
return address == static_cast<void*>(w);
Bindings *bp = static_cast<Bindings*>(address);
return w >= (uintptr_t*)bp && w < (uintptr_t*)(bp + 1);
}
JS_ALWAYS_INLINE void JS_ALWAYS_INLINE void
CheckStackRootThings(uintptr_t *w, Rooted<void*> *rooter, bool *matched) CheckStackRootThings(uintptr_t *w, Rooted<void*> *rooter, ThingRootKind kind, bool *matched)
{ {
while (rooter) { while (rooter) {
if (rooter->address() == static_cast<void*>(w)) if (CheckStackRootThing(w, rooter->address(), kind))
*matched = true; *matched = true;
rooter = rooter->previous(); rooter = rooter->previous();
} }
@ -4994,9 +5007,9 @@ CheckStackRoot(JSTracer *trc, uintptr_t *w)
bool matched = false; bool matched = false;
JSRuntime *rt = trc->runtime; JSRuntime *rt = trc->runtime;
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) { for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
CheckStackRootThings(w, rt->thingGCRooters[i], &matched); CheckStackRootThings(w, rt->thingGCRooters[i], ThingRootKind(i), &matched);
for (ContextIter cx(rt); !cx.done(); cx.next()) { for (ContextIter cx(rt); !cx.done(); cx.next()) {
CheckStackRootThings(w, cx->thingGCRooters[i], &matched); CheckStackRootThings(w, cx->thingGCRooters[i], ThingRootKind(i), &matched);
SkipRoot *skip = cx->skipGCRooters; SkipRoot *skip = cx->skipGCRooters;
while (skip) { while (skip) {
if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w))) if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w)))

View File

@ -240,6 +240,7 @@ enum ThingRootKind
THING_ROOT_PROPERTY_ID, THING_ROOT_PROPERTY_ID,
THING_ROOT_VALUE, THING_ROOT_VALUE,
THING_ROOT_TYPE, THING_ROOT_TYPE,
THING_ROOT_BINDINGS,
THING_ROOT_LIMIT THING_ROOT_LIMIT
}; };

View File

@ -93,9 +93,12 @@ Bindings::initWithTemporaryStorage(JSContext *cx, InternalHandle<Bindings*> self
JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == 2); JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == 2);
gc::AllocKind allocKind = gc::FINALIZE_OBJECT2_BACKGROUND; gc::AllocKind allocKind = gc::FINALIZE_OBJECT2_BACKGROUND;
JS_ASSERT(gc::GetGCKindSlots(allocKind) == CallObject::RESERVED_SLOTS); JS_ASSERT(gc::GetGCKindSlots(allocKind) == CallObject::RESERVED_SLOTS);
self->callObjShape_ = RootedShape initial(cx,
EmptyShape::getInitialShape(cx, &CallClass, NULL, cx->global(), EmptyShape::getInitialShape(cx, &CallClass, NULL, cx->global(),
allocKind, BaseShape::VAROBJ | BaseShape::DELEGATE); allocKind, BaseShape::VAROBJ | BaseShape::DELEGATE));
if (!initial)
return false;
self->callObjShape_.init(initial);
#ifdef DEBUG #ifdef DEBUG
HashSet<PropertyName *> added(cx); HashSet<PropertyName *> added(cx);
@ -169,6 +172,12 @@ Bindings::clone(JSContext *cx, InternalHandle<Bindings*> self,
return true; return true;
} }
/* static */ Bindings
RootMethods<Bindings>::initial()
{
return Bindings();
}
template<XDRMode mode> template<XDRMode mode>
static bool static bool
XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, unsigned numVars, XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, unsigned numVars,
@ -2090,9 +2099,9 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
/* Bindings */ /* Bindings */
Bindings bindings; Rooted<Bindings> bindings(cx);
InternalHandle<Bindings*> bindingsHandle = InternalHandle<Bindings*> bindingsHandle =
InternalHandle<Bindings*>::fromMarkedLocation(&bindings); InternalHandle<Bindings*>::fromMarkedLocation(bindings.address());
if (!Bindings::clone(cx, bindingsHandle, data, src)) if (!Bindings::clone(cx, bindingsHandle, data, src))
return NULL; return NULL;
@ -2610,3 +2619,4 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
{ {
return argsObjAliasesFormals() && !formalIsAliased(argSlot); return argsObjAliasesFormals() && !formalIsAliased(argSlot);
} }

View File

@ -199,6 +199,15 @@ class Bindings
void trace(JSTracer *trc); void trace(JSTracer *trc);
}; };
template <>
struct RootMethods<Bindings> {
static Bindings initial();
static ThingRootKind kind() { return THING_ROOT_BINDINGS; }
static bool poisoned(const Bindings &bindings) {
return IsPoisonedPtr(bindings.callObjShape());
}
};
class ScriptCounts class ScriptCounts
{ {
friend struct ::JSScript; friend struct ::JSScript;