From c1fb5bcfc2978cfe768a9ccdbe24455c6f6df42c Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Mon, 24 Sep 2012 15:18:34 -0700 Subject: [PATCH] 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. --- js/src/jsgc.cpp | 89 ++++++++++++++++++++++++++------------------- js/src/jspubtd.h | 1 + js/src/jsscript.cpp | 18 +++++++-- js/src/jsscript.h | 9 +++++ 4 files changed, 75 insertions(+), 42 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index d556495fd269..94078533f469 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -959,44 +959,47 @@ InFreeList(ArenaHeader *aheader, uintptr_t addr) } #ifdef JSGC_USE_EXACT_ROOTING +static inline void +MarkExactStackRooter(JSTracer *trc, Rooted 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 rooter, ThingRootKind kind) +{ + Rooted *rooter = cx->thingGCRooters[i]; + while (rooter) { + MarkExactStackRoot(trc, rooter, ThingRootKind(i)); + rooter = rooter->previous(); + } +} + static void MarkExactStackRoots(JSTracer *trc) { - for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) { - for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) { - Rooted *rooter = cx->thingGCRooters[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(); - } + for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) { + for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) { + MarkExactStackRooters(trc, cx->thingGCRooters[i], ThingRootKind(i)); } + MarkExactStackRooters(trc, rt->thingGCRooters[i], ThingRootKind(i)); } } #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) +JS_ALWAYS_INLINE bool +CheckStackRootThing(uintptr_t *w, void *address, ThingRootKind kind) +{ + if (kind != THING_ROOT_BINDINGS) + return address == static_cast(w); + + Bindings *bp = static_cast(address); + return w >= (uintptr_t*)bp && w < (uintptr_t*)(bp + 1); +} + JS_ALWAYS_INLINE void -CheckStackRootThings(uintptr_t *w, Rooted *rooter, bool *matched) +CheckStackRootThings(uintptr_t *w, Rooted *rooter, ThingRootKind kind, bool *matched) { while (rooter) { - if (rooter->address() == static_cast(w)) + if (CheckStackRootThing(w, rooter->address(), kind)) *matched = true; rooter = rooter->previous(); } @@ -4994,9 +5007,9 @@ CheckStackRoot(JSTracer *trc, uintptr_t *w) bool matched = false; JSRuntime *rt = trc->runtime; 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()) { - CheckStackRootThings(w, cx->thingGCRooters[i], &matched); + CheckStackRootThings(w, cx->thingGCRooters[i], ThingRootKind(i), &matched); SkipRoot *skip = cx->skipGCRooters; while (skip) { if (skip->contains(reinterpret_cast(w), sizeof(w))) diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 9f1dafa0e0ee..521ae86c209c 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -240,6 +240,7 @@ enum ThingRootKind THING_ROOT_PROPERTY_ID, THING_ROOT_VALUE, THING_ROOT_TYPE, + THING_ROOT_BINDINGS, THING_ROOT_LIMIT }; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 81532ea7ec1b..581c6895ef23 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -93,9 +93,12 @@ Bindings::initWithTemporaryStorage(JSContext *cx, InternalHandle self JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == 2); gc::AllocKind allocKind = gc::FINALIZE_OBJECT2_BACKGROUND; JS_ASSERT(gc::GetGCKindSlots(allocKind) == CallObject::RESERVED_SLOTS); - self->callObjShape_ = + RootedShape initial(cx, 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 HashSet added(cx); @@ -169,6 +172,12 @@ Bindings::clone(JSContext *cx, InternalHandle self, return true; } +/* static */ Bindings +RootMethods::initial() +{ + return Bindings(); +} + template static bool XDRScriptBindings(XDRState *xdr, LifoAllocScope &las, unsigned numArgs, unsigned numVars, @@ -2090,9 +2099,9 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, /* Bindings */ - Bindings bindings; + Rooted bindings(cx); InternalHandle bindingsHandle = - InternalHandle::fromMarkedLocation(&bindings); + InternalHandle::fromMarkedLocation(bindings.address()); if (!Bindings::clone(cx, bindingsHandle, data, src)) return NULL; @@ -2610,3 +2619,4 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot) { return argsObjAliasesFormals() && !formalIsAliased(argSlot); } + diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 687eb97df988..eae25c6462b2 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -199,6 +199,15 @@ class Bindings void trace(JSTracer *trc); }; +template <> +struct RootMethods { + static Bindings initial(); + static ThingRootKind kind() { return THING_ROOT_BINDINGS; } + static bool poisoned(const Bindings &bindings) { + return IsPoisonedPtr(bindings.callObjShape()); + } +}; + class ScriptCounts { friend struct ::JSScript;