author | Brian Hackett <bhackett1024@gmail.com> |
Thu, 24 May 2012 08:52:21 -0700 | |
changeset 94823 | 779d3807d806499d655db9371119ccfc7d547ad6 |
parent 94822 | 54370e2a5963ad98ab1f0d005d245086babf40c7 |
child 94824 | d76b9c64e4575758fd44599c79cff98a960ca8bf |
push id | 9824 |
push user | bhackett@mozilla.com |
push date | Thu, 24 May 2012 15:52:34 +0000 |
treeherder | mozilla-inbound@779d3807d806 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | billm |
bugs | 756823 |
milestone | 15.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -193,17 +193,17 @@ class AddToMap { Value key; if (!pairobj->getElement(cx, 0, &key)) return false; HashableValue hkey; if (!hkey.setValue(cx, key)) return false; - HashableValue::StackRoot hkeyRoot(cx, &hkey); + HashableValue::AutoRooter hkeyRoot(cx, &hkey); Value val; if (!pairobj->getElement(cx, 1, &val)) return false; if (!map->put(hkey, val)) { js_ReportOutOfMemory(cx); return false;
--- a/js/src/builtin/MapObject.h +++ b/js/src/builtin/MapObject.h @@ -36,19 +36,33 @@ class HashableValue { HashableValue() : value(UndefinedValue()) {} bool setValue(JSContext *cx, const Value &v); HashNumber hash() const; bool equals(const HashableValue &other) const; HashableValue mark(JSTracer *trc) const; - struct StackRoot { - StackRoot(JSContext *cx, HashableValue *pv) : valueRoot(cx, (Value*) &pv->value) {} - RootValue valueRoot; + class AutoRooter : private AutoGCRooter + { + public: + explicit AutoRooter(JSContext *cx, HashableValue *v_ + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, HASHABLEVALUE), v(v_), skip(cx, v_) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + void trace(JSTracer *trc); + + private: + HashableValue *v; + SkipRoot skip; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; }; typedef HashMap<HashableValue, RelocatableValue, HashableValue::Hasher, RuntimeAllocPolicy> ValueMap; typedef HashSet<HashableValue,
--- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -17,22 +17,22 @@ #include "jsinferinlines.h" #include "frontend/TreeContext-inl.h" using namespace js; using namespace js::frontend; bool -MarkInnerAndOuterFunctions(JSContext *cx, JSScript* script) +MarkInnerAndOuterFunctions(JSContext *cx, JSScript* script_) { - Root<JSScript*> root(cx, &script); + RootedVar<JSScript*> script(cx, script_); Vector<JSScript *, 16> worklist(cx); - if (!worklist.append(script)) + if (!worklist.append(script.reference())) return false; while (worklist.length()) { JSScript *outer = worklist.back(); worklist.popBack(); if (outer->hasObjects()) { ObjectArray *arr = outer->objects();
--- a/js/src/frontend/TreeContext.h +++ b/js/src/frontend/TreeContext.h @@ -154,17 +154,17 @@ struct SharedContext { FunctionBox *funbox; /* null or box for function we're compiling if inFunction is set and not in js::frontend::CompileFunctionBody */ FunctionBox *functionList; Bindings bindings; /* bindings in this code, including arguments if we're compiling a function */ - Bindings::StackRoot bindingsRoot; /* root for stack allocated bindings. */ + Bindings::AutoRooter bindingsRoot; /* root for stack allocated bindings. */ const bool inFunction:1; /* parsing/emitting inside function body */ bool inForInit:1; /* parsing/emitting init expr of for; exclude 'in' */ ContextFlags cxFlags; inline SharedContext(JSContext *cx, bool inFunction);
--- a/js/src/gc/Root.h +++ b/js/src/gc/Root.h @@ -39,36 +39,31 @@ namespace JS { * * If Foo() cannot trigger a GC, and the same holds for all other calls made * between obj's definitions and its last uses, then no rooting is required. * * Several classes are available for rooting stack locations. All are templated * on the type T of the value being rooted, for which RootMethods<T> must * have an instantiation. * - * - Root<T> roots an existing stack allocated variable or other location of - * type T. This is typically used either when a variable only needs to be - * rooted on certain rare paths, or when a function takes a bare GC thing - * pointer as an argument and needs to root it. In the latter case a - * Handle<T> is generally preferred, see below. - * * - RootedVar<T> declares a variable of type T, whose value is always rooted. + * RootedVar<T> may be automatically coerced to a Handle<T>, below. + * RootedVar<T> should be used whenever a local variable's value may be held + * live across a call which can allocate GC things or otherwise trigger a GC. * - * - Handle<T> is a const reference to a Root<T> or RootedVar<T>. Handles are - * coerced automatically from such a Root<T> or RootedVar<T>. Functions which - * take GC things or values as arguments and need to root those arguments - * should generally replace those arguments with handles and avoid any - * explicit rooting. This has two benefits. First, when several such - * functions call each other then redundant rooting of multiple copies of the - * GC thing can be avoided. Second, if the caller does not pass a rooted - * value a compile error will be generated, which is quicker and easier to - * fix than when relying on a separate rooting analysis. + * - Handle<T> is a const reference to a RootedVar<T>. Functions which take GC + * things or values as arguments and need to root those arguments should + * generally use handles for those arguments and avoid any explicit rooting. + * This has two benefits. First, when several such functions call each other + * then redundant rooting of multiple copies of the GC thing can be avoided. + * Second, if the caller does not pass a rooted value a compile error will be + * generated, which is quicker and easier to fix than when relying on a + * separate rooting analysis. */ -template <typename T> class Root; template <typename T> class RootedVar; template <typename T> struct RootMethods { }; /* * Reference to a T that has been rooted elsewhere. This is most useful * as a parameter type, which guarantees that the T lvalue is properly @@ -81,32 +76,31 @@ class Handle /* Copy handles of different types, with implicit coercion. */ template <typename S> Handle(Handle<S> handle) { testAssign<S>(); ptr = reinterpret_cast<const T *>(handle.address()); } /* * This may be called only if the location of the T is guaranteed - * to be marked (for some reason other than being a Root or RootedVar), + * to be marked (for some reason other than being a RootedVar), * e.g., if it is guaranteed to be reachable from an implicit root. * * Create a Handle from a raw location of a T. */ static Handle fromMarkedLocation(const T *p) { Handle h; h.ptr = p; return h; } /* * Construct a handle from an explicitly rooted location. This is the - * normal way to create a handle. + * normal way to create a handle, and normally happens implicitly. */ - template <typename S> inline Handle(const Root<S> &root); template <typename S> inline Handle(const RootedVar<S> &root); const T *address() const { return ptr; } T value() const { return *ptr; } operator T () const { return value(); } T operator ->() const { return value(); } @@ -136,85 +130,108 @@ template <typename T> struct RootMethods<T *> { static T *initial() { return NULL; } static ThingRootKind kind() { return T::rootKind(); } static bool poisoned(T *v) { return IsPoisonedPtr(v); } }; /* - * Root a stack location holding a GC thing. This takes a stack pointer - * and ensures that throughout its lifetime the referenced variable - * will remain pinned against a moving GC. - * - * It is important to ensure that the location referenced by a Root is - * initialized, as otherwise the GC may try to use the the uninitialized value. - * It is generally preferable to use either RootedVar for local variables, or - * Handle for arguments. + * Local variable of type T whose value is always rooted. This is typically + * used for local variables, or for non-rooted values being passed to a + * function that requires a handle, e.g. Foo(Root<T>(cx, x)). */ template <typename T> -class Root +class RootedVar { - public: - Root(JSContext *cx_, const T *ptr - JS_GUARD_OBJECT_NOTIFIER_PARAM) + void init(JSContext *cx_, T initial) { #ifdef JSGC_ROOT_ANALYSIS ContextFriendFields *cx = ContextFriendFields::get(cx_); ThingRootKind kind = RootMethods<T>::kind(); - this->stack = reinterpret_cast<Root<T>**>(&cx->thingGCRooters[kind]); + this->stack = reinterpret_cast<RootedVar<T>**>(&cx->thingGCRooters[kind]); this->prev = *stack; *stack = this; - JS_ASSERT(!RootMethods<T>::poisoned(*ptr)); + JS_ASSERT(!RootMethods<T>::poisoned(initial)); #endif - this->ptr = ptr; - - JS_GUARD_OBJECT_NOTIFIER_INIT; + ptr = initial; } - ~Root() + public: + RootedVar(JSContext *cx) { init(cx, RootMethods<T>::initial()); } + RootedVar(JSContext *cx, T initial) { init(cx, initial); } + + /* + * This method is only necessary due to an obscure C++98 requirement (that + * there be an accessible, usable copy constructor when passing a temporary + * to an implicitly-called constructor for use with a const-ref parameter). + * (Head spinning yet?) We can remove this when we build the JS engine + * with -std=c++11. + */ + operator Handle<T> () const { return Handle<T>(*this); } + + ~RootedVar() { #ifdef JSGC_ROOT_ANALYSIS JS_ASSERT(*stack == this); *stack = prev; #endif } #ifdef JSGC_ROOT_ANALYSIS - Root<T> *previous() { return prev; } + RootedVar<T> *previous() { return prev; } #endif - const T *address() const { return ptr; } + operator T () const { return ptr; } + T operator ->() const { return ptr; } + T * address() { return &ptr; } + const T * address() const { return &ptr; } + T & reference() { return ptr; } + T raw() const { return ptr; } + + T & operator =(T value) + { + JS_ASSERT(!RootMethods<T>::poisoned(value)); + ptr = value; + return ptr; + } + + T & operator =(const RootedVar &value) + { + ptr = value; + return ptr; + } private: #ifdef JSGC_ROOT_ANALYSIS - Root<T> **stack, *prev; + RootedVar<T> **stack, *prev; #endif - const T *ptr; + T ptr; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER + RootedVar() MOZ_DELETE; + RootedVar(const RootedVar &) MOZ_DELETE; }; template<typename T> template <typename S> inline -Handle<T>::Handle(const Root<S> &root) +Handle<T>::Handle(const RootedVar<S> &root) { testAssign<S>(); ptr = reinterpret_cast<const T *>(root.address()); } -typedef Root<JSObject*> RootObject; -typedef Root<JSFunction*> RootFunction; -typedef Root<JSString*> RootString; -typedef Root<jsid> RootId; -typedef Root<Value> RootValue; +typedef RootedVar<JSObject*> RootedVarObject; +typedef RootedVar<JSFunction*> RootedVarFunction; +typedef RootedVar<JSString*> RootedVarString; +typedef RootedVar<jsid> RootedVarId; +typedef RootedVar<Value> RootedVarValue; /* * Mark a stack location as a root for the rooting analysis, without actually * rooting it in release builds. This should only be used for stack locations * of GC things that cannot be relocated by a garbage collection, and that * are definitely reachable via another path. */ class SkipRoot @@ -233,25 +250,25 @@ class SkipRoot *stack = this; this->start = (const uint8_t *) ptr; this->end = this->start + (sizeof(T) * count); } public: template <typename T> SkipRoot(JSContext *cx, const T *ptr - JS_GUARD_OBJECT_NOTIFIER_PARAM) + JS_GUARD_OBJECT_NOTIFIER_PARAM) { init(ContextFriendFields::get(cx), ptr, 1); JS_GUARD_OBJECT_NOTIFIER_INIT; } template <typename T> SkipRoot(JSContext *cx, const T *ptr, size_t count - JS_GUARD_OBJECT_NOTIFIER_PARAM) + JS_GUARD_OBJECT_NOTIFIER_PARAM) { init(ContextFriendFields::get(cx), ptr, count); JS_GUARD_OBJECT_NOTIFIER_INIT; } ~SkipRoot() { JS_ASSERT(*stack == this); @@ -281,80 +298,16 @@ class SkipRoot JS_GUARD_OBJECT_NOTIFIER_INIT; } #endif /* DEBUG && JSGC_ROOT_ANALYSIS */ JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; -/* Make a local variable which stays rooted throughout its lifetime. */ -template <typename T> -class RootedVar -{ - public: - RootedVar(JSContext *cx) - : ptr(RootMethods<T>::initial()), root(cx, &ptr) - {} - - RootedVar(JSContext *cx, T initial) - : ptr(initial), root(cx, &ptr) - {} - - operator T () const { return ptr; } - T operator ->() const { return ptr; } - T * address() { return &ptr; } - const T * address() const { return &ptr; } - T & reference() { return ptr; } - T raw() { return ptr; } - - /* - * This method is only necessary due to an obscure C++98 requirement (that - * there be an accessible, usable copy constructor when passing a temporary - * to an implicitly-called constructor for use with a const-ref parameter). - * (Head spinning yet?) We can remove this when we build the JS engine - * with -std=c++11. - */ - operator Handle<T> () const { return Handle<T>(*this); } - - T & operator =(T value) - { - JS_ASSERT(!RootMethods<T>::poisoned(value)); - ptr = value; - return ptr; - } - - T & operator =(const RootedVar &value) - { - ptr = value; - return ptr; - } - - private: - T ptr; - Root<T> root; - - RootedVar() MOZ_DELETE; - RootedVar(const RootedVar &) MOZ_DELETE; -}; - -template <typename T> template <typename S> -inline -Handle<T>::Handle(const RootedVar<S> &root) -{ - testAssign<S>(); - ptr = reinterpret_cast<const T *>(root.address()); -} - -typedef RootedVar<JSObject*> RootedVarObject; -typedef RootedVar<JSFunction*> RootedVarFunction; -typedef RootedVar<JSString*> RootedVarString; -typedef RootedVar<jsid> RootedVarId; -typedef RootedVar<Value> RootedVarValue; - /* * Hook for dynamic root analysis. Checks the native stack and poisons * references to GC things which have not been rooted. */ #if defined(JSGC_ROOT_ANALYSIS) && defined(DEBUG) && !defined(JS_THREADSAFE) void CheckStackRoots(JSContext *cx); inline void MaybeCheckStackRoots(JSContext *cx) { CheckStackRoots(cx); } #else
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1906,25 +1906,25 @@ static JSStdName object_prototype_names[ {js_InitObjectClass, EAGER_ATOM(lookupGetter), CLASP(Object)}, {js_InitObjectClass, EAGER_ATOM(lookupSetter), CLASP(Object)}, #endif {NULL, 0, NULL} }; JS_PUBLIC_API(JSBool) -JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved) +JS_ResolveStandardClass(JSContext *cx, JSObject *obj_, jsid id, JSBool *resolved) { JSString *idstr; JSRuntime *rt; JSAtom *atom; JSStdName *stdnm; unsigned i; - RootObject objRoot(cx, &obj); + RootedVarObject obj(cx, obj_); AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); *resolved = JS_FALSE; rt = cx->runtime; if (!rt->hasContexts() || !JSID_IS_ATOM(id)) @@ -3115,26 +3115,27 @@ JS_PUBLIC_API(JSBool) JS_ConvertStub(JSContext *cx, JSHandleObject obj, JSType type, jsval *vp) { JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION); JS_ASSERT(obj); return DefaultValue(cx, RootedVarObject(cx, obj), type, vp); } JS_PUBLIC_API(JSObject *) -JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, +JS_InitClass(JSContext *cx, JSObject *obj_, JSObject *parent_proto, JSClass *clasp, JSNative constructor, unsigned nargs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs) { + RootedVarObject obj(cx, obj_); + AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, parent_proto); - RootObject objRoot(cx, &obj); - return js_InitClass(cx, objRoot, parent_proto, Valueify(clasp), constructor, + return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor, nargs, ps, fs, static_ps, static_fs); } JS_PUBLIC_API(JSBool) JS_LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto) { return LinkConstructorAndPrototype(cx, ctor, proto); } @@ -3691,17 +3692,18 @@ DefinePropertyById(JSContext *cx, Handle if (getter) { JSObject *getobj = JS_NewFunction(cx, (Native) getter, 0, 0, &obj->global(), NULL); if (!getobj) return false; getter = JS_DATA_TO_FUNC_PTR(PropertyOp, getobj); attrs |= JSPROP_GETTER; } if (setter) { - RootObject getRoot(cx, (JSObject **) &getter); + // Root just the getter, since the setter is not yet a JSObject. + AutoRooterGetterSetter getRoot(cx, JSPROP_GETTER, &getter, NULL); JSObject *setobj = JS_NewFunction(cx, (Native) setter, 1, 0, &obj->global(), NULL); if (!setobj) return false; setter = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setobj); attrs |= JSPROP_SETTER; } } @@ -3735,33 +3737,33 @@ JS_DefinePropertyById(JSContext *cx, JSO } JS_PUBLIC_API(JSBool) JS_DefineElement(JSContext *cx, JSObject *obj_, uint32_t index, jsval value_, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) { RootedVarObject obj(cx, obj_); RootedVarValue value(cx, value_); - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); AssertNoGC(cx); CHECK_REQUEST(cx); RootedVarId id(cx); if (!IndexToId(cx, index, id.address())) return false; return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0); } static JSBool DefineProperty(JSContext *cx, JSObject *obj_, const char *name, const Value &value_, PropertyOp getter, StrictPropertyOp setter, unsigned attrs, unsigned flags, int tinyid) { RootedVarObject obj(cx, obj_); RootedVarValue value(cx, value_); - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); RootedVarId id(cx); if (attrs & JSPROP_INDEX) { id = INT_TO_JSID(intptr_t(name)); attrs &= ~JSPROP_INDEX; } else { JSAtom *atom = js_Atomize(cx, name, strlen(name)); if (!atom) @@ -3788,17 +3790,17 @@ JS_DefinePropertyWithTinyId(JSContext *c static JSBool DefineUCProperty(JSContext *cx, JSObject *obj_, const jschar *name, size_t namelen, const Value &value_, PropertyOp getter, StrictPropertyOp setter, unsigned attrs, unsigned flags, int tinyid) { RootedVarObject obj(cx, obj_); RootedVarValue value(cx, value_); - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) return false; RootedVarId id(cx, AtomToId(atom)); return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid); } JS_PUBLIC_API(JSBool) @@ -3822,30 +3824,29 @@ JS_DefineOwnProperty(JSContext *cx, JSOb { AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id, descriptor); return js_DefineOwnProperty(cx, RootedVarObject(cx, obj), RootedVarId(cx, id), descriptor, bp); } JS_PUBLIC_API(JSObject *) -JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp, +JS_DefineObject(JSContext *cx, JSObject *obj_, const char *name, JSClass *jsclasp, JSObject *proto, unsigned attrs) { + RootedVarObject obj(cx, obj_), nobj(cx); + AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, proto); Class *clasp = Valueify(jsclasp); if (!clasp) clasp = &ObjectClass; /* default class is Object */ - RootObject root(cx, &obj); - RootedVarObject nobj(cx); - nobj = NewObjectWithClassProto(cx, clasp, proto, obj); if (!nobj) return NULL; if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0)) return NULL; return nobj; @@ -3869,20 +3870,20 @@ JS_DefineConstDoubles(JSContext *cx, JSO ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0); if (!ok) break; } return ok; } JS_PUBLIC_API(JSBool) -JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps) +JS_DefineProperties(JSContext *cx, JSObject *obj_, JSPropertySpec *ps) { JSBool ok; - RootObject root(cx, &obj); + RootedVarObject obj(cx, obj_); for (ok = true; ps->name; ps++) { ok = DefineProperty(cx, obj, ps->name, UndefinedValue(), ps->getter, ps->setter, ps->flags, Shape::HAS_SHORTID, ps->tinyid); if (!ok) break; } return ok; @@ -4559,49 +4560,51 @@ JS_InitDestroyPrincipalsCallback(JSRunti { JS_ASSERT(destroyPrincipals); JS_ASSERT(!rt->destroyPrincipals); rt->destroyPrincipals = destroyPrincipals; } JS_PUBLIC_API(JSFunction *) JS_NewFunction(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, - JSObject *parent, const char *name) + JSObject *parent_, const char *name) { JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); JSAtom *atom; + RootedVarObject parent(cx, parent_); + AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, parent); if (!name) { atom = NULL; } else { atom = js_Atomize(cx, name, strlen(name)); if (!atom) return NULL; } - RootObject parentRoot(cx, &parent); - return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, atom); + return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom); } JS_PUBLIC_API(JSFunction *) -JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parent, +JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parent_, jsid id) { + RootedVarObject parent(cx, parent_); + JS_ASSERT(JSID_IS_STRING(id)); JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, parent); - RootObject parentRoot(cx, &parent); - return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, JSID_TO_ATOM(id)); + return js_NewFunction(cx, NULL, native, nargs, flags, parent, JSID_TO_ATOM(id)); } JS_PUBLIC_API(JSObject *) JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent_) { AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, parent_); // XXX no funobj for now @@ -4717,42 +4720,40 @@ js_generic_native_method_dispatcher(JSCo /* Clear the last parameter in case too few arguments were passed. */ vp[2 + --argc].setUndefined(); return fs->call(cx, argc, vp); } JS_PUBLIC_API(JSBool) -JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) -{ - RootObject objRoot(cx, &obj); +JS_DefineFunctions(JSContext *cx, JSObject *obj_, JSFunctionSpec *fs) +{ + RootedVarObject obj(cx, obj_); JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); unsigned flags; RootedVarObject ctor(cx); JSFunction *fun; AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); for (; fs->name; fs++) { flags = fs->flags; - JSAtom *atom = js_Atomize(cx, fs->name, strlen(fs->name)); + RootedVarAtom atom(cx, js_Atomize(cx, fs->name, strlen(fs->name))); if (!atom) return JS_FALSE; /* * Define a generic arity N+1 static method for the arity N prototype * method if flags contains JSFUN_GENERIC_NATIVE. */ if (flags & JSFUN_GENERIC_NATIVE) { - RootAtom root(cx, &atom); - if (!ctor) { ctor = JS_GetConstructor(cx, obj); if (!ctor) return JS_FALSE; } flags &= ~JSFUN_GENERIC_NATIVE; fun = js_DefineFunction(cx, ctor, RootedVarId(cx, AtomToId(atom)), @@ -4765,55 +4766,55 @@ JS_DefineFunctions(JSContext *cx, JSObje /* * As jsapi.h notes, fs must point to storage that lives as long * as fun->object lives. */ fun->setExtendedSlot(0, PrivateValue(fs)); } - fun = js_DefineFunction(cx, objRoot, + fun = js_DefineFunction(cx, obj, RootedVarId(cx, AtomToId(atom)), fs->call, fs->nargs, flags); if (!fun) return JS_FALSE; } return JS_TRUE; } JS_PUBLIC_API(JSFunction *) -JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call, +JS_DefineFunction(JSContext *cx, JSObject *obj_, const char *name, JSNative call, unsigned nargs, unsigned attrs) { - RootObject objRoot(cx, &obj); + RootedVarObject obj(cx, obj_); JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); JSAtom *atom = js_Atomize(cx, name, strlen(name)); if (!atom) return NULL; - return js_DefineFunction(cx, objRoot, RootedVarId(cx, AtomToId(atom)), call, nargs, attrs); + return js_DefineFunction(cx, obj, RootedVarId(cx, AtomToId(atom)), call, nargs, attrs); } JS_PUBLIC_API(JSFunction *) -JS_DefineUCFunction(JSContext *cx, JSObject *obj, +JS_DefineUCFunction(JSContext *cx, JSObject *obj_, const jschar *name, size_t namelen, JSNative call, unsigned nargs, unsigned attrs) { - RootObject objRoot(cx, &obj); + RootedVarObject obj(cx, obj_); JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) return NULL; - return js_DefineFunction(cx, objRoot, RootedVarId(cx, AtomToId(atom)), call, nargs, attrs); + return js_DefineFunction(cx, obj, RootedVarId(cx, AtomToId(atom)), call, nargs, attrs); } extern JS_PUBLIC_API(JSFunction *) JS_DefineFunctionById(JSContext *cx, JSObject *obj_, jsid id_, JSNative call, unsigned nargs, unsigned attrs) { RootedVarObject obj(cx, obj_); RootedVarId id(cx, id_); @@ -5131,23 +5132,23 @@ JS_GetGlobalFromScript(JSScript *script) { JS_ASSERT(!script->isCachedEval); JS_ASSERT(script->globalObject); return script->globalObject; } static JSFunction * -CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj, +CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj_, JSPrincipals *principals, const char *name, unsigned nargs, const char **argnames, const jschar *chars, size_t length, const char *filename, unsigned lineno, JSVersion version) { - RootObject objRoot(cx, &obj); + RootedVarObject obj(cx, obj_); JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); AssertNoGC(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, principals); AutoLastFrameCheck lfc(cx); RootedVarAtom funAtom(cx); @@ -5160,17 +5161,17 @@ CompileUCFunctionForPrincipalsCommon(JSC Bindings bindings(cx); for (unsigned i = 0; i < nargs; i++) { uint16_t dummy; RootedVarAtom argAtom(cx, js_Atomize(cx, argnames[i], strlen(argnames[i]))); if (!argAtom || !bindings.addArgument(cx, argAtom, &dummy)) return NULL; } - JSFunction *fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, objRoot, funAtom); + JSFunction *fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom); if (!fun) return NULL; if (!frontend::CompileFunctionBody(cx, fun, principals, NULL, &bindings, chars, length, filename, lineno, version)) { return NULL; }
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -914,17 +914,25 @@ class JS_PUBLIC_API(AutoGCRooter) { XML = -9, /* js::AutoXMLRooter */ OBJECT = -10, /* js::AutoObjectRooter */ ID = -11, /* js::AutoIdRooter */ VALVECTOR = -12, /* js::AutoValueVector */ DESCRIPTOR = -13, /* js::AutoPropertyDescriptorRooter */ STRING = -14, /* js::AutoStringRooter */ IDVECTOR = -15, /* js::AutoIdVector */ OBJVECTOR = -16, /* js::AutoObjectVector */ - SCRIPTVECTOR =-17 /* js::AutoScriptVector */ + SCRIPTVECTOR =-17, /* js::AutoScriptVector */ + PROPDESC = -18, /* js::PropDesc::AutoRooter */ + SHAPERANGE = -19, /* js::Shape::Range::AutoRooter */ + STACKSHAPE = -20, /* js::StackShape::AutoRooter */ + STACKBASESHAPE=-21,/* js::StackBaseShape::AutoRooter */ + BINDINGS = -22, /* js::Bindings::AutoRooter */ + GETTERSETTER =-23, /* js::AutoRooterGetterSetter */ + REGEXPSTATICS=-24, /* js::RegExpStatics::AutoRooter */ + HASHABLEVALUE=-25 }; private: AutoGCRooter ** const stackTop; /* No copy or assignment semantics. */ AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE; void operator=(AutoGCRooter &ida) MOZ_DELETE;
--- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -999,17 +999,17 @@ array_defineGeneric(JSContext *cx, Handl } if (i >= obj->getArrayLength()) obj->setDenseArrayLength(i + 1); obj->setDenseArrayElementWithType(cx, i, *value); return true; } while (false); - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); if (!JSObject::makeDenseArraySlow(cx, obj)) return false; return baseops::DefineProperty(cx, obj, id, value, getter, setter, attrs); } static JSBool array_defineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, const Value *value, @@ -1045,18 +1045,17 @@ array_defineElement(JSContext *cx, Handl } if (index >= obj->getArrayLength()) obj->setDenseArrayLength(index + 1); obj->setDenseArrayElementWithType(cx, index, *value); return true; } while (false); - RootValue valueRoot(cx, value); - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); if (!JSObject::makeDenseArraySlow(cx, obj)) return false; return baseops::DefineElement(cx, obj, index, value, getter, setter, attrs); } } // namespace js @@ -2154,29 +2153,30 @@ SortComparatorFunction::operator()(const } } /* namespace anonymous */ JSBool js::array_sort(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - Value fval; + + RootedVarValue fvalRoot(cx); + Value &fval = fvalRoot.reference(); + if (args.hasDefined(0)) { if (args[0].isPrimitive()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG); return false; } fval = args[0]; /* non-default compare function */ } else { fval.setNull(); } - RootValue fvalRoot(cx, &fval); - RootedVarObject obj(cx, ToObject(cx, &args.thisv())); if (!obj) return false; uint32_t len; if (!js_GetLengthProperty(cx, obj, &len)) return false; if (len == 0) { @@ -3722,48 +3722,48 @@ EnsureNewArrayElements(JSContext *cx, JS JS_ASSERT_IF(cap, !obj->hasDynamicElements()); return true; } template<bool allocateCapacity> static JS_ALWAYS_INLINE JSObject * -NewArray(JSContext *cx, uint32_t length, JSObject *proto) +NewArray(JSContext *cx, uint32_t length, JSObject *proto_) { gc::AllocKind kind = GuessArrayGCKind(length); #ifdef JS_THREADSAFE JS_ASSERT(CanBeFinalizedInBackground(kind, &ArrayClass)); kind = GetBackgroundAllocKind(kind); #endif - GlobalObject *parent = GetCurrentGlobal(cx); + GlobalObject *parent_ = GetCurrentGlobal(cx); NewObjectCache &cache = cx->runtime->newObjectCache; NewObjectCache::EntryIndex entry = -1; - if (cache.lookupGlobal(&ArrayClass, parent, kind, &entry)) { + if (cache.lookupGlobal(&ArrayClass, parent_, kind, &entry)) { JSObject *obj = cache.newObjectFromHit(cx, entry); if (!obj) return NULL; /* Fixup the elements pointer and length, which may be incorrect. */ obj->setFixedElements(); obj->setArrayLength(cx, length); if (allocateCapacity && !EnsureNewArrayElements(cx, obj, length)) return NULL; return obj; } - JS::Root<GlobalObject*> parentRoot(cx, &parent); - - if (!proto && !FindProto(cx, &ArrayClass, parentRoot, &proto)) + RootedVar<GlobalObject*> parent(cx, parent_); + + if (!proto_ && !FindProto(cx, &ArrayClass, parent, &proto_)) return NULL; - RootObject protoRoot(cx, &proto); + RootedVarObject proto(cx, proto_); RootedVarTypeObject type(cx); type = proto->getNewType(cx); if (!type) return NULL; /* * Get a shape with zero fixed slots, regardless of the size class.
--- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -114,18 +114,16 @@ NewObjectCache::newObjectFromHit(JSConte /* Copy the entry to the stack first in case it is purged by a GC. */ size_t nbytes = entry->nbytes; char stackObject[sizeof(JSObject_Slots16)]; JS_ASSERT(nbytes <= sizeof(stackObject)); js_memcpy(&stackObject, &entry->templateObject, nbytes); JSObject *baseobj = (JSObject *) stackObject; - RootShape shapeRoot(cx, (Shape **) baseobj->addressOfShape()); - RootTypeObject typeRoot(cx, (types::TypeObject **) baseobj->addressOfType()); obj = js_NewGCObject(cx, entry->kind); if (obj) { copyCachedToObject(obj, baseobj); Probes::createObject(cx, obj); return obj; }
--- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -181,31 +181,31 @@ DefineHelpProperty(JSContext *cx, Handle return false; jsval v = STRING_TO_JSVAL(atom); return JS_DefineProperty(cx, obj, prop, v, JS_PropertyStub, JS_StrictPropertyStub, JSPROP_READONLY | JSPROP_PERMANENT); } JS_FRIEND_API(bool) -JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj, const JSFunctionSpecWithHelp *fs) +JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj_, const JSFunctionSpecWithHelp *fs) { - RootObject objRoot(cx, &obj); + RootedVarObject obj(cx, obj_); JS_ASSERT(cx->compartment != cx->runtime->atomsCompartment); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); for (; fs->name; fs++) { JSAtom *atom = js_Atomize(cx, fs->name, strlen(fs->name)); if (!atom) return false; RootedVarFunction fun(cx); - fun = js_DefineFunction(cx, objRoot, RootedVarId(cx, AtomToId(atom)), + fun = js_DefineFunction(cx, obj, RootedVarId(cx, AtomToId(atom)), fs->call, fs->nargs, fs->flags); if (!fun) return false; if (fs->usage) { if (!DefineHelpProperty(cx, fun, "usage", fs->usage)) return false; } @@ -291,81 +291,82 @@ js::IsObjectInContextCompartment(const J JS_FRIEND_API(bool) js::IsOriginalScriptFunction(JSFunction *fun) { return fun->script()->function() == fun; } JS_FRIEND_API(JSFunction *) -js::DefineFunctionWithReserved(JSContext *cx, JSObject *obj, const char *name, JSNative call, +js::DefineFunctionWithReserved(JSContext *cx, JSObject *obj_, const char *name, JSNative call, unsigned nargs, unsigned attrs) { - RootObject objRoot(cx, &obj); + RootedVarObject obj(cx, obj_); JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); JSAtom *atom = js_Atomize(cx, name, strlen(name)); if (!atom) return NULL; - return js_DefineFunction(cx, objRoot, RootedVarId(cx, AtomToId(atom)), + return js_DefineFunction(cx, obj, RootedVarId(cx, AtomToId(atom)), call, nargs, attrs, JSFunction::ExtendedFinalizeKind); } JS_FRIEND_API(JSFunction *) js::NewFunctionWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, - JSObject *parent, const char *name) + JSObject *parent_, const char *name) { - RootObject parentRoot(cx, &parent); + RootedVarObject parent(cx, parent_); JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); JSAtom *atom; CHECK_REQUEST(cx); assertSameCompartment(cx, parent); if (!name) { atom = NULL; } else { atom = js_Atomize(cx, name, strlen(name)); if (!atom) return NULL; } - return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, atom, + return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom, JSFunction::ExtendedFinalizeKind); } JS_FRIEND_API(JSFunction *) -js::NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parent, +js::NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parent_, jsid id) { - RootObject parentRoot(cx, &parent); + RootedVarObject parent(cx, parent_); JS_ASSERT(JSID_IS_STRING(id)); JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); CHECK_REQUEST(cx); assertSameCompartment(cx, parent); - return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, JSID_TO_ATOM(id), + return js_NewFunction(cx, NULL, native, nargs, flags, parent, JSID_TO_ATOM(id), JSFunction::ExtendedFinalizeKind); } JS_FRIEND_API(JSObject *) -js::InitClassWithReserved(JSContext *cx, JSObject *obj, JSObject *parent_proto, +js::InitClassWithReserved(JSContext *cx, JSObject *obj_, JSObject *parent_proto, JSClass *clasp, JSNative constructor, unsigned nargs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs) { + RootedVarObject obj(cx, obj_); + CHECK_REQUEST(cx); assertSameCompartment(cx, obj, parent_proto); - RootObject objRoot(cx, &obj); - return js_InitClass(cx, objRoot, parent_proto, Valueify(clasp), constructor, + return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor, nargs, ps, fs, static_ps, static_fs, NULL, JSFunction::ExtendedFinalizeKind); } JS_FRIEND_API(const Value &) js::GetFunctionNativeReserved(JSObject *fun, size_t which) { JS_ASSERT(fun->toFunction()->isNative());
--- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1000,17 +1000,17 @@ Function(JSContext *cx, unsigned argc, V RootedVar<GlobalObject*> global(cx); global = &args.callee().global(); if (!global->isRuntimeCodeGenEnabled(cx)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION); return false; } Bindings bindings(cx); - Bindings::StackRoot bindingsRoot(cx, &bindings); + Bindings::AutoRooter bindingsRoot(cx, &bindings); bool hasRest = false; const char *filename; unsigned lineno; JSPrincipals *originPrincipals; CurrentScriptFileLineOrigin(cx, &filename, &lineno, &originPrincipals); JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
--- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -68,16 +68,17 @@ #include "jsscope.h" #include "jsscript.h" #include "jswatchpoint.h" #include "jsweakmap.h" #if JS_HAS_XML_SUPPORT #include "jsxml.h" #endif +#include "builtin/MapObject.h" #include "frontend/Parser.h" #include "gc/Marking.h" #include "gc/Memory.h" #include "methodjit/MethodJIT.h" #include "vm/Debugger.h" #include "vm/String.h" #include "jsinterpinlines.h" @@ -2176,30 +2177,131 @@ AutoGCRooter::trace(JSTracer *trc) } case SCRIPTVECTOR: { AutoScriptVector::VectorImpl &vector = static_cast<AutoScriptVector *>(this)->vector; for (size_t i = 0; i < vector.length(); i++) MarkScriptRoot(trc, &vector[i], "AutoScriptVector element"); return; } + + case PROPDESC: { + PropDesc::AutoRooter *rooter = static_cast<PropDesc::AutoRooter *>(this); + MarkValueRoot(trc, &rooter->pd->pd_, "PropDesc::AutoRooter pd"); + MarkValueRoot(trc, &rooter->pd->value_, "PropDesc::AutoRooter value"); + MarkValueRoot(trc, &rooter->pd->get_, "PropDesc::AutoRooter get"); + MarkValueRoot(trc, &rooter->pd->set_, "PropDesc::AutoRooter set"); + return; + } + + case SHAPERANGE: { + Shape::Range::AutoRooter *rooter = static_cast<Shape::Range::AutoRooter *>(this); + rooter->trace(trc); + return; + } + + case STACKSHAPE: { + StackShape::AutoRooter *rooter = static_cast<StackShape::AutoRooter *>(this); + if (rooter->shape->base) + MarkBaseShapeRoot(trc, (BaseShape**) &rooter->shape->base, "StackShape::AutoRooter base"); + MarkIdRoot(trc, (jsid*) &rooter->shape->propid, "StackShape::AutoRooter id"); + return; + } + + case STACKBASESHAPE: { + StackBaseShape::AutoRooter *rooter = static_cast<StackBaseShape::AutoRooter *>(this); + if (rooter->base->parent) + MarkObjectRoot(trc, (JSObject**) &rooter->base->parent, "StackBaseShape::AutoRooter parent"); + if ((rooter->base->flags & BaseShape::HAS_GETTER_OBJECT) && rooter->base->rawGetter) { + MarkObjectRoot(trc, (JSObject**) &rooter->base->rawGetter, + "StackBaseShape::AutoRooter getter"); + } + if ((rooter->base->flags & BaseShape::HAS_SETTER_OBJECT) && rooter->base->rawSetter) { + MarkObjectRoot(trc, (JSObject**) &rooter->base->rawSetter, + "StackBaseShape::AutoRooter setter"); + } + return; + } + + case BINDINGS: { + Bindings::AutoRooter *rooter = static_cast<Bindings::AutoRooter *>(this); + rooter->trace(trc); + return; + } + + case GETTERSETTER: { + AutoRooterGetterSetter::Inner *rooter = static_cast<AutoRooterGetterSetter::Inner *>(this); + if ((rooter->attrs & JSPROP_GETTER) && *rooter->pgetter) + MarkObjectRoot(trc, (JSObject**) rooter->pgetter, "AutoRooterGetterSetter getter"); + if ((rooter->attrs & JSPROP_SETTER) && *rooter->psetter) + MarkObjectRoot(trc, (JSObject**) rooter->psetter, "AutoRooterGetterSetter setter"); + return; + } + + case REGEXPSTATICS: { + /* + RegExpStatics::AutoRooter *rooter = static_cast<RegExpStatics::AutoRooter *>(this); + rooter->trace(trc); + */ + return; + } + + case HASHABLEVALUE: { + /* + HashableValue::AutoRooter *rooter = static_cast<HashableValue::AutoRooter *>(this); + rooter->trace(trc); + */ + return; + } } JS_ASSERT(tag >= 0); MarkValueRootRange(trc, tag, static_cast<AutoArrayRooter *>(this)->array, "JS::AutoArrayRooter.array"); } /* static */ void AutoGCRooter::traceAll(JSTracer *trc) { for (js::AutoGCRooter *gcr = trc->runtime->autoGCRooters; gcr; gcr = gcr->down) gcr->trace(trc); } +void +Shape::Range::AutoRooter::trace(JSTracer *trc) +{ + if (r->cursor) + MarkShapeRoot(trc, const_cast<Shape**>(&r->cursor), "Shape::Range::AutoRooter"); +} + +void +Bindings::AutoRooter::trace(JSTracer *trc) +{ + if (bindings->lastBinding) + MarkShapeRoot(trc, reinterpret_cast<Shape**>(&bindings->lastBinding), + "Bindings::AutoRooter lastBinding"); +} + +void +RegExpStatics::AutoRooter::trace(JSTracer *trc) +{ + if (statics->matchPairsInput) + MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics->matchPairsInput), + "RegExpStatics::AutoRooter matchPairsInput"); + if (statics->pendingInput) + MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics->pendingInput), + "RegExpStatics::AutoRooter pendingInput"); +} + +void +HashableValue::AutoRooter::trace(JSTracer *trc) +{ + MarkValueRoot(trc, reinterpret_cast<Value*>(&v->value), "HashableValue::AutoRooter"); +} + namespace js { static void MarkRuntime(JSTracer *trc, bool useSavedRoots = false) { JSRuntime *rt = trc->runtime; JS_ASSERT(trc->callback != GCMarker::GrayCallback); @@ -3954,17 +4056,17 @@ CheckStackRoot(JSTracer *trc, uintptr_t ConservativeGCTest test = MarkIfGCThingWord(trc, *w); if (test == CGCT_VALID) { bool matched = false; JSRuntime *rt = trc->runtime; for (ContextIter cx(rt); !cx.done(); cx.next()) { for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) { - Root<void*> *rooter = cx->thingGCRooters[i]; + RootedVar<void*> *rooter = cx->thingGCRooters[i]; while (rooter) { if (rooter->address() == static_cast<void*>(w)) matched = true; rooter = rooter->previous(); } } SkipRoot *skip = cx->skipGCRooters; while (skip) {
--- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -1872,19 +1872,19 @@ TypeCompartment::init(JSContext *cx) if (masm.supportsFloatingPoint()) #endif inferenceEnabled = true; } } TypeObject * TypeCompartment::newTypeObject(JSContext *cx, JSScript *script, - JSProtoKey key, JSObject *proto, bool unknown) -{ - RootObject root(cx, &proto); + JSProtoKey key, JSObject *proto_, bool unknown) +{ + RootedVarObject proto(cx, proto_); TypeObject *object = gc::NewGCThing<TypeObject>(cx, gc::FINALIZE_TYPE_OBJECT, sizeof(TypeObject)); if (!object) return NULL; new(object) TypeObject(proto, key == JSProto_Function, unknown); if (!cx->typeInferenceEnabled()) object->flags |= OBJECT_FLAG_UNKNOWN_MASK; @@ -4953,23 +4953,23 @@ TypeMonitorResult(JSContext *cx, JSScrip return; InferSpew(ISpewOps, "bytecodeType: #%u:%05u: %s", script->id(), pc - script->code, TypeString(type)); types->addType(cx, type); } bool -TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope) -{ +TypeScript::SetScope(JSContext *cx, JSScript *script_, JSObject *scope_) +{ + RootedVar<JSScript*> script(cx, script_); + RootedVarObject scope(cx, scope_); + JS_ASSERT(script->types && !script->types->hasScope()); - Root<JSScript*> scriptRoot(cx, &script); - RootObject scopeRoot(cx, &scope); - JSFunction *fun = script->function(); bool nullClosure = fun && fun->isNullClosure(); JS_ASSERT_IF(!fun, !script->isOuterFunction && !script->isInnerFunction); JS_ASSERT_IF(!scope, fun && !script->isInnerFunction); /* * The scope object must be the initial one for the script, before any call
--- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -1427,19 +1427,20 @@ inline bool JSScript::ensureRanAnalysis(JSContext *cx, JSObject *scope) { JSScript *self = this; JS::SkipRoot root(cx, &self); if (!self->ensureHasTypes(cx)) return false; if (!self->types->hasScope()) { - js::RootObject objRoot(cx, &scope); + js::RootedVarObject scopeRoot(cx, scope); if (!js::types::TypeScript::SetScope(cx, self, scope)) return false; + scope = scopeRoot; } if (!self->hasAnalysis() && !self->makeAnalysis(cx)) return false; JS_ASSERT(self->analysis()->ranBytecode()); return true; } inline bool
--- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -428,23 +428,23 @@ js::InvokeGetterOrSetter(JSContext *cx, * bug 355497. */ JS_CHECK_RECURSION(cx, return false); return Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval); } bool -js::ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value &thisv, +js::ExecuteKernel(JSContext *cx, JSScript *script_, JSObject &scopeChain, const Value &thisv, ExecuteType type, StackFrame *evalInFrame, Value *result) { JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG); JS_ASSERT_IF(type == EXECUTE_GLOBAL, !scopeChain.isScope()); - JS::Root<JSScript*> scriptRoot(cx, &script); + JS::RootedVar<JSScript*> script(cx, script_); if (script->isEmpty()) { if (result) result->setUndefined(); return true; } ExecuteFrameGuard efg;
--- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -201,59 +201,58 @@ GetPropertyOperation(JSContext *cx, jsby if (obj->isTypedArray()) { *vp = Int32Value(TypedArray::getLength(obj)); return true; } } } - JSObject *obj = ValueToObject(cx, lval); + RootedVarObject obj(cx, ValueToObject(cx, lval)); if (!obj) return false; PropertyCacheEntry *entry; JSObject *obj2; PropertyName *name; - JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name); + JS_PROPERTY_CACHE(cx).test(cx, pc, obj.reference(), obj2, entry, name); if (!name) { AssertValidPropertyCacheHit(cx, obj, obj2, entry); if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp)) return false; return true; } - RootObject objRoot(cx, &obj); RootedVarId id(cx, NameToId(name)); if (obj->getOps()->getProperty) { - if (!GetPropertyGenericMaybeCallXML(cx, op, objRoot, id, vp)) + if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp)) return false; } else { - if (!GetPropertyHelper(cx, objRoot, id, JSGET_CACHE_RESULT, vp)) + if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, vp)) return false; } #if JS_HAS_NO_SUCH_METHOD if (op == JSOP_CALLPROP && JS_UNLIKELY(vp->isPrimitive()) && lval.isObject()) { - if (!OnUnknownMethod(cx, objRoot, IdToValue(id), vp)) + if (!OnUnknownMethod(cx, obj, IdToValue(id), vp)) return false; } #endif return true; } inline bool SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Value &rval) { - JSObject *obj = ValueToObject(cx, lval); + RootedVarObject obj(cx, ValueToObject(cx, lval)); if (!obj) return false; JS_ASSERT_IF(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME, lval.isObject()); JS_ASSERT_IF(*pc == JSOP_SETGNAME, obj == &cx->fp()->global()); PropertyCacheEntry *entry; JSObject *obj2; @@ -299,85 +298,78 @@ SetPropertyOperation(JSContext *cx, jsby GET_NAME_FROM_BYTECODE(cx->stack.currentScript(), pc, 0, name); } bool strict = cx->stack.currentScript()->strictModeCode; RootedVarValue rref(cx, rval); JSOp op = JSOp(*pc); - RootObject objRoot(cx, &obj); - RootedVarId id(cx, NameToId(name)); if (JS_LIKELY(!obj->getOps()->setProperty)) { unsigned defineHow = (op == JSOP_SETNAME) ? DNP_CACHE_RESULT | DNP_UNQUALIFIED : DNP_CACHE_RESULT; - if (!baseops::SetPropertyHelper(cx, objRoot, id, defineHow, rref.address(), strict)) + if (!baseops::SetPropertyHelper(cx, obj, id, defineHow, rref.address(), strict)) return false; } else { if (!obj->setGeneric(cx, id, rref.address(), strict)) return false; } return true; } inline bool NameOperation(JSContext *cx, jsbytecode *pc, Value *vp) { - JSObject *obj = cx->stack.currentScriptedScopeChain(); + RootedVarObject obj(cx, cx->stack.currentScriptedScopeChain()); /* * Skip along the scope chain to the enclosing global object. This is * used for GNAME opcodes where the bytecode emitter has determined a * name access must be on the global. It also insulates us from bugs * in the emitter: type inference will assume that GNAME opcodes are * accessing the global object, and the inferred behavior should match * the actual behavior even if the id could be found on the scope chain * before the global object. */ if (js_CodeSpec[*pc].format & JOF_GNAME) obj = &obj->global(); PropertyCacheEntry *entry; JSObject *obj2; - PropertyName *name; - JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name); + RootedVarPropertyName name(cx); + JS_PROPERTY_CACHE(cx).test(cx, pc, obj.reference(), obj2, entry, name.reference()); if (!name) { AssertValidPropertyCacheHit(cx, obj, obj2, entry); if (!NativeGet(cx, obj, obj2, entry->prop, 0, vp)) return false; return true; } - jsid id = NameToId(name); - - RootPropertyName nameRoot(cx, &name); - RootObject objRoot(cx, &obj); - JSProperty *prop; - if (!FindPropertyHelper(cx, nameRoot, true, objRoot, &obj, &obj2, &prop)) + if (!FindPropertyHelper(cx, name, true, obj, obj.address(), &obj2, &prop)) return false; if (!prop) { /* Kludge to allow (typeof foo == "undefined") tests. */ JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]); if (op2 == JSOP_TYPEOF) { vp->setUndefined(); return true; } JSAutoByteString printable; if (js_AtomToPrintableString(cx, name, &printable)) js_ReportIsNotDefined(cx, printable.ptr()); return false; } /* Take the slow path if prop was not found in a native object. */ if (!obj->isNative() || !obj2->isNative()) { - if (!obj->getGeneric(cx, RootedVarId(cx, id), vp)) + if (!obj->getGeneric(cx, RootedVarId(cx, NameToId(name)), vp)) return false; } else { Shape *shape = (Shape *)prop; JSObject *normalized = obj; if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter()) normalized = &normalized->asWith().object(); if (!NativeGet(cx, normalized, obj2, shape, 0, vp)) return false; @@ -834,23 +826,23 @@ SetObjectElementOperation(JSContext *cx, } while (0); RootedVarValue tmp(cx, value); return obj->setGeneric(cx, id, tmp.address(), strict); } #define RELATIONAL_OP(OP) \ JS_BEGIN_MACRO \ - Value lval = lhs; \ - Value rval = rhs; \ + RootedVarValue lvalRoot(cx, lhs), rvalRoot(cx, rhs); \ + Value &lval = lvalRoot.reference(); \ + Value &rval = rvalRoot.reference(); \ /* Optimize for two int-tagged operands (typical loop control). */ \ if (lval.isInt32() && rval.isInt32()) { \ *res = lval.toInt32() OP rval.toInt32(); \ } else { \ - RootValue lvalRoot(cx, &lval), rvalRoot(cx, &rval); \ if (!ToPrimitive(cx, JSTYPE_NUMBER, &lval)) \ return false; \ if (!ToPrimitive(cx, JSTYPE_NUMBER, &rval)) \ return false; \ if (lval.isString() && rval.isString()) { \ JSString *l = lval.toString(), *r = rval.toString(); \ int32_t result; \ if (!CompareStrings(cx, l, r, &result)) \
--- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -197,27 +197,26 @@ Enumerate(JSContext *cx, JSObject *obj, if (enumerable || (flags & JSITER_HIDDEN)) return props->append(id); return true; } static bool -EnumerateNativeProperties(JSContext *cx, JSObject *obj, JSObject *pobj, unsigned flags, IdSet &ht, +EnumerateNativeProperties(JSContext *cx, JSObject *obj_, JSObject *pobj_, unsigned flags, IdSet &ht, AutoIdVector *props) { - RootObject objRoot(cx, &obj); - RootObject pobjRoot(cx, &pobj); + RootedVarObject obj(cx, obj_), pobj(cx, pobj_); size_t initialLength = props->length(); /* Collect all unique properties from this object's scope. */ Shape::Range r = pobj->lastProperty()->all(); - Shape::Range::Root root(cx, &r); + Shape::Range::AutoRooter root(cx, &r); for (; !r.empty(); r.popFront()) { const Shape &shape = r.front(); if (!JSID_IS_DEFAULT_XML_NAMESPACE(shape.propid()) && !Enumerate(cx, obj, pobj, shape.propid(), shape.enumerable(), flags, ht, props)) { return false; } @@ -277,24 +276,23 @@ struct SortComparatorIds *lessOrEqualp = (result <= 0); return true; } }; #endif /* JS_MORE_DETERMINISTIC */ static bool -Snapshot(JSContext *cx, JSObject *obj, unsigned flags, AutoIdVector *props) +Snapshot(JSContext *cx, JSObject *obj_, unsigned flags, AutoIdVector *props) { IdSet ht(cx); if (!ht.init(32)) return NULL; - RootObject objRoot(cx, &obj); - RootedVarObject pobj(cx); + RootedVarObject obj(cx, obj_), pobj(cx); pobj = obj; do { Class *clasp = pobj->getClass(); if (pobj->isNative() && !pobj->getOps()->enumerate && !(clasp->flags & JSCLASS_NEW_ENUMERATE)) { if (!clasp->enumerate(cx, pobj))
--- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -179,18 +179,19 @@ MarkSharpObjects(JSContext *cx, HandleOb JSObject *obj2; JSProperty *prop; ok = obj->lookupGeneric(cx, id, &obj2, &prop); if (!ok) break; if (!prop) continue; bool hasGetter, hasSetter; - Value value = UndefinedValue(), setter = UndefinedValue(); - RootValue valueRoot(cx, &value), setterRoot(cx, &setter); + RootedVarValue valueRoot(cx), setterRoot(cx); + Value &value = valueRoot.reference(); + Value &setter = setterRoot.reference(); if (obj2->isNative()) { const Shape *shape = (Shape *) prop; hasGetter = shape->hasGetterValue(); hasSetter = shape->hasSetterValue(); if (hasGetter) value = shape->getterValue(); if (hasSetter) setter = shape->setterValue(); @@ -1506,17 +1507,17 @@ NewPropertyDescriptorObject(JSContext *c { if (!desc->obj) { vp->setUndefined(); return true; } /* We have our own property, so start creating the descriptor. */ PropDesc d; - PropDesc::StackRoot dRoot(cx, &d); + PropDesc::AutoRooter dRoot(cx, &d); d.initFromPropertyDescriptor(*desc); if (!d.makeObject(cx)) return false; *vp = d.pd(); return true; } @@ -2715,67 +2716,66 @@ js_Object(JSContext *cx, unsigned argc, return JS_FALSE; obj->setType(type); } vp->setObject(*obj); return JS_TRUE; } static inline JSObject * -NewObject(JSContext *cx, Class *clasp, types::TypeObject *type, JSObject *parent, +NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *parent, gc::AllocKind kind) { JS_ASSERT(clasp != &ArrayClass); JS_ASSERT_IF(clasp == &FunctionClass, kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind); - RootTypeObject typeRoot(cx, &type); + RootedVarTypeObject type(cx, type_); RootedVarShape shape(cx); shape = EmptyShape::getInitialShape(cx, clasp, type->proto, parent, kind); if (!shape) return NULL; HeapSlot *slots; if (!PreallocateObjectDynamicSlots(cx, shape, &slots)) return NULL; - JSObject *obj = JSObject::create(cx, kind, shape, typeRoot, slots); + JSObject *obj = JSObject::create(cx, kind, shape, type, slots); if (!obj) return NULL; /* * This will cancel an already-running incremental GC from doing any more * slices, and it will prevent any future incremental GCs. */ if (clasp->trace && !(clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS)) cx->runtime->gcIncrementalEnabled = false; Probes::createObject(cx, obj); return obj; } JSObject * -js::NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, +js::NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto_, JSObject *parent_, gc::AllocKind kind) { + RootedVarObject proto(cx, proto_), parent(cx, parent_); + if (CanBeFinalizedInBackground(kind, clasp)) kind = GetBackgroundAllocKind(kind); NewObjectCache &cache = cx->runtime->newObjectCache; NewObjectCache::EntryIndex entry = -1; if (proto && (!parent || parent == proto->getParent()) && !proto->isGlobal()) { if (cache.lookupProto(clasp, proto, kind, &entry)) return cache.newObjectFromHit(cx, entry); } - RootObject protoRoot(cx, &proto); - RootObject parentRoot(cx, &parent); - types::TypeObject *type = proto ? proto->getNewType(cx) : cx->compartment->getEmptyType(cx); if (!type) return NULL; /* * Default parent to the parent of the prototype, which was set from * the parent of the prototype's constructor. */ @@ -2788,21 +2788,23 @@ js::NewObjectWithGivenProto(JSContext *c if (entry != -1 && !obj->hasDynamicSlots()) cache.fillProto(entry, clasp, proto, kind, obj); return obj; } JSObject * -js::NewObjectWithClassProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, +js::NewObjectWithClassProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent_, gc::AllocKind kind) { if (proto) - return NewObjectWithGivenProto(cx, clasp, proto, parent, kind); + return NewObjectWithGivenProto(cx, clasp, proto, parent_, kind); + + RootedVarObject parent(cx, parent_); if (CanBeFinalizedInBackground(kind, clasp)) kind = GetBackgroundAllocKind(kind); if (!parent) parent = GetCurrentGlobal(cx); /* @@ -2819,19 +2821,17 @@ js::NewObjectWithClassProto(JSContext *c NewObjectCache &cache = cx->runtime->newObjectCache; NewObjectCache::EntryIndex entry = -1; if (parent->isGlobal() && protoKey != JSProto_Null) { if (cache.lookupGlobal(clasp, &parent->asGlobal(), kind, &entry)) return cache.newObjectFromHit(cx, entry); } - RootObject parentRoot(cx, &parent); - - if (!FindProto(cx, clasp, parentRoot, &proto)) + if (!FindProto(cx, clasp, parent, &proto)) return NULL; types::TypeObject *type = proto->getNewType(cx); if (!type) return NULL; JSObject *obj = NewObject(cx, clasp, type, parent, kind); if (!obj) @@ -3139,17 +3139,17 @@ JS_CopyPropertiesFrom(JSContext *cx, JSO } size_t n = shapes.length(); while (n > 0) { const Shape *shape = shapes[--n]; unsigned attrs = shape->attributes(); PropertyOp getter = shape->getter(); StrictPropertyOp setter = shape->setter(); - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); if ((attrs & JSPROP_GETTER) && !cx->compartment->wrap(cx, &getter)) return false; if ((attrs & JSPROP_SETTER) && !cx->compartment->wrap(cx, &setter)) return false; Value v = shape->hasSlot() ? obj->getSlot(shape->slot()) : UndefinedValue(); if (!cx->compartment->wrap(cx, &v)) return false; if (!target->defineGeneric(cx, RootedVarId(cx, shape->propid()), v, getter, setter, attrs)) @@ -3754,23 +3754,23 @@ MarkStandardClassInitializedNoProto(JSOb */ if (obj->getReservedSlot(key) == UndefinedValue()) obj->setSlot(key, BooleanValue(true)); } } JSObject * -js_InitClass(JSContext *cx, HandleObject obj, JSObject *protoProto, +js_InitClass(JSContext *cx, HandleObject obj, JSObject *protoProto_, Class *clasp, Native constructor, unsigned nargs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs, JSObject **ctorp, AllocKind ctorKind) { - RootObject rootProto(cx, &protoProto); + RootedVarObject protoProto(cx, protoProto_); RootedVarAtom atom(cx); atom = js_Atomize(cx, clasp->name, strlen(clasp->name)); if (!atom) return NULL; /* * All instances of the class will inherit properties from the prototype @@ -3782,17 +3782,17 @@ js_InitClass(JSContext *cx, HandleObject * of js_InitClass depend on this nicety. Note that in * js_InitFunctionAndObjectClasses, we specially hack the resolving table * and then depend on js_GetClassPrototype here leaving protoProto NULL and * returning true. */ JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp); if (key != JSProto_Null && !protoProto && - !js_GetClassPrototype(cx, obj, JSProto_Object, &protoProto)) { + !js_GetClassPrototype(cx, obj, JSProto_Object, protoProto.address())) { return NULL; } return DefineConstructorAndPrototype(cx, obj, key, atom, protoProto, clasp, constructor, nargs, ps, fs, static_ps, static_fs, ctorp, ctorKind); } inline bool @@ -4186,20 +4186,20 @@ SetProto(JSContext *cx, HandleObject obj obj->setType(type); return true; } } JSBool -js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, +js_GetClassObject(JSContext *cx, JSObject *obj_, JSProtoKey key, JSObject **objp) { - RootObject objRoot(cx, &obj); + RootedVarObject obj(cx, obj_); obj = &obj->global(); if (!obj->isGlobal()) { *objp = NULL; return true; } Value v = obj->getReservedSlot(key); @@ -4344,22 +4344,22 @@ JSObject::freeSlot(JSContext *cx, uint32 last = slot; return; } } setSlot(slot, UndefinedValue()); } static bool -PurgeProtoChain(JSContext *cx, JSObject *obj, jsid id) +PurgeProtoChain(JSContext *cx, JSObject *obj_, jsid id_) { const Shape *shape; - RootObject objRoot(cx, &obj); - RootId idRoot(cx, &id); + RootedVarObject obj(cx, obj_); + RootedVarId id(cx, id_); while (obj) { if (!obj->isNative()) { obj = obj->getProto(); continue; } shape = obj->nativeLookup(cx, id); if (shape) { @@ -4371,20 +4371,20 @@ PurgeProtoChain(JSContext *cx, JSObject } obj = obj->getProto(); } return true; } bool -js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id) -{ - RootObject objRoot(cx, &obj); - RootId idRoot(cx, &id); +js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj_, jsid id_) +{ + RootedVarObject obj(cx, obj_); + RootedVarId id(cx, id_); JS_ASSERT(obj->isDelegate()); PurgeProtoChain(cx, obj->getProto(), id); /* * We must purge the scope chain only for Call objects as they are the only * kind of cacheable non-global object that can gain properties after outer * properties with the same names have been cached or traced. Call objects @@ -4429,17 +4429,17 @@ JSBool baseops::DefineElement(JSContext *cx, HandleObject obj, uint32_t index, const Value *value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { if (index <= JSID_INT_MAX) { return !!DefineNativeProperty(cx, obj, RootedVarId(cx, INT_TO_JSID(index)), *value, getter, setter, attrs, 0, 0); } - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); RootedVarId id(cx); if (!IndexToId(cx, index, id.address())) return false; return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0); } @@ -4471,17 +4471,17 @@ const Shape * DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value_, PropertyOp getter, StrictPropertyOp setter, unsigned attrs, unsigned flags, int shortid, unsigned defineHow /* = 0 */) { JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_DONT_PURGE | DNP_SKIP_TYPE)) == 0); JS_ASSERT(!(attrs & JSPROP_NATIVE_ACCESSORS)); - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); /* Make a local copy of value so addProperty can mutate its inout parameter. */ RootedVarValue value(cx); value = value_; /* * If defining a getter or setter, we must check for its counterpart and * update the attributes and property ops. A getter or setter is really @@ -4927,25 +4927,25 @@ js_NativeGetInline(JSContext *cx, JSObje jsbytecode *pc; JSScript *script = cx->stack.currentScript(&pc); if (script && script->hasAnalysis()) { analyze::Bytecode *code = script->analysis()->maybeCode(pc); if (code) code->accessGetter = true; } - Root<const Shape*> rootShape(cx, &shape); - RootObject pobjRoot(cx, &pobj); + RootedVar<const Shape*> shapeRoot(cx, shape); + RootedVarObject pobjRoot(cx, pobj); if (!shape->get(cx, RootedVarObject(cx, receiver), obj, pobj, vp)) return false; /* Update slotful shapes according to the value produced by the getter. */ - if (shape->hasSlot() && pobj->nativeContains(cx, *shape)) - pobj->nativeSetSlot(shape->slot(), *vp); + if (shapeRoot->hasSlot() && pobjRoot->nativeContains(cx, *shapeRoot)) + pobjRoot->nativeSetSlot(shapeRoot->slot(), *vp); return true; } JSBool js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, unsigned getHow, Value *vp) { @@ -4973,30 +4973,30 @@ js_NativeSet(JSContext *cx, JSObject *ob * Such properties effectively function as data descriptors which are * not writable, so attempting to set such a property should do nothing * or throw if we're in strict mode. */ if (!shape->hasGetterValue() && shape->hasDefaultSetter()) return js_ReportGetterOnlyAssignment(cx); } - Root<const Shape *> shapeRoot(cx, &shape); + RootedVar<const Shape *> shapeRoot(cx, shape); int32_t sample = cx->runtime->propertyRemovals; if (!shape->set(cx, RootedVarObject(cx, obj), strict, vp)) return false; /* * Update any slot for the shape with the value produced by the setter, * unless the setter deleted the shape. */ - if (shape->hasSlot() && + if (shapeRoot->hasSlot() && (JS_LIKELY(cx->runtime->propertyRemovals == sample) || - obj->nativeContains(cx, *shape))) { - obj->setSlot(shape->slot(), *vp); + obj->nativeContains(cx, *shapeRoot))) { + obj->setSlot(shapeRoot->slot(), *vp); } return true; } static JS_ALWAYS_INLINE JSBool js_GetPropertyHelperInline(JSContext *cx, HandleObject obj, HandleObject receiver, jsid id_, uint32_t getHow, Value *vp)
--- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -576,20 +576,21 @@ Str(JSContext *cx, const Value &v, Strin ok = JO(cx, obj, scx); scx->depth--; return ok; } /* ES5 15.12.3. */ JSBool -js_Stringify(JSContext *cx, Value *vp, JSObject *replacer_, Value space, StringBuffer &sb) +js_Stringify(JSContext *cx, Value *vp, JSObject *replacer_, Value space_, StringBuffer &sb) { RootedVarObject replacer(cx, replacer_); - RootValue spaceRoot(cx, &space); + RootedVarValue spaceRoot(cx, space_); + Value &space = spaceRoot.reference(); /* Step 4. */ AutoIdVector propertyList(cx); if (replacer) { if (replacer->isCallable()) { /* Step 4a(i): use replacer to transform values. */ } else if (ObjectClassIs(*replacer, ESClass_Array, cx)) { /*
--- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -415,17 +415,17 @@ ToDisassemblySource(JSContext *cx, jsval if (!JSVAL_IS_PRIMITIVE(v)) { JSObject *obj = JSVAL_TO_OBJECT(v); if (obj->isBlock()) { char *source = JS_sprintf_append(NULL, "depth %d {", obj->asBlock().stackDepth()); if (!source) return false; Shape::Range r = obj->lastProperty()->all(); - Shape::Range::Root root(cx, &r); + Shape::Range::AutoRooter root(cx, &r); while (!r.empty()) { RootedVar<const Shape*> shape(cx, &r.front()); JSAtom *atom = JSID_IS_INT(shape->propid()) ? cx->runtime->atomState.emptyAtom : JSID_TO_ATOM(shape->propid()); JSAutoByteString bytes;
--- a/js/src/jspropertytree.cpp +++ b/js/src/jspropertytree.cpp @@ -139,45 +139,45 @@ ReadBarrier(Shape *shape) MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier"); JS_ASSERT(tmp == shape); } #endif return shape; } Shape * -PropertyTree::getChild(JSContext *cx, Shape *parent, uint32_t nfixed, const StackShape &child) +PropertyTree::getChild(JSContext *cx, Shape *parent_, uint32_t nfixed, const StackShape &child) { Shape *shape; - JS_ASSERT(parent); + JS_ASSERT(parent_); /* * The property tree has extremely low fan-out below its root in * popular embeddings with real-world workloads. Patterns such as * defining closures that capture a constructor's environment as * getters or setters on the new object that is passed in as * |this| can significantly increase fan-out below the property * tree root -- see bug 335700 for details. */ - KidsPointer *kidp = &parent->kids; + KidsPointer *kidp = &parent_->kids; if (kidp->isShape()) { shape = kidp->toShape(); if (shape->matches(child)) return ReadBarrier(shape); } else if (kidp->isHash()) { shape = *kidp->toHash()->lookup(child); if (shape) return ReadBarrier(shape); } else { /* If kidp->isNull(), we always insert. */ } - RootStackShape childRoot(cx, &child); - RootShape parentRoot(cx, &parent); + StackShape::AutoRooter childRoot(cx, &child); + RootedVarShape parent(cx, parent_); shape = newShape(cx); if (!shape) return NULL; new (shape) Shape(child, nfixed); if (!insertChild(cx, parent, shape))
--- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -222,22 +222,16 @@ struct TypeCompartment; } /* namespace types */ typedef JS::Handle<Shape*> HandleShape; typedef JS::Handle<BaseShape*> HandleBaseShape; typedef JS::Handle<types::TypeObject*> HandleTypeObject; typedef JS::Handle<JSAtom*> HandleAtom; typedef JS::Handle<PropertyName*> HandlePropertyName; -typedef JS::Root<Shape*> RootShape; -typedef JS::Root<BaseShape*> RootBaseShape; -typedef JS::Root<types::TypeObject*> RootTypeObject; -typedef JS::Root<JSAtom*> RootAtom; -typedef JS::Root<PropertyName*> RootPropertyName; - typedef JS::RootedVar<Shape*> RootedVarShape; typedef JS::RootedVar<BaseShape*> RootedVarBaseShape; typedef JS::RootedVar<types::TypeObject*> RootedVarTypeObject; typedef JS::RootedVar<JSAtom*> RootedVarAtom; typedef JS::RootedVar<PropertyName*> RootedVarPropertyName; enum XDRMode { XDR_ENCODE,
--- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -211,17 +211,17 @@ typedef JSBool (*JSInitC JS_END_EXTERN_C #ifdef __cplusplus namespace JS { template <typename T> -class Root; +class RootedVar; class SkipRoot; enum ThingRootKind { THING_ROOT_OBJECT, THING_ROOT_SHAPE, THING_ROOT_BASE_SHAPE, @@ -249,17 +249,17 @@ struct ContextFriendFields { } #ifdef JSGC_ROOT_ANALYSIS /* * Stack allocated GC roots for stack GC heap pointers, which may be * overwritten if moved during a GC. */ - Root<void*> *thingGCRooters[THING_ROOT_LIMIT]; + RootedVar<void*> *thingGCRooters[THING_ROOT_LIMIT]; #ifdef DEBUG /* * Stack allocated list of stack locations which hold non-relocatable * GC heap pointers (where the target is rooted somewhere else) or integer * values which may be confused for GC heap pointers. These are used to * suppress false positives which occur when a rooting analysis treats the * location as holding a relocatable pointer, but have no other effect on
--- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -3190,20 +3190,19 @@ static JSFunctionSpec static_methods[] = JS_FN("parse", reflect_parse, 1, 0), JS_FS_END }; JS_BEGIN_EXTERN_C JS_PUBLIC_API(JSObject *) -JS_InitReflect(JSContext *cx, JSObject *obj) +JS_InitReflect(JSContext *cx, JSObject *obj_) { - RootObject root(cx, &obj); - RootedVarObject Reflect(cx); + RootedVarObject obj(cx, obj_), Reflect(cx); Reflect = NewObjectWithClassProto(cx, &ObjectClass, NULL, obj); if (!Reflect || !Reflect->setSingletonType(cx)) return NULL; if (!JS_DefineProperty(cx, obj, "Reflect", OBJECT_TO_JSVAL(Reflect), JS_PropertyStub, JS_StrictPropertyStub, 0)) { return NULL;
--- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -305,30 +305,30 @@ Shape::getChildBinding(JSContext *cx, co } shape->setNumFixedSlots(nfixed - 1); } return shape; } /* static */ Shape * -Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base, JSObject *proto, Shape *shape) +Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base, JSObject *proto, Shape *shape_) { + RootedVarShape shape(cx, shape_); + JS_ASSERT(!shape->inDictionary()); if (!shape->parent) { /* Treat as resetting the initial property of the shape hierarchy. */ AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots()); return EmptyShape::getInitialShape(cx, base.clasp, proto, base.parent, kind, base.flags & BaseShape::OBJECT_FLAG_MASK); } - RootShape root(cx, &shape); - UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base); if (!nbase) return NULL; StackShape child(shape); child.base = nbase; return cx->propertyTree().getChild(cx, shape->parent, shape->numFixedSlots(), child); @@ -364,17 +364,17 @@ JSObject::getChildProperty(JSContext *cx } Shape *shape; RootedVarObject self(cx, this); if (inDictionaryMode()) { JS_ASSERT(parent == lastProperty()); - RootStackShape childRoot(cx, &child); + StackShape::AutoRooter childRoot(cx, &child); shape = js_NewGCShape(cx); if (!shape) return NULL; if (child.hasSlot() && child.slot() >= self->lastProperty()->base()->slotSpan()) { if (!self->setSlotSpan(cx, child.slot() + 1)) return NULL; } shape->initDictionaryShape(child, self->numFixedSlots(), &self->shape_); @@ -494,28 +494,28 @@ JSObject::addProperty(JSContext *cx, jsi if (inDictionaryMode()) spp = lastProperty()->table().search(id, true); return self->addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, spp, allowDictionary); } Shape * -JSObject::addPropertyInternal(JSContext *cx, jsid id, +JSObject::addPropertyInternal(JSContext *cx, jsid id_, PropertyOp getter, StrictPropertyOp setter, uint32_t slot, unsigned attrs, unsigned flags, int shortid, Shape **spp, bool allowDictionary) { JS_ASSERT_IF(!allowDictionary, !inDictionaryMode()); - RootId idRoot(cx, &id); + RootedVarId id(cx, id_); RootedVarObject self(cx, this); - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); ShapeTable *table = NULL; if (!inDictionaryMode()) { bool stableSlot = (slot == SHAPE_INVALID_SLOT) || lastProperty()->hasMissingSlot() || (slot == lastProperty()->maybeSlot() + 1); JS_ASSERT_IF(!allowDictionary, stableSlot); @@ -603,51 +603,48 @@ CheckCanChangeAttrs(JSContext *cx, JSObj obj->reportNotConfigurable(cx, shape->propid()); return false; } return true; } Shape * -JSObject::putProperty(JSContext *cx, jsid id, +JSObject::putProperty(JSContext *cx, jsid id_, PropertyOp getter, StrictPropertyOp setter, uint32_t slot, unsigned attrs, unsigned flags, int shortid) { + RootedVarId id(cx, id_); JS_ASSERT(!JSID_IS_VOID(id)); - RootId idRoot(cx, &id); - NormalizeGetterAndSetter(cx, this, id, attrs, flags, getter, setter); RootedVarObject self(cx, this); - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); /* Search for id in order to claim its entry if table has been allocated. */ Shape **spp; - Shape *shape = Shape::search(cx, lastProperty(), id, &spp, true); + RootedVarShape shape(cx, Shape::search(cx, lastProperty(), id, &spp, true)); if (!shape) { /* * You can't add properties to a non-extensible object, but you can change * attributes of properties in such objects. */ if (!self->isExtensible()) { self->reportNotExtensible(cx); return NULL; } return self->addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, spp, true); } /* Property exists: search must have returned a valid *spp. */ JS_ASSERT_IF(spp, !SHAPE_IS_REMOVED(*spp)); - RootShape shapeRoot(cx, &shape); - if (!CheckCanChangeAttrs(cx, self, shape, &attrs)) return NULL; /* * If the caller wants to allocate a slot, but doesn't care which slot, * copy the existing shape's slot into slot so we can match shape, if all * other members match. */ @@ -797,21 +794,21 @@ JSObject::changeProperty(JSContext *cx, Shape *newShape = putProperty(cx, shape->propid(), getter, setter, shape->maybeSlot(), attrs, shape->flags, shape->maybeShortid()); checkShapeConsistency(); return newShape; } bool -JSObject::removeProperty(JSContext *cx, jsid id) +JSObject::removeProperty(JSContext *cx, jsid id_) { + RootedVarId id(cx, id_); RootedVarObject self(cx, this); - RootId idRoot(cx, &id); RootedVarShape shape(cx); Shape **spp; shape = Shape::search(cx, lastProperty(), id, &spp); if (!shape) return true; /* @@ -959,30 +956,34 @@ JSObject::replaceWithNewEquivalentShape( { JS_ASSERT_IF(oldShape != lastProperty(), inDictionaryMode() && nativeLookup(cx, oldShape->propidRef()) == oldShape); JSObject *self = this; if (!inDictionaryMode()) { - RootObject selfRoot(cx, &self); - RootShape newRoot(cx, &newShape); + RootedVarObject selfRoot(cx, self); + RootedVarShape newRoot(cx, newShape); if (!toDictionaryMode(cx)) return NULL; oldShape = self->lastProperty(); + self = selfRoot; + newShape = newRoot; } if (!newShape) { - RootObject selfRoot(cx, &self); - RootShape oldRoot(cx, &oldShape); + RootedVarObject selfRoot(cx, self); + RootedVarShape oldRoot(cx, oldShape); newShape = js_NewGCShape(cx); if (!newShape) return NULL; new (newShape) Shape(oldShape->base()->unowned(), 0); + self = selfRoot; + oldShape = oldRoot; } ShapeTable &table = self->lastProperty()->table(); Shape **spp = oldShape->isEmptyShape() ? NULL : table.search(oldShape->propidRef(), false); /* @@ -1132,48 +1133,30 @@ StackBaseShape::match(UnownedBaseShape * { return key->flags == lookup->flags && key->clasp == lookup->clasp && key->parent == lookup->parent && key->rawGetter == lookup->rawGetter && key->rawSetter == lookup->rawSetter; } -/* Root for stack allocated base shapes. */ -class RootStackBaseShape -{ - Root<const JSObject*> parentRoot; - Maybe<RootObject> getterRoot; - Maybe<RootObject> setterRoot; - - public: - RootStackBaseShape(JSContext *cx, const StackBaseShape *base) - : parentRoot(cx, &base->parent) - { - if (base->flags & BaseShape::HAS_GETTER_OBJECT) - getterRoot.construct(cx, (JSObject **) &base->rawGetter); - if (base->flags & BaseShape::HAS_SETTER_OBJECT) - setterRoot.construct(cx, (JSObject **) &base->rawSetter); - } -}; - /* static */ UnownedBaseShape * BaseShape::getUnowned(JSContext *cx, const StackBaseShape &base) { BaseShapeSet &table = cx->compartment->baseShapes; if (!table.initialized() && !table.init()) return NULL; BaseShapeSet::AddPtr p = table.lookupForAdd(&base); if (p) return *p; - RootStackBaseShape root(cx, &base); + StackBaseShape::AutoRooter root(cx, &base); BaseShape *nbase_ = js_NewGCBaseShape(cx); if (!nbase_) return NULL; new (nbase_) BaseShape(base); UnownedBaseShape *nbase = static_cast<UnownedBaseShape *>(nbase_); @@ -1224,29 +1207,29 @@ Bindings::setExtensibleParents(JSContext Shape *newShape = Shape::setExtensibleParents(cx, lastBinding); if (!newShape) return false; lastBinding = newShape; return true; } bool -Bindings::setParent(JSContext *cx, JSObject *obj) +Bindings::setParent(JSContext *cx, JSObject *obj_) { + RootedVarObject obj(cx, obj_); + /* * This may be invoked on GC heap allocated bindings, in which case this * is pointing to an internal value of a JSScript that can't itself be * relocated. The script itself will be rooted, and will not be moved, so * mark the stack value as non-relocatable for the stack root analysis. */ Bindings *self = this; SkipRoot root(cx, &self); - RootObject rootObj(cx, &obj); - if (!ensureShape(cx)) return false; /* This is only used for Block objects, which have a NULL proto. */ Shape *newShape = Shape::setObjectParent(cx, obj, NULL, self->lastBinding); if (!newShape) return false; self->lastBinding = newShape; @@ -1302,31 +1285,34 @@ EmptyShape::getInitialShape(JSContext *c size_t nfixed = GetGCKindSlots(kind, clasp); InitialShapeEntry::Lookup lookup(clasp, proto, parent, nfixed, objectFlags); InitialShapeSet::AddPtr p = table.lookupForAdd(lookup); if (p) return p->shape; - RootObject protoRoot(cx, &lookup.proto); - RootObject parentRoot(cx, &lookup.parent); + RootedVarObject protoRoot(cx, lookup.proto); + RootedVarObject parentRoot(cx, lookup.parent); RootedVar<UnownedBaseShape*> nbase(cx); StackBaseShape base(clasp, parent, objectFlags); nbase = BaseShape::getUnowned(cx, base); if (!nbase) return NULL; Shape *shape = cx->propertyTree().newShape(cx); if (!shape) return NULL; new (shape) EmptyShape(nbase, nfixed); + lookup.proto = protoRoot; + lookup.parent = parentRoot; + if (!table.relookupOrAdd(p, lookup, InitialShapeEntry(shape, lookup.proto))) return NULL; return shape; } void NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto)
--- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -417,16 +417,34 @@ struct StackBaseShape inline StackBaseShape(Shape *shape); inline void updateGetterSetter(uint8_t attrs, PropertyOp rawGetter, StrictPropertyOp rawSetter); static inline HashNumber hash(const StackBaseShape *lookup); static inline bool match(UnownedBaseShape *key, const StackBaseShape *lookup); + + class AutoRooter : private AutoGCRooter + { + public: + explicit AutoRooter(JSContext *cx, const StackBaseShape *base_ + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, STACKBASESHAPE), base(base_), skip(cx, base_) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + const StackBaseShape *base; + SkipRoot skip; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + }; }; typedef HashSet<ReadBarriered<UnownedBaseShape>, StackBaseShape, SystemAllocPolicy> BaseShapeSet; struct Shape : public js::gc::Cell { @@ -555,22 +573,33 @@ struct Shape : public js::gc::Cell return *cursor; } void popFront() { JS_ASSERT(!empty()); cursor = cursor->parent; } - class Root { - js::Root<const Shape*> cursorRoot; + class AutoRooter : private AutoGCRooter + { public: - Root(JSContext *cx, Range *range) - : cursorRoot(cx, &range->cursor) - {} + explicit AutoRooter(JSContext *cx, Range *r_ + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, SHAPERANGE), r(r_), skip(cx, r_) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + void trace(JSTracer *trc); + + private: + Range *r; + SkipRoot skip; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; }; Range all() const { return Range(this); } Class *getObjectClass() const { return base()->clasp; } @@ -859,29 +888,52 @@ struct Shape : public js::gc::Cell private: static void staticAsserts() { JS_STATIC_ASSERT(offsetof(Shape, base_) == offsetof(js::shadow::Shape, base)); JS_STATIC_ASSERT(offsetof(Shape, slotInfo) == offsetof(js::shadow::Shape, slotInfo)); JS_STATIC_ASSERT(FIXED_SLOTS_SHIFT == js::shadow::Shape::FIXED_SLOTS_SHIFT); } }; -class RootGetterSetter +class AutoRooterGetterSetter { - mozilla::Maybe<RootObject> getterRoot; - mozilla::Maybe<RootObject> setterRoot; + class Inner : private AutoGCRooter + { + public: + Inner(JSContext *cx, uint8_t attrs, + PropertyOp *pgetter_, StrictPropertyOp *psetter_) + : AutoGCRooter(cx, GETTERSETTER), attrs(attrs), + pgetter(pgetter_), psetter(psetter_), + getterRoot(cx, pgetter_), setterRoot(cx, psetter_) + {} + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + uint8_t attrs; + PropertyOp *pgetter; + StrictPropertyOp *psetter; + SkipRoot getterRoot, setterRoot; + }; public: - RootGetterSetter(JSContext *cx, uint8_t attrs, PropertyOp *pgetter, StrictPropertyOp *psetter) + explicit AutoRooterGetterSetter(JSContext *cx, uint8_t attrs, + PropertyOp *pgetter, StrictPropertyOp *psetter + JS_GUARD_OBJECT_NOTIFIER_PARAM) { - if (attrs & JSPROP_GETTER) - getterRoot.construct(cx, (JSObject **) pgetter); - if (attrs & JSPROP_SETTER) - setterRoot.construct(cx, (JSObject **) psetter); + if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) + inner.construct(cx, attrs, pgetter, psetter); + JS_GUARD_OBJECT_NOTIFIER_INIT; } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + Maybe<Inner> inner; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; struct EmptyShape : public js::Shape { EmptyShape(UnownedBaseShape *base, uint32_t nfixed); /* * Lookup an initial shape matching the given parameters, creating an empty @@ -986,30 +1038,35 @@ struct StackShape } void setSlot(uint32_t slot) { JS_ASSERT(slot <= SHAPE_INVALID_SLOT); slot_ = slot; } inline HashNumber hash() const; -}; -/* Rooter for stack allocated shapes. */ -class RootStackShape -{ - Root<const UnownedBaseShape*> baseShapeRoot; - Root<const jsid> propidRoot; + class AutoRooter : private AutoGCRooter + { + public: + explicit AutoRooter(JSContext *cx, const StackShape *shape_ + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, STACKSHAPE), shape(shape_), skip(cx, shape_) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } - public: - RootStackShape(JSContext *cx, const StackShape *shape) - : baseShapeRoot(cx, &shape->base), - propidRoot(cx, &shape->propid) - {} -}; + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + const StackShape *shape; + SkipRoot skip; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + }; + }; } /* namespace js */ /* js::Shape pointer tag bit indicating a collision. */ #define SHAPE_COLLISION (uintptr_t(1)) #define SHAPE_REMOVED ((js::Shape *) SHAPE_COLLISION) /* Macros to get and set shape pointer values and collision flags. */ @@ -1041,22 +1098,24 @@ Shape::search(JSContext *cx, Shape *star if (start->hasTable()) { Shape **spp = start->table().search(id, adding); return SHAPE_FETCH(spp); } if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) { if (start->isBigEnoughForAShapeTable()) { - RootShape startRoot(cx, &start); - RootId idRoot(cx, &id); + RootedVarShape startRoot(cx, start); + RootedVarId idRoot(cx, id); if (start->hashify(cx)) { Shape **spp = start->table().search(id, adding); return SHAPE_FETCH(spp); } + start = startRoot; + id = idRoot; } /* * No table built -- there weren't enough entries, or OOM occurred. * Don't increment numLinearSearches, to keep hasTable() false. */ JS_ASSERT(!start->hasTable()); } else { start->incrementNumLinearSearches();
--- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -412,17 +412,17 @@ js::XDRScript(XDRState<mode> *xdr, JSScr if (mode == XDR_DECODE) { nargs = argsVars >> 16; nvars = argsVars & 0xFFFF; } JS_ASSERT(nargs != Bindings::BINDING_COUNT_LIMIT); JS_ASSERT(nvars != Bindings::BINDING_COUNT_LIMIT); Bindings bindings(cx); - Bindings::StackRoot bindingsRoot(cx, &bindings); + Bindings::AutoRooter bindingsRoot(cx, &bindings); uint32_t nameCount = nargs + nvars; if (nameCount > 0) { LifoAllocScope las(&cx->tempLifoAlloc()); /* * To xdr the names we prefix the names with a bitmap descriptor and * then xdr the names as strings. For argument names (indexes below
--- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -221,22 +221,33 @@ class Bindings * Sometimes iteration order must be from oldest to youngest, however. For * such cases, use js::Bindings::getLocalNameArray. */ const js::Shape *lastArgument() const; const js::Shape *lastVariable() const; void trace(JSTracer *trc); - /* Rooter for stack allocated Bindings. */ - struct StackRoot { - RootShape root; - StackRoot(JSContext *cx, Bindings *bindings) - : root(cx, (Shape **) &bindings->lastBinding) - {} + class AutoRooter : private AutoGCRooter + { + public: + explicit AutoRooter(JSContext *cx, Bindings *bindings_ + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, BINDINGS), bindings(bindings_), skip(cx, bindings_) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + void trace(JSTracer *trc); + + private: + Bindings *bindings; + SkipRoot skip; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; }; } /* namespace js */ #define JS_OBJECT_ARRAY_SIZE(length) \ (offsetof(ObjectArray, vector) + sizeof(JSObject *) * (length))
--- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -396,17 +396,17 @@ ArrayBufferObject::obj_lookupSpecial(JSC JSBool ArrayBufferObject::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *v, PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) return true; - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); RootedVarObject delegate(cx, DelegateObject(cx, obj)); if (!delegate) return false; return baseops::DefineProperty(cx, delegate, id, v, getter, setter, attrs); } JSBool @@ -416,17 +416,17 @@ ArrayBufferObject::obj_defineProperty(JS { return obj_defineGeneric(cx, obj, RootedVarId(cx, NameToId(name)), v, getter, setter, attrs); } JSBool ArrayBufferObject::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, const Value *v, PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { - RootGetterSetter gsRoot(cx, attrs, &getter, &setter); + AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); RootedVarObject delegate(cx, DelegateObject(cx, obj)); if (!delegate) return false; return baseops::DefineElement(cx, delegate, index, v, getter, setter, attrs); } JSBool @@ -719,20 +719,19 @@ ArrayBufferObject::obj_typeOf(JSContext /* * ArrayBufferViews of various sorts */ static JSObject * GetProtoForClass(JSContext *cx, Class *clasp) { // Pass in the proto from this compartment - GlobalObject *parent = GetCurrentGlobal(cx); - Root<GlobalObject*> parentRoot(cx, &parent); + RootedVar<GlobalObject*> parent(cx, GetCurrentGlobal(cx)); JSObject *proto; - if (!FindProto(cx, clasp, parentRoot, &proto)) + if (!FindProto(cx, clasp, parent, &proto)) return NULL; return proto; } /* * TypedArray * * The non-templated base class for the specific typed implementations.
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -383,32 +383,32 @@ SkipUTF8BOM(FILE* file) ungetc(ch3, file); if (ch2 != EOF) ungetc(ch2, file); if (ch1 != EOF) ungetc(ch1, file); } static void -Process(JSContext *cx, JSObject *obj, const char *filename, bool forceTTY) +Process(JSContext *cx, JSObject *obj_, const char *filename, bool forceTTY) { JSBool ok, hitEOF; JSScript *script; jsval result; JSString *str; char *buffer; size_t size; jschar *uc_buffer; size_t uc_len; int lineno; int startline; FILE *file; uint32_t oldopts; - RootObject root(cx, &obj); + RootedVarObject obj(cx, obj_); if (forceTTY || !filename || strcmp(filename, "-") == 0) { file = stdin; } else { file = fopen(filename, "r"); if (!file) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_CANT_OPEN, filename, strerror(errno)); @@ -1726,19 +1726,21 @@ TryNotes(JSContext *cx, JSScript *script Sprint(sp, " %-7s %6u %8u %8u\n", TryNoteNames[tn->kind], tn->stackDepth, tn->start, tn->start + tn->length); } while (++tn != tnlimit); return JS_TRUE; } static bool -DisassembleScript(JSContext *cx, JSScript *script, JSFunction *fun, bool lines, bool recursive, +DisassembleScript(JSContext *cx, JSScript *script_, JSFunction *fun, bool lines, bool recursive, Sprinter *sp) { + RootedVar<JSScript*> script(cx, script_); + if (fun && (fun->flags & ~7U)) { uint16_t flags = fun->flags; Sprint(sp, "flags:"); #define SHOW_FLAG(flag) if (flags & JSFUN_##flag) Sprint(sp, " " #flag); SHOW_FLAG(LAMBDA); SHOW_FLAG(HEAVYWEIGHT); @@ -1747,18 +1749,16 @@ DisassembleScript(JSContext *cx, JSScrip #undef SHOW_FLAG if (fun->isNullClosure()) Sprint(sp, " NULL_CLOSURE"); Sprint(sp, "\n"); } - Root<JSScript*> scriptRoot(cx, &script); - if (!js_Disassemble(cx, script, lines, sp)) return false; SrcNotes(cx, script, sp); TryNotes(cx, script, sp); if (recursive && script->hasObjects()) { ObjectArray *objects = script->objects(); for (unsigned i = 0; i != objects->length; ++i) { @@ -4655,19 +4655,19 @@ NewGlobalObject(JSContext *cx, Compartme if (compartment == NEW_COMPARTMENT && !JS_WrapObject(cx, glob.address())) return NULL; return glob; } static bool -BindScriptArgs(JSContext *cx, JSObject *obj, OptionParser *op) +BindScriptArgs(JSContext *cx, JSObject *obj_, OptionParser *op) { - RootObject root(cx, &obj); + RootedVarObject obj(cx, obj_); MultiStringRange msr = op->getMultiStringArg("scriptArgs"); RootedVarObject scriptArgs(cx); scriptArgs = JS_NewArrayObject(cx, 0, NULL); if (!scriptArgs) return false; /* @@ -4688,19 +4688,19 @@ BindScriptArgs(JSContext *cx, JSObject * return false; } } return true; } static int -ProcessArgs(JSContext *cx, JSObject *obj, OptionParser *op) +ProcessArgs(JSContext *cx, JSObject *obj_, OptionParser *op) { - RootObject root(cx, &obj); + RootedVarObject obj(cx, obj_); if (op->getBoolOption('a')) JS_ToggleOptions(cx, JSOPTION_METHODJIT_ALWAYS); if (op->getBoolOption('c')) compileOnly = true; if (op->getBoolOption('m')) {
--- a/js/src/shell/jsheaptools.cpp +++ b/js/src/shell/jsheaptools.cpp @@ -476,49 +476,49 @@ ReferenceFinder::Path::computeName(JSCon } } JS_ASSERT(next + 1 == path + size); return path; } bool -ReferenceFinder::addReferrer(jsval referrer, Path *path) +ReferenceFinder::addReferrer(jsval referrer_, Path *path) { - if (!context->compartment->wrap(context, &referrer)) + RootedVar<jsval> referrer(context, referrer_); + + if (!context->compartment->wrap(context, referrer.address())) return NULL; char *pathName = path->computeName(context); if (!pathName) return false; AutoReleasePtr releasePathName(context, pathName); - Root<jsval> referrerRoot(context, &referrer); - /* Find the property of the results object named |pathName|. */ JS::Value v; if (!JS_GetProperty(context, result, pathName, &v)) return false; if (v.isUndefined()) { /* Create an array to accumulate referents under this path. */ - JSObject *array = JS_NewArrayObject(context, 1, &referrer); + JSObject *array = JS_NewArrayObject(context, 1, referrer.address()); if (!array) return false; v.setObject(*array); return !!JS_SetProperty(context, result, pathName, &v); } /* The property's value had better be an array. */ RootedVarObject array(context, &v.toObject()); JS_ASSERT(JS_IsArrayObject(context, array)); /* Append our referrer to this array. */ uint32_t length; return JS_GetArrayLength(context, array, &length) && - JS_SetElement(context, array, length, &referrer); + JS_SetElement(context, array, length, referrer.address()); } JSObject * ReferenceFinder::findReferences(HandleObject target) { result = JS_NewObject(context, NULL, NULL, NULL); if (!result) return NULL;
--- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -745,26 +745,26 @@ Debugger::resultToCompletion(JSContext * cx->clearPendingException(); } else { *status = JSTRAP_ERROR; value->setUndefined(); } } bool -Debugger::newCompletionValue(JSContext *cx, JSTrapStatus status, Value value, Value *result) +Debugger::newCompletionValue(JSContext *cx, JSTrapStatus status, Value value_, Value *result) { /* * We must be in the debugger's compartment, since that's where we want * to construct the completion value. */ assertSameCompartment(cx, object.get()); RootedVarId key(cx); - RootValue valueRoot(cx, &value); + RootedVarValue value(cx, value_); switch (status) { case JSTRAP_RETURN: key = NameToId(cx->runtime->atomState.returnAtom); break; case JSTRAP_THROW: key = NameToId(cx->runtime->atomState.throwAtom); @@ -776,17 +776,17 @@ Debugger::newCompletionValue(JSContext * default: JS_NOT_REACHED("bad status passed to Debugger::newCompletionValue"); } /* Common tail for JSTRAP_RETURN and JSTRAP_THROW. */ RootedVarObject obj(cx, NewBuiltinClassInstance(cx, &ObjectClass)); if (!obj || - !wrapDebuggeeValue(cx, &value) || + !wrapDebuggeeValue(cx, value.address()) || !DefineNativeProperty(cx, obj, key, value, JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0)) { return false; } result->setObject(*obj); return true; @@ -4434,34 +4434,34 @@ static JSFunctionSpec DebuggerEnv_method JS_FS_END }; /*** Glue ****************************************************************************************/ extern JS_PUBLIC_API(JSBool) -JS_DefineDebuggerObject(JSContext *cx, JSObject *obj) +JS_DefineDebuggerObject(JSContext *cx, JSObject *obj_) { - RootObject objRoot(cx, &obj); + RootedVarObject obj(cx, obj_); RootedVarObject objProto(cx), debugCtor(cx), debugProto(cx), frameProto(cx), scriptProto(cx), objectProto(cx); objProto = obj->asGlobal().getOrCreateObjectPrototype(cx); if (!objProto) return false; - debugProto = js_InitClass(cx, objRoot, + debugProto = js_InitClass(cx, obj, objProto, &Debugger::jsclass, Debugger::construct, 1, Debugger::properties, Debugger::methods, NULL, NULL, debugCtor.address()); if (!debugProto) return false; frameProto = js_InitClass(cx, debugCtor, objProto, &DebuggerFrame_class, DebuggerFrame_construct, 0,
--- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -392,32 +392,31 @@ GlobalObject::createBlankPrototype(JSCon JSObject * GlobalObject::createBlankPrototypeInheriting(JSContext *cx, Class *clasp, JSObject &proto) { return CreateBlankProto(cx, clasp, proto, *this); } bool -LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto) +LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor_, JSObject *proto_) { - RootObject ctorRoot(cx, &ctor); - RootObject protoRoot(cx, &proto); + RootedVarObject ctor(cx, ctor_), proto(cx, proto_); return ctor->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom, ObjectValue(*proto), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY) && proto->defineProperty(cx, cx->runtime->atomState.constructorAtom, ObjectValue(*ctor), JS_PropertyStub, JS_StrictPropertyStub, 0); } bool -DefinePropertiesAndBrand(JSContext *cx, JSObject *obj, JSPropertySpec *ps, JSFunctionSpec *fs) +DefinePropertiesAndBrand(JSContext *cx, JSObject *obj_, JSPropertySpec *ps, JSFunctionSpec *fs) { - RootObject root(cx, &obj); + RootedVarObject obj(cx, obj_); if ((ps && !JS_DefineProperties(cx, obj, ps)) || (fs && !JS_DefineFunctions(cx, obj, fs))) return false; return true; } void GlobalDebuggees_finalize(FreeOp *fop, JSObject *obj)
--- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -181,114 +181,104 @@ class GlobalObject : public JSObject /* * Identical to createBlankPrototype, but uses proto as the [[Prototype]] * of the returned blank prototype. */ JSObject *createBlankPrototypeInheriting(JSContext *cx, js::Class *clasp, JSObject &proto); JSObject *getOrCreateObjectPrototype(JSContext *cx) { - GlobalObject *self = this; - if (!functionObjectClassesInitialized()) { - Root<GlobalObject*> root(cx, &self); - if (!initFunctionAndObjectClasses(cx)) - return NULL; - } + if (functionObjectClassesInitialized()) + return &getPrototype(JSProto_Object).toObject(); + RootedVar<GlobalObject*> self(cx, this); + if (!initFunctionAndObjectClasses(cx)) + return NULL; return &self->getPrototype(JSProto_Object).toObject(); } JSObject *getOrCreateFunctionPrototype(JSContext *cx) { - GlobalObject *self = this; - if (!functionObjectClassesInitialized()) { - Root<GlobalObject*> root(cx, &self); - if (!initFunctionAndObjectClasses(cx)) - return NULL; - } + if (functionObjectClassesInitialized()) + return &getPrototype(JSProto_Function).toObject(); + RootedVar<GlobalObject*> self(cx, this); + if (!initFunctionAndObjectClasses(cx)) + return NULL; return &self->getPrototype(JSProto_Function).toObject(); } JSObject *getOrCreateArrayPrototype(JSContext *cx) { - GlobalObject *self = this; - if (!arrayClassInitialized()) { - Root<GlobalObject*> root(cx, &self); - if (!js_InitArrayClass(cx, this)) - return NULL; - } + if (arrayClassInitialized()) + return &getPrototype(JSProto_Array).toObject(); + RootedVar<GlobalObject*> self(cx, this); + if (!js_InitArrayClass(cx, this)) + return NULL; return &self->getPrototype(JSProto_Array).toObject(); } JSObject *getOrCreateBooleanPrototype(JSContext *cx) { - GlobalObject *self = this; - if (!booleanClassInitialized()) { - Root<GlobalObject*> root(cx, &self); - if (!js_InitBooleanClass(cx, this)) - return NULL; - } + if (booleanClassInitialized()) + return &getPrototype(JSProto_Boolean).toObject(); + RootedVar<GlobalObject*> self(cx, this); + if (!js_InitBooleanClass(cx, this)) + return NULL; return &self->getPrototype(JSProto_Boolean).toObject(); } JSObject *getOrCreateNumberPrototype(JSContext *cx) { - GlobalObject *self = this; - if (!numberClassInitialized()) { - Root<GlobalObject*> root(cx, &self); - if (!js_InitNumberClass(cx, this)) - return NULL; - } + if (numberClassInitialized()) + return &getPrototype(JSProto_Number).toObject(); + RootedVar<GlobalObject*> self(cx, this); + if (!js_InitNumberClass(cx, this)) + return NULL; return &self->getPrototype(JSProto_Number).toObject(); } JSObject *getOrCreateStringPrototype(JSContext *cx) { - GlobalObject *self = this; - if (!stringClassInitialized()) { - Root<GlobalObject*> root(cx, &self); - if (!js_InitStringClass(cx, this)) - return NULL; - } + if (stringClassInitialized()) + return &getPrototype(JSProto_String).toObject(); + RootedVar<GlobalObject*> self(cx, this); + if (!js_InitStringClass(cx, this)) + return NULL; return &self->getPrototype(JSProto_String).toObject(); } JSObject *getOrCreateRegExpPrototype(JSContext *cx) { - GlobalObject *self = this; - if (!regexpClassInitialized()) { - Root<GlobalObject*> root(cx, &self); - if (!js_InitRegExpClass(cx, this)) - return NULL; - } + if (regexpClassInitialized()) + return &getPrototype(JSProto_RegExp).toObject(); + RootedVar<GlobalObject*> self(cx, this); + if (!js_InitRegExpClass(cx, this)) + return NULL; return &self->getPrototype(JSProto_RegExp).toObject(); } JSObject *getOrCreateArrayBufferPrototype(JSContext *cx) { - GlobalObject *self = this; - if (!arrayBufferClassInitialized()) { - Root<GlobalObject*> root(cx, &self); - if (!js_InitTypedArrayClasses(cx, this)) - return NULL; - } + if (arrayBufferClassInitialized()) + return &getPrototype(JSProto_ArrayBuffer).toObject(); + RootedVar<GlobalObject*> self(cx, this); + if (!js_InitTypedArrayClasses(cx, this)) + return NULL; return &self->getPrototype(JSProto_ArrayBuffer).toObject(); } JSObject *getOrCreateCustomErrorPrototype(JSContext *cx, int exnType) { - GlobalObject *self = this; JSProtoKey key = GetExceptionProtoKey(exnType); - if (!errorClassesInitialized()) { - Root<GlobalObject*> root(cx, &self); - if (!js_InitExceptionClasses(cx, this)) - return NULL; - } + if (errorClassesInitialized()) + return &getPrototype(key).toObject(); + RootedVar<GlobalObject*> self(cx, this); + if (!js_InitExceptionClasses(cx, this)) + return NULL; return &self->getPrototype(key).toObject(); } JSObject *getOrCreateGeneratorPrototype(JSContext *cx) { - GlobalObject *self = this; Value v = getSlotRef(GENERATOR_PROTO); - if (!v.isObject()) { - Root<GlobalObject*> root(cx, &self); - if (!js_InitIteratorClasses(cx, this)) - return NULL; - } + if (v.isObject()) + return &v.toObject(); + RootedVar<GlobalObject*> self(cx, this); + if (!js_InitIteratorClasses(cx, this)) + return NULL; return &self->getSlot(GENERATOR_PROTO).toObject(); } inline RegExpStatics *getRegExpStatics() const; JSObject *getThrowTypeError() const { JS_ASSERT(functionObjectClassesInitialized()); return &getSlot(THROWTYPEERROR).toObject();
--- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -222,23 +222,33 @@ struct PropDesc { bool checkSetter(JSContext *cx); bool unwrapDebuggerObjectsInto(JSContext *cx, Debugger *dbg, JSObject *obj, PropDesc *unwrapped) const; bool wrapInto(JSContext *cx, JSObject *obj, const jsid &id, jsid *wrappedId, PropDesc *wrappedDesc) const; - struct StackRoot { - StackRoot(JSContext *cx, PropDesc *pd) - : pdRoot(cx, &pd->pd_), valueRoot(cx, &pd->value_), - getRoot(cx, &pd->get_), setRoot(cx, &pd->set_) - {} - RootValue pdRoot, valueRoot, getRoot, setRoot; - }; + class AutoRooter : private AutoGCRooter + { + public: + explicit AutoRooter(JSContext *cx, PropDesc *pd_ + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, PROPDESC), pd(pd_), skip(cx, pd_) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + PropDesc *pd; + SkipRoot skip; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + }; }; class DenseElementsHeader; class SparseElementsHeader; class Uint8ElementsHeader; class Int8ElementsHeader; class Uint16ElementsHeader; class Int16ElementsHeader;
--- a/js/src/vm/RegExpStatics.h +++ b/js/src/vm/RegExpStatics.h @@ -204,34 +204,41 @@ class RegExpStatics /* Substring creators. */ void getParen(size_t pairNum, JSSubString *out) const; void getLastMatch(JSSubString *out) const; void getLastParen(JSSubString *out) const; void getLeftContext(JSSubString *out) const; void getRightContext(JSSubString *out) const; - class StackRoot + class AutoRooter : private AutoGCRooter { - Root<JSLinearString*> matchPairsInputRoot; - RootString pendingInputRoot; + public: + explicit AutoRooter(JSContext *cx, RegExpStatics *statics_ + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, REGEXPSTATICS), statics(statics_), skip(cx, statics_) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } - public: - StackRoot(JSContext *cx, RegExpStatics *buffer) - : matchPairsInputRoot(cx, (JSLinearString**) &buffer->matchPairsInput), - pendingInputRoot(cx, (JSString**) &buffer->pendingInput) - {} + friend void AutoGCRooter::trace(JSTracer *trc); + void trace(JSTracer *trc); + + private: + RegExpStatics *statics; + SkipRoot skip; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; }; class PreserveRegExpStatics { RegExpStatics * const original; RegExpStatics buffer; - RegExpStatics::StackRoot bufferRoot; + RegExpStatics::AutoRooter bufferRoot; public: explicit PreserveRegExpStatics(JSContext *cx, RegExpStatics *original) : original(original), buffer(RegExpStatics::InitBuffer()), bufferRoot(cx, &buffer) {}
--- a/js/src/vm/String-inl.h +++ b/js/src/vm/String-inl.h @@ -108,28 +108,28 @@ JSDependentString::init(JSLinearString * JS_ASSERT(!js::IsPoisonedPtr(base)); d.lengthAndFlags = buildLengthAndFlags(length, DEPENDENT_BIT); d.u1.chars = chars; d.s.u2.base = base; JSString::writeBarrierPost(d.s.u2.base, &d.s.u2.base); } JS_ALWAYS_INLINE JSDependentString * -JSDependentString::new_(JSContext *cx, JSLinearString *base, const jschar *chars, size_t length) +JSDependentString::new_(JSContext *cx, JSLinearString *base_, const jschar *chars, size_t length) { + JS::RootedVar<JSLinearString*> base(cx, base_); + /* Try to avoid long chains of dependent strings. */ while (base->isDependent()) base = base->asDependent().base(); JS_ASSERT(base->isFlat()); JS_ASSERT(chars >= base->chars() && chars < base->chars() + base->length()); JS_ASSERT(length <= base->length() - (chars - base->chars())); - JS::Root<JSLinearString*> baseRoot(cx, &base); - /* * The characters may be an internal pointer to a GC thing, so prevent them * from being overwritten. For now this prevents strings used as dependent * bases of other strings from being moved by the GC. */ JS::SkipRoot charsRoot(cx, &chars); JSDependentString *str = (JSDependentString *)js_NewGCString(cx);