Remove Root<T>, bug 756823. r=billm
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 24 May 2012 08:52:21 -0700
changeset 94823 779d3807d806499d655db9371119ccfc7d547ad6
parent 94822 54370e2a5963ad98ab1f0d005d245086babf40c7
child 94824 d76b9c64e4575758fd44599c79cff98a960ca8bf
push id9824
push userbhackett@mozilla.com
push dateThu, 24 May 2012 15:52:34 +0000
treeherdermozilla-inbound@779d3807d806 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs756823
milestone15.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
Remove Root<T>, bug 756823. r=billm
js/src/builtin/MapObject.cpp
js/src/builtin/MapObject.h
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/TreeContext.h
js/src/gc/Root.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jscntxtinlines.h
js/src/jsfriendapi.cpp
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsinfer.cpp
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jspropertytree.cpp
js/src/jsprvtd.h
js/src/jspubtd.h
js/src/jsreflect.cpp
js/src/jsscope.cpp
js/src/jsscope.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jstypedarray.cpp
js/src/shell/js.cpp
js/src/shell/jsheaptools.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
js/src/vm/ObjectImpl.h
js/src/vm/RegExpStatics.h
js/src/vm/String-inl.h
--- 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);