Bug 548702 - Temporary value-rooting scheme should be C++- and RAII-based, not macro-based. r=igor
authorJeff Walden <jwalden@mit.edu>
Mon, 11 Jan 2010 11:52:21 -0600
changeset 40221 e7065853ef79e2dfe231b2bd8145647edc4fa3a4
parent 39942 24b2678b458d8345f06b40d0b08aa32f07fbc777
child 40222 54ce0245d0951322a8657c0776ad9398dbc8b3d7
child 40378 81494bc56f63ce7f68ffc6c0fded8423713b31aa
push idunknown
push userunknown
push dateunknown
reviewersigor
bugs548702
milestone1.9.3a2pre
Bug 548702 - Temporary value-rooting scheme should be C++- and RAII-based, not macro-based. r=igor
content/canvas/src/CustomQS_WebGL.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
js/ctypes/Function.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsinterp.cpp
js/src/jsiter.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/json.h
js/src/jsopcode.cpp
js/src/jsparse.cpp
js/src/jsparse.h
js/src/jsprvtd.h
js/src/jsregexp.cpp
js/src/jsregexp.h
js/src/jsscript.cpp
js/src/jsstr.cpp
js/src/jstracer.cpp
js/src/jstypedarray.cpp
js/src/jsutil.h
js/src/jsvector.h
js/src/jsxml.cpp
js/src/jsxml.h
js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
js/src/xpconnect/src/XPCNativeWrapper.cpp
js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
js/src/xpconnect/src/XPCWrapper.cpp
js/src/xpconnect/src/qsgen.py
js/src/xpconnect/src/xpcconvert.cpp
js/src/xpconnect/src/xpcquickstubs.cpp
js/src/xpconnect/src/xpcquickstubs.h
js/src/xpconnect/src/xpcwrappednativejsops.cpp
js/src/xpconnect/tests/TestXPC.cpp
modules/plugin/base/src/nsJSNPRuntime.cpp
modules/plugin/base/src/nsNPAPIPlugin.cpp
xpinstall/src/nsXPITriggerInfo.cpp
--- a/content/canvas/src/CustomQS_WebGL.h
+++ b/content/canvas/src/CustomQS_WebGL.h
@@ -63,17 +63,17 @@ nsICanvasRenderingContextWebGL_BufferDat
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
-    JSAutoTempValueRooter tvr(cx);
+    js::AutoValueRooter tvr(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
         return JS_FALSE;
 
     if (argc < 3)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
@@ -129,17 +129,17 @@ nsICanvasRenderingContextWebGL_BufferSub
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
-    JSAutoTempValueRooter tvr(cx);
+    js::AutoValueRooter tvr(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
         return JS_FALSE;
 
     if (argc < 3)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
@@ -199,17 +199,17 @@ nsICanvasRenderingContextWebGL_TexImage2
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
-    JSAutoTempValueRooter tvr(cx);
+    js::AutoValueRooter tvr(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
         return JS_FALSE;
 
     if (argc < 3)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
@@ -301,17 +301,17 @@ nsICanvasRenderingContextWebGL_TexSubIma
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
-    JSAutoTempValueRooter tvr(cx);
+    js::AutoValueRooter tvr(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
         return JS_FALSE;
 
     if (argc < 7 || (argc > 7 && argc < 9))
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
@@ -402,17 +402,17 @@ helper_nsICanvasRenderingContextWebGL_Un
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
-    JSAutoTempValueRooter tvr(cx);
+    js::AutoValueRooter tvr(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
         return JS_FALSE;
 
     if (argc < 2)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
@@ -422,17 +422,17 @@ helper_nsICanvasRenderingContextWebGL_Un
 
     if (!JSVAL_IS_OBJECT(argv[1])) {
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
         return JS_FALSE;
     }
 
     JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]);
 
-    JSAutoTempValueRooter obj_tvr(cx);
+    js::AutoValueRooter obj_tvr(cx);
 
     js::TypedArray *wa = 0;
 
     if (helper_isInt32Array(arg1)) {
         wa = js::TypedArray::fromJSObject(arg1);
     }  else if (JS_IsArrayObject(cx, arg1)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_INT32, arg1);
         if (!nobj) {
@@ -472,17 +472,17 @@ helper_nsICanvasRenderingContextWebGL_Un
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
-    JSAutoTempValueRooter tvr(cx);
+    js::AutoValueRooter tvr(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
         return JS_FALSE;
 
     if (argc < 2)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
@@ -492,17 +492,17 @@ helper_nsICanvasRenderingContextWebGL_Un
 
     if (!JSVAL_IS_OBJECT(argv[1])) {
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
         return JS_FALSE;
     }
 
     JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]);
 
-    JSAutoTempValueRooter obj_tvr(cx);
+    js::AutoValueRooter obj_tvr(cx);
 
     js::TypedArray *wa = 0;
 
     if (helper_isFloat32Array(arg1)) {
         wa = js::TypedArray::fromJSObject(arg1);
     }  else if (JS_IsArrayObject(cx, arg1)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg1);
         if (!nobj) {
@@ -542,17 +542,17 @@ helper_nsICanvasRenderingContextWebGL_Un
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
-    JSAutoTempValueRooter tvr(cx);
+    js::AutoValueRooter tvr(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
         return JS_FALSE;
 
     if (argc < 3)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
@@ -566,17 +566,17 @@ helper_nsICanvasRenderingContextWebGL_Un
 
     if (!JSVAL_IS_OBJECT(argv[2])) {
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 2);
         return JS_FALSE;
     }
 
     JSObject *arg2 = JSVAL_TO_OBJECT(argv[2]);
 
-    JSAutoTempValueRooter obj_tvr(cx);
+    js::AutoValueRooter obj_tvr(cx);
 
     js::TypedArray *wa = 0;
 
     if (helper_isFloat32Array(arg2)) {
         wa = js::TypedArray::fromJSObject(arg2);
     }  else if (JS_IsArrayObject(cx, arg2)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg2);
         if (!nobj) {
@@ -613,17 +613,17 @@ helper_nsICanvasRenderingContextWebGL_Ve
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
-    JSAutoTempValueRooter tvr(cx);
+    js::AutoValueRooter tvr(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
         return JS_FALSE;
 
     if (argc < 2)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
@@ -633,17 +633,17 @@ helper_nsICanvasRenderingContextWebGL_Ve
 
     if (!JSVAL_IS_OBJECT(argv[1])) {
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
         return JS_FALSE;
     }
 
     JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]);
 
-    JSAutoTempValueRooter obj_tvr(cx);
+    js::AutoValueRooter obj_tvr(cx);
 
     js::TypedArray *wa = 0;
 
     if (helper_isFloat32Array(arg1)) {
         wa = js::TypedArray::fromJSObject(arg1);
     }  else if (JS_IsArrayObject(cx, arg1)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg1);
         if (!nobj) {
@@ -775,17 +775,17 @@ helper_nsICanvasRenderingContextWebGL_Un
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
     xpc_qsArgValArray<3> vp(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
         js_SetTraceableNativeFailed(cx);
         return JSVAL_VOID;
     }
 
-    JSAutoTempValueRooter obj_tvr(cx);
+    js::AutoValueRooter obj_tvr(cx);
 
     js::TypedArray *wa = 0;
 
     if (helper_isInt32Array(arg)) {
         wa = js::TypedArray::fromJSObject(arg);
     }  else if (JS_IsArrayObject(cx, arg)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_INT32, arg);
         if (!nobj) {
@@ -830,17 +830,17 @@ helper_nsICanvasRenderingContextWebGL_Un
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
     xpc_qsArgValArray<3> vp(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
         js_SetTraceableNativeFailed(cx);
         return JSVAL_VOID;
     }
 
-    JSAutoTempValueRooter obj_tvr(cx);
+    js::AutoValueRooter obj_tvr(cx);
 
     js::TypedArray *wa = 0;
 
     if (helper_isFloat32Array(arg)) {
         wa = js::TypedArray::fromJSObject(arg);
     }  else if (JS_IsArrayObject(cx, arg)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg);
         if (!nobj) {
@@ -885,17 +885,17 @@ helper_nsICanvasRenderingContextWebGL_Un
     nsICanvasRenderingContextWebGL *self;
     xpc_qsSelfRef selfref;
     xpc_qsArgValArray<4> vp(cx);
     if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
         js_SetTraceableNativeFailed(cx);
         return JSVAL_VOID;
     }
 
-    JSAutoTempValueRooter obj_tvr(cx);
+    js::AutoValueRooter obj_tvr(cx);
 
     js::TypedArray *wa = 0;
 
     if (helper_isFloat32Array(arg)) {
         wa = js::TypedArray::fromJSObject(arg);
     }  else if (JS_IsArrayObject(cx, arg)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg);
         if (!nobj) {
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2106,24 +2106,23 @@ nsJSContext::CallEventHandler(nsISupport
                               nsIArray *aargv, nsIVariant **arv)
 {
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   if (!mScriptsEnabled) {
     return NS_OK;
   }
 
-  jsval targetVal = JSVAL_VOID;
-  JSAutoTempValueRooter tvr(mContext, 1, &targetVal);
+  js::AutoValueRooter targetVal(mContext, JSVAL_VOID);
 
   JSObject* target = nsnull;
   nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  targetVal = OBJECT_TO_JSVAL(target);
+  targetVal.setObject(target);
 
   jsval rval = JSVAL_VOID;
 
   // This one's a lot easier than EvaluateString because we don't have to
   // hassle with principals: they're already compiled into the JS function.
   // xxxmarkh - this comment is no longer true - principals are not used at
   // all now, and never were in some cases.
 
@@ -2138,17 +2137,17 @@ nsJSContext::CallEventHandler(nsISupport
   nsJSContext::TerminationFuncHolder holder(this);
 
   if (NS_SUCCEEDED(rv)) {
     // Convert args to jsvals.
     PRUint32 argc = 0;
     jsval *argv = nsnull;
 
     js::LazilyConstructed<nsAutoPoolRelease> poolRelease;
-    js::LazilyConstructed<JSAutoTempValueRooter> tvr;
+    js::LazilyConstructed<js::AutoArrayRooter> tvr;
 
     // Use |target| as the scope for wrapping the arguments, since aScope is
     // the safe scope in many cases, which isn't very useful.  Wrapping aTarget
     // was OK because those typically have PreCreate methods that give them the
     // right scope anyway, and we want to make sure that the arguments end up
     // in the same scope as aTarget.
     rv = ConvertSupportsTojsvals(aargv, target, &argc,
                                  &argv, poolRelease, tvr);
@@ -2650,17 +2649,17 @@ nsresult
 nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArgs)
 {
   PRUint32  argc;
   jsval    *argv = nsnull;
 
   JSAutoRequest ar(mContext);
 
   js::LazilyConstructed<nsAutoPoolRelease> poolRelease;
-  js::LazilyConstructed<JSAutoTempValueRooter> tvr;
+  js::LazilyConstructed<js::AutoArrayRooter> tvr;
 
   nsresult rv;
   rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc,
                                &argv, poolRelease, tvr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   jsval vargs;
 
@@ -2685,17 +2684,17 @@ nsJSContext::SetProperty(void *aTarget, 
 }
 
 nsresult
 nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
                                      void *aScope,
                                      PRUint32 *aArgc,
                                      jsval **aArgv,
                                      js::LazilyConstructed<nsAutoPoolRelease> &aPoolRelease,
-                                     js::LazilyConstructed<JSAutoTempValueRooter> &aRooter)
+                                     js::LazilyConstructed<js::AutoArrayRooter> &aRooter)
 {
   nsresult rv = NS_OK;
 
   // If the array implements nsIJSArgArray, just grab the values directly.
   nsCOMPtr<nsIJSArgArray> fastArray = do_QueryInterface(aArgs);
   if (fastArray != nsnull)
     return fastArray->GetArgs(aArgc, reinterpret_cast<void **>(aArgv));
 
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -44,18 +44,21 @@
 #include "nsIObserver.h"
 #include "nsIXPCScriptNotify.h"
 #include "prtime.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsScriptNameSpaceManager.h"
 
 class nsIXPConnectJSObjectHolder;
 class nsAutoPoolRelease;
-class JSAutoTempValueRooter;
-namespace js { template <class> class LazilyConstructed; }
+namespace js {
+class AutoValueRooter;
+class AutoArrayRooter;
+template <class> class LazilyConstructed;
+}
 
 class nsJSContext : public nsIScriptContext,
                     public nsIXPCScriptNotify
 {
 public:
   nsJSContext(JSRuntime *aRuntime);
   virtual ~nsJSContext();
 
@@ -210,17 +213,17 @@ protected:
   nsresult InitializeExternalClasses();
 
   // Helper to convert xpcom datatypes to jsvals.
   nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
                                    void *aScope,
                                    PRUint32 *aArgc,
                                    jsval **aArgv,
                                    js::LazilyConstructed<nsAutoPoolRelease> &aPoolRelease,
-                                   js::LazilyConstructed<JSAutoTempValueRooter> &aRooter);
+                                   js::LazilyConstructed<js::AutoArrayRooter> &aRooter);
 
   nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv);
 
   // given an nsISupports object (presumably an event target or some other
   // DOM object), get (or create) the JSObject wrapping it.
   nsresult JSObjectFromInterface(nsISupports *aSup, void *aScript, 
                                  JSObject **aRet);
 
--- a/js/ctypes/Function.cpp
+++ b/js/ctypes/Function.cpp
@@ -619,17 +619,17 @@ Function::Create(JSContext* aContext,
 
   // create and root the new JS function object
   JSFunction* fn = JS_NewFunction(aContext, JSNative(Function::Call),
                      aArgLength, JSFUN_FAST_NATIVE, NULL, aName);
   if (!fn)
     return NULL;
 
   JSObject* fnObj = JS_GetFunctionObject(fn);
-  JSAutoTempValueRooter fnRoot(aContext, fnObj);
+  js::AutoValueRooter fnRoot(aContext, fnObj);
 
   // stash a pointer to self, which Function::Call will need at call time
   if (!JS_SetReservedSlot(aContext, fnObj, 0, PRIVATE_TO_JSVAL(self.get())))
     return NULL;
 
   // make a strong reference to the library for GC-safety
   if (!JS_SetReservedSlot(aContext, fnObj, 1, OBJECT_TO_JSVAL(aLibrary)))
     return NULL;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -433,63 +433,63 @@ JS_ValueToSource(JSContext *cx, jsval v)
     return js_ValueToSource(cx, v);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
 {
     CHECK_REQUEST(cx);
 
-    JSAutoTempValueRooter tvr(cx, v);
+    AutoValueRooter tvr(cx, v);
     *dp = js_ValueToNumber(cx, tvr.addr());
     return !JSVAL_IS_NULL(tvr.value());
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DoubleIsInt32(jsdouble d, jsint *ip)
 {
     return JSDOUBLE_IS_INT(d, *ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
 {
     CHECK_REQUEST(cx);
 
-    JSAutoTempValueRooter tvr(cx, v);
+    AutoValueRooter tvr(cx, v);
     *ip = js_ValueToECMAInt32(cx, tvr.addr());
     return !JSVAL_IS_NULL(tvr.value());
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
 {
     CHECK_REQUEST(cx);
 
-    JSAutoTempValueRooter tvr(cx, v);
+    AutoValueRooter tvr(cx, v);
     *ip = js_ValueToECMAUint32(cx, tvr.addr());
     return !JSVAL_IS_NULL(tvr.value());
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
 {
     CHECK_REQUEST(cx);
 
-    JSAutoTempValueRooter tvr(cx, v);
+    AutoValueRooter tvr(cx, v);
     *ip = js_ValueToInt32(cx, tvr.addr());
     return !JSVAL_IS_NULL(tvr.value());
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
 {
     CHECK_REQUEST(cx);
 
-    JSAutoTempValueRooter tvr(cx, v);
+    AutoValueRooter tvr(cx, v);
     *ip = js_ValueToUint16(cx, tvr.addr());
     return !JSVAL_IS_NULL(tvr.value());
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
 {
     CHECK_REQUEST(cx);
@@ -3054,17 +3054,17 @@ LookupResult(JSContext *cx, JSObject *ob
         return JS_TRUE;
     }
 
     JSBool ok = JS_TRUE;
     if (OBJ_IS_NATIVE(obj2)) {
         JSScopeProperty *sprop = (JSScopeProperty *) prop;
 
         if (sprop->isMethod()) {
-            JSAutoTempValueRooter root(cx, sprop);
+            AutoScopePropertyRooter root(cx, sprop);
             JS_UNLOCK_OBJ(cx, obj2);
             *vp = sprop->methodValue();
             return OBJ_SCOPE(obj2)->methodReadBarrier(cx, sprop, vp);
         }
 
         /* Peek at the native property's slot value, without doing a Get. */
         *vp = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
                ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
@@ -3805,29 +3805,28 @@ JS_ClearScope(JSContext *cx, JSObject *o
             JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
     }
 }
 
 JS_PUBLIC_API(JSIdArray *)
 JS_Enumerate(JSContext *cx, JSObject *obj)
 {
     jsint i, n;
-    jsval iter_state, num_properties;
     jsid id;
     JSIdArray *ida;
     jsval *vector;
 
     CHECK_REQUEST(cx);
 
     ida = NULL;
-    iter_state = JSVAL_NULL;
-    JSAutoEnumStateRooter tvr(cx, obj, &iter_state);
+    AutoEnumStateRooter iterState(cx, obj);
 
     /* Get the number of properties to enumerate. */
-    if (!obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties))
+    jsval num_properties;
+    if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties))
         goto error;
     if (!JSVAL_IS_INT(num_properties)) {
         JS_ASSERT(0);
         goto error;
     }
 
     /* Grow as needed if we don't know the exact amount ahead of time. */
     n = JSVAL_TO_INT(num_properties);
@@ -3837,36 +3836,34 @@ JS_Enumerate(JSContext *cx, JSObject *ob
     /* Create an array of jsids large enough to hold all the properties */
     ida = NewIdArray(cx, n);
     if (!ida)
         goto error;
 
     i = 0;
     vector = &ida->vector[0];
     for (;;) {
-        if (!obj->enumerate(cx, JSENUMERATE_NEXT, &iter_state, &id))
+        if (!obj->enumerate(cx, JSENUMERATE_NEXT, iterState.addr(), &id))
             goto error;
 
         /* No more jsid's to enumerate ? */
-        if (iter_state == JSVAL_NULL)
+        if (iterState.state() == JSVAL_NULL)
             break;
 
         if (i == ida->length) {
             ida = SetIdArrayLength(cx, ida, ida->length * 2);
             if (!ida)
                 goto error;
             vector = &ida->vector[0];
         }
         vector[i++] = id;
     }
     return SetIdArrayLength(cx, ida, i);
 
 error:
-    if (!JSVAL_IS_NULL(iter_state))
-        obj->enumerate(cx, JSENUMERATE_DESTROY, &iter_state, 0);
     if (ida)
         JS_DestroyIdArray(cx, ida);
     return NULL;
 }
 
 /*
  * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
  *     prop_iterator_class somehow...
@@ -3940,17 +3937,17 @@ JS_NewPropertyIterator(JSContext *cx, JS
         index = -1;
     } else {
         /*
          * Non-native case: enumerate a JSIdArray and keep it via private.
          *
          * Note: we have to make sure that we root obj around the call to
          * JS_Enumerate to protect against multiple allocations under it.
          */
-        JSAutoTempValueRooter tvr(cx, iterobj);
+        AutoValueRooter tvr(cx, iterobj);
         ida = JS_Enumerate(cx, obj);
         if (!ida)
             return NULL;
         pdata = ida;
         index = ida->length;
     }
 
     /* iterobj cannot escape to other threads here. */
@@ -4590,35 +4587,37 @@ JS_CompileFileHandleForPrincipals(JSCont
                                        NULL, 0, file, filename, 1);
     LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewScriptObject(JSContext *cx, JSScript *script)
 {
-    JSTempValueRooter tvr;
     JSObject *obj;
 
     CHECK_REQUEST(cx);
     if (!script)
         return js_NewObject(cx, &js_ScriptClass, NULL, NULL);
 
     JS_ASSERT(!script->u.object);
 
-    JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr);
-    obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
-    if (obj) {
-        obj->setPrivate(script);
-        script->u.object = obj;
+    {
+        AutoScriptRooter root(cx, script);
+
+        obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
+        if (obj) {
+            obj->setPrivate(script);
+            script->u.object = obj;
 #ifdef CHECK_SCRIPT_OWNER
-        script->owner = NULL;
+            script->owner = NULL;
 #endif
+        }
     }
-    JS_POP_TEMP_ROOT(cx, &tvr);
+
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetScriptObject(JSScript *script)
 {
     return script->u.object;
 }
@@ -4686,17 +4685,16 @@ JS_CompileUCFunction(JSContext *cx, JSOb
 JS_PUBLIC_API(JSFunction *)
 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
                                   JSPrincipals *principals, const char *name,
                                   uintN nargs, const char **argnames,
                                   const jschar *chars, size_t length,
                                   const char *filename, uintN lineno)
 {
     JSFunction *fun;
-    JSTempValueRooter tvr;
     JSAtom *funAtom, *argAtom;
     uintN i;
 
     CHECK_REQUEST(cx);
     if (!name) {
         funAtom = NULL;
     } else {
         funAtom = js_Atomize(cx, name, strlen(name), 0);
@@ -4704,57 +4702,58 @@ JS_CompileUCFunctionForPrincipals(JSCont
             fun = NULL;
             goto out2;
         }
     }
     fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
     if (!fun)
         goto out2;
 
-    MUST_FLOW_THROUGH("out");
-    JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr);
-    for (i = 0; i < nargs; i++) {
-        argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
-        if (!argAtom) {
-            fun = NULL;
-            goto out;
+    {
+        AutoValueRooter tvr(cx, FUN_OBJECT(fun));
+        MUST_FLOW_THROUGH("out");
+
+        for (i = 0; i < nargs; i++) {
+            argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
+            if (!argAtom) {
+                fun = NULL;
+                goto out;
+            }
+            if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) {
+                fun = NULL;
+                goto out;
+            }
         }
-        if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) {
+
+        if (!JSCompiler::compileFunctionBody(cx, fun, principals,
+                                             chars, length, filename, lineno)) {
             fun = NULL;
             goto out;
         }
-    }
-
-    if (!JSCompiler::compileFunctionBody(cx, fun, principals,
-                                         chars, length, filename, lineno)) {
-        fun = NULL;
-        goto out;
-    }
-
-    if (obj &&
-        funAtom &&
-        !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)),
-                             NULL, NULL, JSPROP_ENUMERATE)) {
-        fun = NULL;
-    }
+
+        if (obj && funAtom &&
+            !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)),
+                                 NULL, NULL, JSPROP_ENUMERATE)) {
+            fun = NULL;
+        }
 
 #ifdef JS_SCOPE_DEPTH_METER
-    if (fun && obj) {
-        JSObject *pobj = obj;
-        uintN depth = 1;
-
-        while ((pobj = pobj->getParent()) != NULL)
-            ++depth;
-        JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
+        if (fun && obj) {
+            JSObject *pobj = obj;
+            uintN depth = 1;
+
+            while ((pobj = pobj->getParent()) != NULL)
+                ++depth;
+            JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
+        }
+#endif
+
+      out:
+        cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun;
     }
-#endif
-
-  out:
-    cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun;
-    JS_POP_TEMP_ROOT(cx, &tvr);
 
   out2:
     LAST_FRAME_CHECKS(cx, fun);
     return fun;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
@@ -4932,17 +4931,17 @@ JS_CallFunction(JSContext *cx, JSObject 
 }
 
 JS_PUBLIC_API(JSBool)
 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
                     jsval *argv, jsval *rval)
 {
     CHECK_REQUEST(cx);
 
-    JSAutoTempValueRooter tvr(cx);
+    AutoValueRooter tvr(cx);
     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     JSBool ok = atom &&
                 js_GetMethod(cx, obj, ATOM_TO_JSID(atom),
                              JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
                 js_InternalCall(cx, obj, tvr.value(), argc, argv, rval);
     LAST_FRAME_CHECKS(cx, ok);
     return ok;
 }
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -226,17 +226,17 @@ ValueIsLength(JSContext *cx, jsval* vp)
 JSBool
 js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
 {
     if (obj->isArray()) {
         *lengthp = obj->fslots[JSSLOT_ARRAY_LENGTH];
         return JS_TRUE;
     }
 
-    JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
+    AutoValueRooter tvr(cx, JSVAL_NULL);
     if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), tvr.addr()))
         return JS_FALSE;
 
     if (JSVAL_IS_INT(tvr.value())) {
         *lengthp = jsuint(jsint(JSVAL_TO_INT(tvr.value()))); /* jsuint cast does ToUint32 */
         return JS_TRUE;
     }
 
@@ -400,17 +400,17 @@ EnsureCapacity(JSContext *cx, JSObject *
         }
     }
     return JS_TRUE;
 }
 
 static bool
 ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp)
 {
-    JSAutoTempValueRooter dval(cx);
+    AutoValueRooter dval(cx);
     if (!js_NewDoubleInRootedValue(cx, index, dval.addr()) ||
         !js_ValueToStringId(cx, dval.value(), idp)) {
         return JS_FALSE;
     }
     return JS_TRUE;
 }
 
 static bool
@@ -445,17 +445,17 @@ GetArrayElement(JSContext *cx, JSObject 
 {
     JS_ASSERT(index >= 0);
     if (obj->isDenseArray() && index < js_DenseArrayCapacity(obj) &&
         (*vp = obj->dslots[jsuint(index)]) != JSVAL_HOLE) {
         *hole = JS_FALSE;
         return JS_TRUE;
     }
 
-    JSAutoTempIdRooter idr(cx);
+    AutoIdRooter idr(cx);
 
     *hole = JS_FALSE;
     if (!IndexToId(cx, obj, index, hole, idr.addr()))
         return JS_FALSE;
     if (*hole) {
         *vp = JSVAL_VOID;
         return JS_TRUE;
     }
@@ -500,17 +500,17 @@ SetArrayElement(JSContext *cx, JSObject 
                 return JS_TRUE;
             }
         }
 
         if (!js_MakeArraySlow(cx, obj))
             return JS_FALSE;
     }
 
-    JSAutoTempIdRooter idr(cx);
+    AutoIdRooter idr(cx);
 
     if (!IndexToId(cx, obj, index, NULL, idr.addr(), JS_TRUE))
         return JS_FALSE;
     JS_ASSERT(!JSVAL_IS_VOID(idr.id()));
 
     return obj->setProperty(cx, idr.id(), &v);
 }
 
@@ -526,17 +526,17 @@ DeleteArrayElement(JSContext *cx, JSObje
                     obj->fslots[JSSLOT_ARRAY_COUNT]--;
                 obj->dslots[idx] = JSVAL_HOLE;
                 return JS_TRUE;
             }
         }
         return JS_TRUE;
     }
 
-    JSAutoTempIdRooter idr(cx);
+    AutoIdRooter idr(cx);
 
     if (!IndexToId(cx, obj, index, NULL, idr.addr()))
         return JS_FALSE;
     if (JSVAL_IS_VOID(idr.id()))
         return JS_TRUE;
 
     jsval junk;
     return obj->deleteProperty(cx, idr.id(), &junk);
@@ -568,17 +568,17 @@ js_SetLengthProperty(JSContext *cx, JSOb
     id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
     return obj->setProperty(cx, id, &v);
 }
 
 JSBool
 js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
 {
     JSErrorReporter older = JS_SetErrorReporter(cx, NULL);
-    JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
+    AutoValueRooter tvr(cx, JSVAL_NULL);
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
     JSBool ok = obj->getProperty(cx, id, tvr.addr());
     JS_SetErrorReporter(cx, older);
     if (!ok)
         return false;
 
     *lengthp = ValueIsLength(cx, tvr.addr());
     return !JSVAL_IS_NULL(tvr.value());
@@ -621,90 +621,80 @@ array_length_getter(JSContext *cx, JSObj
     return JS_TRUE;
 }
 
 static JSBool
 array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
     jsuint newlen, oldlen, gap, index;
     jsval junk;
-    JSObject *iter;
-    JSTempValueRooter tvr;
-    JSBool ok;
 
     if (!obj->isArray()) {
         jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
 
         return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE);
     }
 
     newlen = ValueIsLength(cx, vp);
     if (JSVAL_IS_NULL(*vp))
-        return JS_FALSE;
+        return false;
     oldlen = obj->fslots[JSSLOT_ARRAY_LENGTH];
 
     if (oldlen == newlen)
-        return JS_TRUE;
+        return true;
 
     if (!IndexToValue(cx, newlen, vp))
-        return JS_FALSE;
+        return false;
 
     if (oldlen < newlen) {
         obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
-        return JS_TRUE;
+        return true;
     }
 
     if (obj->isDenseArray()) {
         /* Don't reallocate if we're not actually shrinking our slots. */
         jsuint capacity = js_DenseArrayCapacity(obj);
         if (capacity > newlen && !ResizeSlots(cx, obj, capacity, newlen))
-            return JS_FALSE;
+            return false;
     } else if (oldlen - newlen < (1 << 24)) {
         do {
             --oldlen;
-            if (!JS_CHECK_OPERATION_LIMIT(cx) ||
-                !DeleteArrayElement(cx, obj, oldlen)) {
-                return JS_FALSE;
-            }
+            if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, oldlen))
+                return false;
         } while (oldlen != newlen);
     } else {
         /*
          * We are going to remove a lot of indexes in a presumably sparse
          * array. So instead of looping through indexes between newlen and
          * oldlen, we iterate through all properties and remove those that
          * correspond to indexes in the half-open range [newlen, oldlen).  See
          * bug 322135.
          */
-        iter = JS_NewPropertyIterator(cx, obj);
+        JSObject *iter = JS_NewPropertyIterator(cx, obj);
         if (!iter)
-            return JS_FALSE;
+            return false;
 
         /* Protect iter against GC under JSObject::deleteProperty. */
-        JS_PUSH_TEMP_ROOT_OBJECT(cx, iter, &tvr);
+        AutoValueRooter tvr(cx, iter);
+
         gap = oldlen - newlen;
         for (;;) {
-            ok = (JS_CHECK_OPERATION_LIMIT(cx) &&
-                  JS_NextProperty(cx, iter, &id));
-            if (!ok)
-                break;
+            if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &id))
+                return false;
             if (JSVAL_IS_VOID(id))
                 break;
-            if (js_IdIsIndex(id, &index) && index - newlen < gap) {
-                ok = obj->deleteProperty(cx, id, &junk);
-                if (!ok)
-                    break;
+            if (js_IdIsIndex(id, &index) && index - newlen < gap &&
+                !obj->deleteProperty(cx, id, &junk)) {
+                return false;
             }
         }
-        JS_POP_TEMP_ROOT(cx, &tvr);
-        if (!ok)
-            return JS_FALSE;
     }
 
     obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
-    return JS_TRUE;
+    return true;
 }
 
 /*
  * We have only indexed properties up to capacity (excepting holes), plus the
  * length property. For all else, we delegate to the prototype.
  */
 static inline bool
 IsDenseArrayId(JSContext *cx, JSObject *obj, jsid id)
@@ -1513,17 +1503,17 @@ array_toString_sub(JSContext *cx, JSObje
         }
         genBefore = cx->busyArrays.generation();
     } else {
         /* Cycle, so return empty string. */
         *rval = ATOM_KEY(cx->runtime->atomState.emptyAtom);
         return true;
     }
 
-    JSAutoTempValueRooter tvr(cx, obj);
+    AutoValueRooter tvr(cx, obj);
 
     /* After this point, all paths exit through the 'out' label. */
     MUST_FLOW_THROUGH("out");
     bool ok = false;
 
     /* Get characters to use for the separator. */
     static const jschar comma = ',';
     const jschar *sep;
@@ -1647,17 +1637,17 @@ InitArrayElements(JSContext *cx, JSObjec
      * wouldn't otherwise make the array slow.
      */
     if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
         start <= MAXINDEX - count && !INDEX_TOO_BIG(start + count)) {
 
 #ifdef DEBUG_jwalden
         {
             /* Verify that overwriteType and writeType were accurate. */
-            JSAutoTempIdRooter idr(cx, JSVAL_ZERO);
+            AutoIdRooter idr(cx);
             for (jsuint i = 0; i < count; i++) {
                 JS_ASSERT_IF(vectorType == SourceVectorAllValues, vector[i] != JSVAL_HOLE);
 
                 jsdouble index = jsdouble(start) + i;
                 if (targetType == TargetElementsAllHoles && index < jsuint(-1)) {
                     JS_ASSERT(ReallyBigIndexToId(cx, index, idr.addr()));
                     JSObject* obj2;
                     JSProperty* prop;
@@ -1713,22 +1703,22 @@ InitArrayElements(JSContext *cx, JSObjec
         return JS_TRUE;
 
     /* Finish out any remaining elements past the max array index. */
     if (obj->isDenseArray() && !ENSURE_SLOW_ARRAY(cx, obj))
         return JS_FALSE;
 
     JS_ASSERT(start == MAXINDEX);
     jsval tmp[2] = {JSVAL_NULL, JSVAL_NULL};
-    JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp);
     if (!js_NewDoubleInRootedValue(cx, MAXINDEX, &tmp[0]))
         return JS_FALSE;
     jsdouble *dp = JSVAL_TO_DOUBLE(tmp[0]);
     JS_ASSERT(*dp == MAXINDEX);
-    JSAutoTempIdRooter idr(cx);
+    AutoIdRooter idr(cx);
     do {
         tmp[1] = *vector++;
         if (!js_ValueToStringId(cx, tmp[0], idr.addr()) ||
             !obj->setProperty(cx, idr.id(), &tmp[1])) {
             return JS_FALSE;
         }
         *dp += 1;
     } while (vector != end);
@@ -1764,28 +1754,28 @@ InitArrayObject(JSContext *cx, JSObject 
     }
     return JS_TRUE;
 }
 
 #ifdef JS_TRACER
 static JSString* FASTCALL
 Array_p_join(JSContext* cx, JSObject* obj, JSString *str)
 {
-    JSAutoTempValueRooter tvr(cx);
+    AutoValueRooter tvr(cx);
     if (!array_toString_sub(cx, obj, JS_FALSE, str, tvr.addr())) {
         SetBuiltinError(cx);
         return NULL;
     }
     return JSVAL_TO_STRING(tvr.value());
 }
 
 static JSString* FASTCALL
 Array_p_toString(JSContext* cx, JSObject* obj)
 {
-    JSAutoTempValueRooter tvr(cx);
+    AutoValueRooter tvr(cx);
     if (!array_toString_sub(cx, obj, JS_FALSE, NULL, tvr.addr())) {
         SetBuiltinError(cx);
         return NULL;
     }
     return JSVAL_TO_STRING(tvr.value());
 }
 #endif
 
@@ -1847,17 +1837,17 @@ array_reverse(JSContext *cx, uintN argc,
         /*
          * Per ECMA-262, don't update the length of the array, even if the new
          * array has trailing holes (and thus the original array began with
          * holes).
          */
         return JS_TRUE;
     }
 
-    JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
+    AutoValueRooter tvr(cx);
     for (jsuint i = 0, half = len / 2; i < half; i++) {
         JSBool hole, hole2;
         if (!JS_CHECK_OPERATION_LIMIT(cx) ||
             !GetArrayElement(cx, obj, i, &hole, tvr.addr()) ||
             !GetArrayElement(cx, obj, len - i - 1, &hole2, vp) ||
             !SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, tvr.value()) ||
             !SetOrDeleteArrayElement(cx, obj, i, hole2, *vp)) {
             return false;
@@ -2097,277 +2087,254 @@ sort_compare_strings(void *arg, const vo
  * perform initialization using memset.  Other parts of SpiderMonkey likewise
  * "know" that JSVAL_NULL is zero; this static assertion covers all cases.
  */
 JS_STATIC_ASSERT(JSVAL_NULL == 0);
 
 static JSBool
 array_sort(JSContext *cx, uintN argc, jsval *vp)
 {
-    jsval *argv, fval, *vec, *mergesort_tmp, v;
-    JSObject *obj;
-    CompareArgs ca;
+    jsval fval;
     jsuint len, newlen, i, undefs;
-    JSTempValueRooter tvr;
-    JSBool hole;
-    JSBool ok;
     size_t elemsize;
     JSString *str;
 
-    /*
-     * Optimize the default compare function case if all of obj's elements
-     * have values of type string.
-     */
-    JSBool all_strings;
-
-    argv = JS_ARGV(cx, vp);
+    jsval *argv = JS_ARGV(cx, vp);
     if (argc > 0) {
         if (JSVAL_IS_PRIMITIVE(argv[0])) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                 JSMSG_BAD_SORT_ARG);
-            return JS_FALSE;
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG);
+            return false;
         }
         fval = argv[0];     /* non-default compare function */
     } else {
         fval = JSVAL_NULL;
     }
 
-    obj = JS_THIS_OBJECT(cx, vp);
+    JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj || !js_GetLengthProperty(cx, obj, &len))
-        return JS_FALSE;
+        return false;
     if (len == 0) {
         *vp = OBJECT_TO_JSVAL(obj);
-        return JS_TRUE;
+        return true;
     }
 
     /*
      * We need a temporary array of 2 * len jsvals to hold the array elements
      * and the scratch space for merge sort. Check that its size does not
      * overflow size_t, which would allow for indexing beyond the end of the
      * malloc'd vector.
      */
 #if JS_BITS_PER_WORD == 32
-    if ((size_t)len > ~(size_t)0 / (2 * sizeof(jsval))) {
+    if (size_t(len) > SIZE_MAX / (2 * sizeof(jsval))) {
         js_ReportAllocationOverflow(cx);
-        return JS_FALSE;
+        return false;
     }
 #endif
-    vec = (jsval *) cx->malloc(2 * (size_t) len * sizeof(jsval));
-    if (!vec)
-        return JS_FALSE;
 
     /*
      * Initialize vec as a root. We will clear elements of vec one by
-     * one while increasing tvr.count when we know that the property at
-     * the corresponding index exists and its value must be rooted.
+     * one while increasing the rooted amount of vec when we know that the
+     * property at the corresponding index exists and its value must be rooted.
      *
      * In this way when sorting a huge mostly sparse array we will not
      * access the tail of vec corresponding to properties that do not
      * exist, allowing OS to avoiding committing RAM. See bug 330812.
      *
      * After this point control must flow through label out: to exit.
      */
-    JS_PUSH_TEMP_ROOT(cx, 0, vec, &tvr);
-
-    /*
-     * By ECMA 262, 15.4.4.11, a property that does not exist (which we
-     * call a "hole") is always greater than an existing property with
-     * value undefined and that is always greater than any other property.
-     * Thus to sort holes and undefs we simply count them, sort the rest
-     * of elements, append undefs after them and then make holes after
-     * undefs.
-     */
-    undefs = 0;
-    newlen = 0;
-    all_strings = JS_TRUE;
-    for (i = 0; i < len; i++) {
-        ok = JS_CHECK_OPERATION_LIMIT(cx);
-        if (!ok)
-            goto out;
-
-        /* Clear vec[newlen] before including it in the rooted set. */
-        vec[newlen] = JSVAL_NULL;
-        tvr.count = newlen + 1;
-        ok = GetArrayElement(cx, obj, i, &hole, &vec[newlen]);
-        if (!ok)
-            goto out;
-
-        if (hole)
-            continue;
-
-        if (JSVAL_IS_VOID(vec[newlen])) {
-            ++undefs;
-            continue;
+    {
+        jsval *vec = (jsval *) cx->malloc(2 * size_t(len) * sizeof(jsval));
+        if (!vec)
+            return false;
+
+        struct AutoFreeVector {
+            AutoFreeVector(JSContext *cx, jsval *&vec) : cx(cx), vec(vec) { }
+            ~AutoFreeVector() {
+                cx->free(vec);
+            }
+            JSContext * const cx;
+            jsval *&vec;
+        } free(cx, vec);
+
+        AutoArrayRooter tvr(cx, 0, vec);
+
+        /*
+         * By ECMA 262, 15.4.4.11, a property that does not exist (which we
+         * call a "hole") is always greater than an existing property with
+         * value undefined and that is always greater than any other property.
+         * Thus to sort holes and undefs we simply count them, sort the rest
+         * of elements, append undefs after them and then make holes after
+         * undefs.
+         */
+        undefs = 0;
+        newlen = 0;
+        bool allStrings = true;
+        for (i = 0; i < len; i++) {
+            if (!JS_CHECK_OPERATION_LIMIT(cx))
+                return false;
+
+            /* Clear vec[newlen] before including it in the rooted set. */
+            JSBool hole;
+            vec[newlen] = JSVAL_NULL;
+            tvr.changeLength(newlen + 1);
+            if (!GetArrayElement(cx, obj, i, &hole, &vec[newlen]))
+                return false;
+
+            if (hole)
+                continue;
+
+            if (JSVAL_IS_VOID(vec[newlen])) {
+                ++undefs;
+                continue;
+            }
+
+            allStrings = allStrings && JSVAL_IS_STRING(vec[newlen]);
+
+            ++newlen;
         }
 
-        /* We know JSVAL_IS_STRING yields 0 or 1, so avoid a branch via &=. */
-        all_strings &= JSVAL_IS_STRING(vec[newlen]);
-
-        ++newlen;
-    }
-
-    if (newlen == 0) {
-        /* The array has only holes and undefs. */
-        ok = JS_TRUE;
-        goto out;
-    }
-
-    /*
-     * The first newlen elements of vec are copied from the array object
-     * (above). The remaining newlen positions are used as GC-rooted scratch
-     * space for mergesort. We must clear the space before including it to
-     * the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize
-     * initialization using memset.
-     */
-    mergesort_tmp = vec + newlen;
-    memset(mergesort_tmp, 0, newlen * sizeof(jsval));
-    tvr.count = newlen * 2;
-
-    /* Here len == 2 * (newlen + undefs + number_of_holes). */
-    if (fval == JSVAL_NULL) {
+        if (newlen == 0)
+            return true; /* The array has only holes and undefs. */
+
         /*
-         * Sort using the default comparator converting all elements to
-         * strings.
+         * The first newlen elements of vec are copied from the array object
+         * (above). The remaining newlen positions are used as GC-rooted scratch
+         * space for mergesort. We must clear the space before including it to
+         * the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize
+         * initialization using memset.
          */
-        if (all_strings) {
-            elemsize = sizeof(jsval);
-        } else {
+        jsval *mergesort_tmp = vec + newlen;
+        memset(mergesort_tmp, 0, newlen * sizeof(jsval));
+        tvr.changeLength(newlen * 2);
+
+        /* Here len == 2 * (newlen + undefs + number_of_holes). */
+        if (fval == JSVAL_NULL) {
             /*
-             * To avoid string conversion on each compare we do it only once
-             * prior to sorting. But we also need the space for the original
-             * values to recover the sorting result. To reuse
-             * sort_compare_strings we move the original values to the odd
-             * indexes in vec, put the string conversion results in the even
-             * indexes and pass 2 * sizeof(jsval) as an element size to the
-             * sorting function. In this way sort_compare_strings will only
-             * see the string values when it casts the compare arguments as
-             * pointers to jsval.
-             *
-             * This requires doubling the temporary storage including the
-             * scratch space for the merge sort. Since vec already contains
-             * the rooted scratch space for newlen elements at the tail, we
-             * can use it to rearrange and convert to strings first and try
-             * realloc only when we know that we successfully converted all
-             * the elements.
+             * Sort using the default comparator converting all elements to
+             * strings.
              */
+            if (allStrings) {
+                elemsize = sizeof(jsval);
+            } else {
+                /*
+                 * To avoid string conversion on each compare we do it only once
+                 * prior to sorting. But we also need the space for the original
+                 * values to recover the sorting result. To reuse
+                 * sort_compare_strings we move the original values to the odd
+                 * indexes in vec, put the string conversion results in the even
+                 * indexes and pass 2 * sizeof(jsval) as an element size to the
+                 * sorting function. In this way sort_compare_strings will only
+                 * see the string values when it casts the compare arguments as
+                 * pointers to jsval.
+                 *
+                 * This requires doubling the temporary storage including the
+                 * scratch space for the merge sort. Since vec already contains
+                 * the rooted scratch space for newlen elements at the tail, we
+                 * can use it to rearrange and convert to strings first and try
+                 * realloc only when we know that we successfully converted all
+                 * the elements.
+                 */
 #if JS_BITS_PER_WORD == 32
-            if ((size_t)newlen > ~(size_t)0 / (4 * sizeof(jsval))) {
-                js_ReportAllocationOverflow(cx);
-                ok = JS_FALSE;
-                goto out;
-            }
+                if (size_t(newlen) > SIZE_MAX / (4 * sizeof(jsval))) {
+                    js_ReportAllocationOverflow(cx);
+                    return false;
+                }
 #endif
 
-            /*
-             * Rearrange and string-convert the elements of the vector from
-             * the tail here and, after sorting, move the results back
-             * starting from the start to prevent overwrite the existing
-             * elements.
-             */
-            i = newlen;
-            do {
-                --i;
-                ok = JS_CHECK_OPERATION_LIMIT(cx);
-                if (!ok)
-                    goto out;
-                v = vec[i];
-                str = js_ValueToString(cx, v);
-                if (!str) {
-                    ok = JS_FALSE;
-                    goto out;
+                /*
+                 * Rearrange and string-convert the elements of the vector from
+                 * the tail here and, after sorting, move the results back
+                 * starting from the start to prevent overwrite the existing
+                 * elements.
+                 */
+                i = newlen;
+                do {
+                    --i;
+                    if (!JS_CHECK_OPERATION_LIMIT(cx))
+                        return false;
+                    jsval v = vec[i];
+                    str = js_ValueToString(cx, v);
+                    if (!str)
+                        return false;
+                    vec[2 * i] = STRING_TO_JSVAL(str);
+                    vec[2 * i + 1] = v;
+                } while (i != 0);
+
+                JS_ASSERT(tvr.array == vec);
+                vec = (jsval *) cx->realloc(vec, 4 * size_t(newlen) * sizeof(jsval));
+                if (!vec) {
+                    vec = tvr.array;
+                    return false;
                 }
-                vec[2 * i] = STRING_TO_JSVAL(str);
-                vec[2 * i + 1] = v;
-            } while (i != 0);
-
-            JS_ASSERT(tvr.u.array == vec);
-            vec = (jsval *) cx->realloc(vec,
-                                        4 * (size_t) newlen * sizeof(jsval));
-            if (!vec) {
-                vec = tvr.u.array;
-                ok = JS_FALSE;
-                goto out;
+                mergesort_tmp = vec + 2 * newlen;
+                memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval));
+                tvr.changeArray(vec, newlen * 4);
+                elemsize = 2 * sizeof(jsval);
+            }
+            if (!js_MergeSort(vec, size_t(newlen), elemsize,
+                              sort_compare_strings, cx, mergesort_tmp)) {
+                return false;
             }
-            tvr.u.array = vec;
-            mergesort_tmp = vec + 2 * newlen;
-            memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval));
-            tvr.count = newlen * 4;
-            elemsize = 2 * sizeof(jsval);
+            if (!allStrings) {
+                /*
+                 * We want to make the following loop fast and to unroot the
+                 * cached results of toString invocations before the operation
+                 * callback has a chance to run the GC. For this reason we do
+                 * not call JS_CHECK_OPERATION_LIMIT in the loop.
+                 */
+                i = 0;
+                do {
+                    vec[i] = vec[2 * i + 1];
+                } while (++i != newlen);
+            }
+        } else {
+            void *mark;
+
+            LeaveTrace(cx);
+
+            CompareArgs ca;
+            ca.context = cx;
+            ca.fval = fval;
+            ca.elemroot  = js_AllocStack(cx, 2 + 2, &mark);
+            if (!ca.elemroot)
+                return false;
+            bool ok = js_MergeSort(vec, size_t(newlen), sizeof(jsval),
+                                   comparator_stack_cast(sort_compare),
+                                   &ca, mergesort_tmp);
+            js_FreeStack(cx, mark);
+            if (!ok)
+                return false;
         }
-        ok = js_MergeSort(vec, (size_t) newlen, elemsize,
-                          sort_compare_strings, cx, mergesort_tmp);
-        if (!ok)
-            goto out;
-        if (!all_strings) {
-            /*
-             * We want to make the following loop fast and to unroot the
-             * cached results of toString invocations before the operation
-             * callback has a chance to run the GC. For this reason we do
-             * not call JS_CHECK_OPERATION_LIMIT in the loop.
-             */
-            i = 0;
-            do {
-                vec[i] = vec[2 * i + 1];
-            } while (++i != newlen);
+
+        /*
+         * We no longer need to root the scratch space for the merge sort, so
+         * unroot it now to make the job of a potential GC under
+         * InitArrayElements easier.
+         */
+        tvr.changeLength(newlen);
+        if (!InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues,
+                               SourceVectorAllValues)) {
+            return false;
         }
-    } else {
-        void *mark;
-
-        LeaveTrace(cx);
-
-        ca.context = cx;
-        ca.fval = fval;
-        ca.elemroot  = js_AllocStack(cx, 2 + 2, &mark);
-        if (!ca.elemroot) {
-            ok = JS_FALSE;
-            goto out;
-        }
-        ok = js_MergeSort(vec, (size_t) newlen, sizeof(jsval),
-                          comparator_stack_cast(sort_compare),
-                          &ca, mergesort_tmp);
-        js_FreeStack(cx, mark);
-        if (!ok)
-            goto out;
     }
 
-    /*
-     * We no longer need to root the scratch space for the merge sort, so
-     * unroot it now to make the job of a potential GC under InitArrayElements
-     * easier.
-     */
-    tvr.count = newlen;
-    ok = InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues,
-                           SourceVectorAllValues);
-    if (!ok)
-        goto out;
-
-  out:
-    JS_POP_TEMP_ROOT(cx, &tvr);
-    cx->free(vec);
-    if (!ok)
-        return JS_FALSE;
-
     /* Set undefs that sorted after the rest of elements. */
     while (undefs != 0) {
         --undefs;
-        if (!JS_CHECK_OPERATION_LIMIT(cx) ||
-            !SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) {
-            return JS_FALSE;
-        }
+        if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, newlen++, JSVAL_VOID))
+            return false;
     }
 
     /* Re-create any holes that sorted to the end of the array. */
     while (len > newlen) {
-        if (!JS_CHECK_OPERATION_LIMIT(cx) ||
-            !DeleteArrayElement(cx, obj, --len)) {
+        if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, --len))
             return JS_FALSE;
-        }
     }
     *vp = OBJECT_TO_JSVAL(obj);
-    return JS_TRUE;
+    return true;
 }
 
 /*
  * Perl-inspired push, pop, shift, unshift, and splice methods.
  */
 static JSBool
 array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
@@ -2431,17 +2398,17 @@ js_ArrayCompPush(JSContext *cx, JSObject
 }
 JS_DEFINE_CALLINFO_3(extern, BOOL, js_ArrayCompPush, CONTEXT, OBJECT, JSVAL, 0,
                      nanojit::ACC_STORE_ANY)
 
 #ifdef JS_TRACER
 static jsval FASTCALL
 Array_p_push1(JSContext* cx, JSObject* obj, jsval v)
 {
-    JSAutoTempValueRooter tvr(cx, v);
+    AutoValueRooter tvr(cx, v);
     if (obj->isDenseArray()
         ? array_push1_dense(cx, obj, v, tvr.addr())
         : array_push_slowly(cx, obj, 1, tvr.addr(), tvr.addr())) {
         return tvr.value();
     }
     SetBuiltinError(cx);
     return JSVAL_VOID;
 }
@@ -2503,17 +2470,17 @@ array_pop_dense(JSContext *cx, JSObject*
     obj->fslots[JSSLOT_ARRAY_LENGTH] = index;
     return JS_TRUE;
 }
 
 #ifdef JS_TRACER
 static jsval FASTCALL
 Array_p_pop(JSContext* cx, JSObject* obj)
 {
-    JSAutoTempValueRooter tvr(cx);
+    AutoValueRooter tvr(cx);
     if (obj->isDenseArray()
         ? array_pop_dense(cx, obj, tvr.addr())
         : array_pop_slowly(cx, obj, tvr.addr())) {
         return tvr.value();
     }
     SetBuiltinError(cx);
     return JSVAL_VOID;
 }
@@ -2567,17 +2534,17 @@ array_shift(JSContext *cx, uintN argc, j
                 *vp = JSVAL_VOID;
             }
         } else {
             /* Get the to-be-deleted property's value into vp ASAP. */
             if (!GetArrayElement(cx, obj, 0, &hole, vp))
                 return JS_FALSE;
 
             /* Slide down the array above the first element. */
-            JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
+            AutoValueRooter tvr(cx);
             for (i = 0; i != length; i++) {
                 if (!JS_CHECK_OPERATION_LIMIT(cx) ||
                     !GetArrayElement(cx, obj, i + 1, &hole, tvr.addr()) ||
                     !SetOrDeleteArrayElement(cx, obj, i, hole, tvr.value())) {
                     return JS_FALSE;
                 }
             }
 
@@ -2612,17 +2579,17 @@ array_unshift(JSContext *cx, uintN argc,
                 if (!EnsureCapacity(cx, obj, length + argc))
                     return JS_FALSE;
                 memmove(obj->dslots + argc, obj->dslots, length * sizeof(jsval));
                 for (uint32 i = 0; i < argc; i++)
                     obj->dslots[i] = JSVAL_HOLE;
             } else {
                 last = length;
                 jsdouble upperIndex = last + argc;
-                JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
+                AutoValueRooter tvr(cx);
                 do {
                     --last, --upperIndex;
                     if (!JS_CHECK_OPERATION_LIMIT(cx) ||
                         !GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
                         !SetOrDeleteArrayElement(cx, obj, upperIndex, hole, tvr.value())) {
                         return JS_FALSE;
                     }
                 } while (last != 0);
@@ -2702,17 +2669,17 @@ array_splice(JSContext *cx, uintN argc, 
         else if (d > delta)
             d = delta;
         count = (jsuint)d;
         end = begin + count;
         argc--;
         argv++;
     }
 
-    JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
+    AutoValueRooter tvr(cx, JSVAL_NULL);
 
     /* If there are elements to remove, put them into the return value. */
     if (count > 0) {
         if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
             !js_PrototypeHasIndexedProperties(cx, obj2) &&
             end <= js_DenseArrayCapacity(obj)) {
             if (!InitArrayObject(cx, obj2, count, obj->dslots + begin,
                                  obj->fslots[JSSLOT_ARRAY_COUNT] !=
@@ -2841,17 +2808,17 @@ array_concat(JSContext *cx, uintN argc, 
     } else {
         nobj = js_NewArrayObject(cx, 0, NULL);
         if (!nobj)
             return JS_FALSE;
         *vp = OBJECT_TO_JSVAL(nobj);
         length = 0;
     }
 
-    JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
+    AutoValueRooter tvr(cx, JSVAL_NULL);
 
     /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
     for (i = 0; i <= argc; i++) {
         if (!JS_CHECK_OPERATION_LIMIT(cx))
             return false;
         v = argv[i];
         if (!JSVAL_IS_PRIMITIVE(v)) {
             JSObject *wobj;
@@ -2955,17 +2922,17 @@ array_slice(JSContext *cx, uintN argc, j
     }
 
     /* Create a new Array object and root it using *vp. */
     nobj = js_NewArrayObject(cx, 0, NULL);
     if (!nobj)
         return JS_FALSE;
     *vp = OBJECT_TO_JSVAL(nobj);
 
-    JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
+    AutoValueRooter tvr(cx);
     for (slot = begin; slot < end; slot++) {
         if (!JS_CHECK_OPERATION_LIMIT(cx) ||
             !GetArrayElement(cx, obj, slot, &hole, tvr.addr())) {
             return JS_FALSE;
         }
         if (!hole && !SetArrayElement(cx, nobj, slot - begin, tvr.value()))
             return JS_FALSE;
     }
@@ -3465,33 +3432,31 @@ js_InitArrayClass(JSContext *cx, JSObjec
     if (!proto || !InitArrayObject(cx, proto, 0, NULL))
         return NULL;
     return proto;
 }
 
 JSObject *
 js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
 {
-    JSTempValueRooter tvr;
-    JSObject *obj;
-
-    obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
+    JSObject *obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
     if (!obj)
         return NULL;
 
     /*
      * If this fails, the global object was not initialized and its class does
      * not have JSCLASS_IS_GLOBAL.
      */
     JS_ASSERT(obj->getProto());
 
-    JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
-    if (!InitArrayObject(cx, obj, length, vector, holey))
-        obj = NULL;
-    JS_POP_TEMP_ROOT(cx, &tvr);
+    {
+        AutoValueRooter tvr(cx, obj);
+        if (!InitArrayObject(cx, obj, length, vector, holey))
+            obj = NULL;
+    }
 
     /* Set/clear newborn root, in case we lost it.  */
     cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
     return obj;
 }
 
 JSObject *
 js_NewSlowArrayObject(JSContext *cx)
@@ -3597,17 +3562,17 @@ js_CoerceArrayToCanvasImageData(JSObject
 
 JS_FRIEND_API(JSObject *)
 js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector)
 {
     JSObject *obj = js_NewArrayObject(cx, capacity, NULL);
     if (!obj)
         return NULL;
 
-    JSAutoTempValueRooter tvr(cx, obj);
+    AutoValueRooter tvr(cx, obj);
     if (!EnsureCapacity(cx, obj, capacity, JS_FALSE))
         obj = NULL;
 
     /* Set/clear newborn root, in case we lost it.  */
     cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
     if (!obj)
         return NULL;
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1156,120 +1156,33 @@ typedef struct JSResolvingKey {
 typedef struct JSResolvingEntry {
     JSDHashEntryHdr     hdr;
     JSResolvingKey      key;
     uint32              flags;
 } JSResolvingEntry;
 
 #define JSRESFLAG_LOOKUP        0x1     /* resolving id from lookup */
 #define JSRESFLAG_WATCH         0x2     /* resolving id from watch */
-
-/*
- * Macros to push/pop JSTempValueRooter instances to context-linked stack of
- * temporary GC roots. If you need to protect a result value that flows out of
- * a C function across several layers of other functions, use the
- * js_LeaveLocalRootScopeWithResult internal API (see further below) instead.
- *
- * The macros also provide a simple way to get a single rooted pointer via
- * JS_PUSH_TEMP_ROOT_<KIND>(cx, NULL, &tvr). Then &tvr.u.<kind> gives the
- * necessary pointer.
- *
- * JSTempValueRooter.count defines the type of the rooted value referenced by
- * JSTempValueRooter.u union of type JSTempValueUnion. When count is positive
- * or zero, u.array points to a vector of jsvals. Otherwise it must be one of
- * the following constants:
- */
-#define JSTVU_SINGLE        (-1)    /* u.value or u.<gcthing> is single jsval
-                                       or non-JSString GC-thing pointer */
-#define JSTVU_TRACE         (-2)    /* u.trace is a hook to trace a custom
-                                     * structure */
-#define JSTVU_SPROP         (-3)    /* u.sprop roots property tree node */
-#define JSTVU_WEAK_ROOTS    (-4)    /* u.weakRoots points to saved weak roots */
-#define JSTVU_COMPILER      (-5)    /* u.compiler roots JSCompiler* */
-#define JSTVU_SCRIPT        (-6)    /* u.script roots JSScript* */
-#define JSTVU_ENUMERATOR    (-7)    /* a pointer to JSTempValueRooter points
-                                       to an instance of JSAutoEnumStateRooter
-                                       with u.object storing the enumeration
-                                       object */
-
-/*
- * Here single JSTVU_SINGLE covers both jsval and pointers to almost (see note
- * below) any GC-thing via reinterpreting the thing as JSVAL_OBJECT. This works
- * because the GC-thing is aligned on a 0 mod 8 boundary, and object has the 0
- * jsval tag. So any GC-heap-allocated thing pointer may be tagged as if it
- * were an object and untagged, if it's then used only as an opaque pointer
- * until discriminated by other means than tag bits. This is how, for example,
- * js_GetGCThingTraceKind uses its |thing| parameter -- it consults GC-thing
- * flags stored separately from the thing to decide the kind of thing.
- *
- * Note well that JSStrings may be statically allocated (see the intStringTable
- * and unitStringTable static arrays), so this hack does not work for arbitrary
- * GC-thing pointers.
- */
-#define JS_PUSH_TEMP_ROOT_COMMON(cx,x,tvr,cnt,kind)                           \
-    JS_BEGIN_MACRO                                                            \
-        JS_ASSERT((cx)->tempValueRooters != (tvr));                           \
-        (tvr)->count = (cnt);                                                 \
-        (tvr)->u.kind = (x);                                                  \
-        (tvr)->down = (cx)->tempValueRooters;                                 \
-        (cx)->tempValueRooters = (tvr);                                       \
-    JS_END_MACRO
-
-#define JS_POP_TEMP_ROOT(cx,tvr)                                              \
-    JS_BEGIN_MACRO                                                            \
-        JS_ASSERT((cx)->tempValueRooters == (tvr));                           \
-        (cx)->tempValueRooters = (tvr)->down;                                 \
-    JS_END_MACRO
-
-#define JS_PUSH_TEMP_ROOT(cx,cnt,arr,tvr)                                     \
-    JS_BEGIN_MACRO                                                            \
-        JS_ASSERT((int)(cnt) >= 0);                                           \
-        JS_PUSH_TEMP_ROOT_COMMON(cx, arr, tvr, (ptrdiff_t) (cnt), array);     \
-    JS_END_MACRO
-
-#define JS_PUSH_SINGLE_TEMP_ROOT(cx,val,tvr)                                  \
-    JS_PUSH_TEMP_ROOT_COMMON(cx, val, tvr, JSTVU_SINGLE, value)
-
-#define JS_PUSH_TEMP_ROOT_OBJECT(cx,obj,tvr)                                  \
-    JS_PUSH_TEMP_ROOT_COMMON(cx, obj, tvr, JSTVU_SINGLE, object)
-
-#define JS_PUSH_TEMP_ROOT_STRING(cx,str,tvr)                                  \
-    JS_PUSH_SINGLE_TEMP_ROOT(cx, str ? STRING_TO_JSVAL(str) : JSVAL_NULL, tvr)
-
-#define JS_PUSH_TEMP_ROOT_XML(cx,xml_,tvr)                                    \
-    JS_PUSH_TEMP_ROOT_COMMON(cx, xml_, tvr, JSTVU_SINGLE, xml)
-
-#define JS_PUSH_TEMP_ROOT_TRACE(cx,trace_,tvr)                                \
-    JS_PUSH_TEMP_ROOT_COMMON(cx, trace_, tvr, JSTVU_TRACE, trace)
-
-#define JS_PUSH_TEMP_ROOT_SPROP(cx,sprop_,tvr)                                \
-    JS_PUSH_TEMP_ROOT_COMMON(cx, sprop_, tvr, JSTVU_SPROP, sprop)
-
-#define JS_PUSH_TEMP_ROOT_WEAK_COPY(cx,weakRoots_,tvr)                        \
-    JS_PUSH_TEMP_ROOT_COMMON(cx, weakRoots_, tvr, JSTVU_WEAK_ROOTS, weakRoots)
-
-#define JS_PUSH_TEMP_ROOT_COMPILER(cx,pc,tvr)                                 \
-    JS_PUSH_TEMP_ROOT_COMMON(cx, pc, tvr, JSTVU_COMPILER, compiler)
-
-#define JS_PUSH_TEMP_ROOT_SCRIPT(cx,script_,tvr)                              \
-    JS_PUSH_TEMP_ROOT_COMMON(cx, script_, tvr, JSTVU_SCRIPT, script)
-
 #define JSRESOLVE_INFER         0xffff  /* infer bits from current bytecode */
 
 extern const JSDebugHooks js_NullDebugHooks;  /* defined in jsdbgapi.cpp */
 
 /*
  * Wraps a stack frame which has been temporarily popped from its call stack
  * and needs to be GC-reachable. See JSContext::{push,pop}GCReachableFrame.
  */
 struct JSGCReachableFrame {
     JSGCReachableFrame  *next;
     JSStackFrame        *frame;
 };
 
+namespace js {
+class AutoGCRooter;
+}
+
 struct JSContext
 {
     explicit JSContext(JSRuntime *rt) : runtime(rt), busyArrays(this) {}
 
     /*
      * If this flag is set, we were asked to call back the operation callback
      * as soon as possible.
      */
@@ -1461,18 +1374,18 @@ struct JSContext
 
 #define CX_FROM_THREAD_LINKS(tl) \
     ((JSContext *)((char *)(tl) - offsetof(JSContext, threadLinks)))
 #endif
 
     /* PDL of stack headers describing stack slots not rooted by argv, etc. */
     JSStackHeader       *stackHeaders;
 
-    /* Stack of thread-stack-allocated temporary GC roots. */
-    JSTempValueRooter   *tempValueRooters;
+    /* Stack of thread-stack-allocated GC roots. */
+    js::AutoGCRooter   *autoGCRooters;
 
     /* Debug hooks associated with the current context. */
     const JSDebugHooks  *debugHooks;
 
     /* Security callbacks that override any defined on the runtime. */
     JSSecurityCallbacks *securityCallbacks;
 
     /* Pinned regexp pool used for regular expressions. */
@@ -1699,161 +1612,360 @@ JSStackFrame::varobj(JSContext *cx)
 static inline JSAtom **
 FrameAtomBase(JSContext *cx, JSStackFrame *fp)
 {
     return fp->imacpc
            ? COMMON_ATOMS_START(&cx->runtime->atomState)
            : fp->script->atomMap.vector;
 }
 
-/* FIXME(bug 332648): Move this into a public header. */
-class JSAutoTempValueRooter
+namespace js {
+
+class AutoGCRooter {
+  public:
+    AutoGCRooter(JSContext *cx, ptrdiff_t tag)
+      : down(cx->autoGCRooters), tag(tag), context(cx)
+    {
+        JS_ASSERT(this != cx->autoGCRooters);
+        cx->autoGCRooters = this;
+    }
+
+    ~AutoGCRooter() {
+        JS_ASSERT(this == context->autoGCRooters);
+        context->autoGCRooters = down;
+    }
+
+    inline void trace(JSTracer *trc);
+
+    friend void ::js_TraceContext(JSTracer *trc, JSContext *acx);
+
+  protected:
+    AutoGCRooter * const down;
+
+    /*
+     * Discriminates actual subclass of this being used.  If non-negative, the
+     * subclass roots an array of jsvals of the length stored in this field.
+     * If negative, meaning is indicated by the corresponding value in the enum
+     * below.  Any other negative value indicates some deeper problem such as
+     * memory corruption.
+     */
+    ptrdiff_t tag;
+
+    JSContext * const context;
+
+    enum {
+        JSVAL =        -1, /* js::AutoValueRooter */
+        SPROP =        -2, /* JSAutoScopePropertyTreeRooter */
+        WEAKROOTS =    -3, /* AutoSaveWeakRoots */
+        COMPILER =     -4, /* JSCompiler */
+        SCRIPT =       -5, /* JSAutoScriptRooter */
+        ENUMERATOR =   -6, /* JSAutoEnumStateRooter */
+        IDARRAY =      -7, /* JSAutoIdArray */
+        DESCRIPTORS =  -8, /* AutoDescriptorArray */
+        NAMESPACES =   -9, /* AutoNamespaceArray */
+        XML =         -10, /* JSAutoXML */
+        OBJECT =      -11, /* JSAutoObjectRooter */
+        ID =          -12  /* JSAutoTempIdRooter */
+    };
+};
+
+class AutoSaveWeakRoots : private AutoGCRooter
 {
   public:
-    JSAutoTempValueRooter(JSContext *cx, size_t len, jsval *vec
-                          JS_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mContext(cx) {
-        JS_GUARD_OBJECT_NOTIFIER_INIT;
-        JS_PUSH_TEMP_ROOT(mContext, len, vec, &mTvr);
-    }
-    explicit JSAutoTempValueRooter(JSContext *cx, jsval v = JSVAL_NULL
-                                   JS_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mContext(cx) {
+    explicit AutoSaveWeakRoots(JSContext *cx
+                               JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, WEAKROOTS), savedRoots(cx->weakRoots)
+    {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
-        JS_PUSH_SINGLE_TEMP_ROOT(mContext, v, &mTvr);
-    }
-    JSAutoTempValueRooter(JSContext *cx, JSString *str
-                          JS_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mContext(cx) {
-        JS_GUARD_OBJECT_NOTIFIER_INIT;
-        JS_PUSH_TEMP_ROOT_STRING(mContext, str, &mTvr);
-    }
-    JSAutoTempValueRooter(JSContext *cx, JSObject *obj
-                          JS_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mContext(cx) {
-        JS_GUARD_OBJECT_NOTIFIER_INIT;
-        JS_PUSH_TEMP_ROOT_OBJECT(mContext, obj, &mTvr);
-    }
-    JSAutoTempValueRooter(JSContext *cx, JSScopeProperty *sprop
-                          JS_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mContext(cx) {
-        JS_GUARD_OBJECT_NOTIFIER_INIT;
-        JS_PUSH_TEMP_ROOT_SPROP(mContext, sprop, &mTvr);
     }
 
-    ~JSAutoTempValueRooter() {
-        JS_POP_TEMP_ROOT(mContext, &mTvr);
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
+  private:
+    JSWeakRoots savedRoots;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/* FIXME(bug 332648): Move this into a public header. */
+class AutoValueRooter : private AutoGCRooter
+{
+  public:
+    explicit AutoValueRooter(JSContext *cx, jsval v = JSVAL_NULL
+                             JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, JSVAL), val(v)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+    AutoValueRooter(JSContext *cx, JSString *str
+                    JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, JSVAL), val(STRING_TO_JSVAL(str))
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+    AutoValueRooter(JSContext *cx, JSObject *obj
+                    JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, JSVAL), val(OBJECT_TO_JSVAL(obj))
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
-    jsval value() { return mTvr.u.value; }
-    jsval *addr() { return &mTvr.u.value; }
+    void setObject(JSObject *obj) {
+        JS_ASSERT(tag == JSVAL);
+        val = OBJECT_TO_JSVAL(obj);
+    }
+
+    void setString(JSString *str) {
+        JS_ASSERT(tag == JSVAL);
+        JS_ASSERT(str);
+        val = STRING_TO_JSVAL(str);
+    }
 
-  protected:
-    JSContext *mContext;
+    void setDouble(jsdouble *dp) {
+        JS_ASSERT(tag == JSVAL);
+        JS_ASSERT(dp);
+        val = DOUBLE_TO_JSVAL(dp);
+    }
+
+    jsval value() const {
+        JS_ASSERT(tag == JSVAL);
+        return val;
+    }
+
+    jsval *addr() {
+        JS_ASSERT(tag == JSVAL);
+        return &val;
+    }
+
+    friend void AutoGCRooter::trace(JSTracer *trc);
 
   private:
-    JSTempValueRooter mTvr;
+    jsval val;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-class JSAutoTempIdRooter
-{
+class AutoObjectRooter : private AutoGCRooter {
   public:
-    explicit JSAutoTempIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0)
-                                JS_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mContext(cx) {
+    AutoObjectRooter(JSContext *cx, JSObject *obj = NULL
+                     JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, OBJECT), obj(obj)
+    {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
-        JS_PUSH_SINGLE_TEMP_ROOT(mContext, ID_TO_VALUE(id), &mTvr);
+    }
+
+    void setObject(JSObject *obj) {
+        this->obj = obj;
+    }
+
+    JSObject * object() const {
+        return obj;
+    }
+
+    JSObject ** addr() {
+        return &obj;
     }
 
-    ~JSAutoTempIdRooter() {
-        JS_POP_TEMP_ROOT(mContext, &mTvr);
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
+  private:
+    JSObject *obj;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+class AutoArrayRooter : private AutoGCRooter {
+  public:
+    AutoArrayRooter(JSContext *cx, size_t len, jsval *vec
+                    JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, len), array(vec)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+        JS_ASSERT(tag >= 0);
     }
 
-    jsid id() { return (jsid) mTvr.u.value; }
-    jsid * addr() { return (jsid *) &mTvr.u.value; }
+    void changeLength(size_t newLength) {
+        tag = ptrdiff_t(newLength);
+        JS_ASSERT(tag >= 0);
+    }
+
+    void changeArray(jsval *newArray, size_t newLength) {
+        changeLength(newLength);
+        array = newArray;
+    }
+
+    jsval *array;
+
+    friend void AutoGCRooter::trace(JSTracer *trc);
 
   private:
-    JSContext *mContext;
-    JSTempValueRooter mTvr;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-class JSAutoIdArray {
+class AutoScopePropertyRooter : private AutoGCRooter {
   public:
-    JSAutoIdArray(JSContext *cx, JSIdArray *ida
-                  JS_GUARD_OBJECT_NOTIFIER_PARAM)
-        : cx(cx), idArray(ida) {
+    AutoScopePropertyRooter(JSContext *cx, JSScopeProperty *sprop
+                            JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, SPROP), sprop(sprop)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
+  private:
+    JSScopeProperty * const sprop;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+class AutoScriptRooter : private AutoGCRooter {
+  public:
+    AutoScriptRooter(JSContext *cx, JSScript *script
+                     JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, SCRIPT), script(script)
+    {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
-        if (ida)
-            JS_PUSH_TEMP_ROOT(cx, ida->length, ida->vector, &tvr);
+    }
+
+    void setScript(JSScript *script) {
+        this->script = script;
+    }
+
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
+  private:
+    JSScript *script;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+class AutoIdRooter : private AutoGCRooter
+{
+  public:
+    explicit AutoIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0)
+                          JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, ID), idval(id)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
-    ~JSAutoIdArray() {
-        if (idArray) {
-            JS_POP_TEMP_ROOT(cx, &tvr);
-            JS_DestroyIdArray(cx, idArray);
-        }
+
+    jsid id() {
+        return idval;
+    }
+
+    jsid * addr() {
+        return &idval;
+    }
+
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
+  private:
+    jsid idval;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+class AutoIdArray : private AutoGCRooter {
+  public:
+    AutoIdArray(JSContext *cx, JSIdArray *ida
+                  JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, ida ? ida->length : 0), idArray(ida)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+    ~AutoIdArray() {
+        if (idArray)
+            JS_DestroyIdArray(context, idArray);
     }
     bool operator!() {
         return idArray == NULL;
     }
     jsid operator[](size_t i) const {
         JS_ASSERT(idArray);
         JS_ASSERT(i < size_t(idArray->length));
         return idArray->vector[i];
     }
     size_t length() const {
          return idArray->length;
     }
+
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
+  protected:
+    inline void trace(JSTracer *trc);
+
   private:
-    JSContext * const cx;
     JSIdArray * const idArray;
-    JSTempValueRooter tvr;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 
     /* No copy or assignment semantics. */
-    JSAutoIdArray(JSAutoIdArray &);
-    void operator=(JSAutoIdArray &);
+    AutoIdArray(AutoIdArray &ida);
+    void operator=(AutoIdArray &ida);
 };
 
 /* The auto-root for enumeration object and its state. */
-class JSAutoEnumStateRooter : public JSTempValueRooter
+class AutoEnumStateRooter : private AutoGCRooter
 {
   public:
-    JSAutoEnumStateRooter(JSContext *cx, JSObject *obj, jsval *statep
-                          JS_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mContext(cx), mStatep(statep)
+    AutoEnumStateRooter(JSContext *cx, JSObject *obj
+                        JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, ENUMERATOR), obj(obj), stateValue(JSVAL_NULL)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
         JS_ASSERT(obj);
-        JS_ASSERT(statep);
-        JS_PUSH_TEMP_ROOT_COMMON(cx, obj, this, JSTVU_ENUMERATOR, object);
     }
 
-    ~JSAutoEnumStateRooter() {
-        JS_POP_TEMP_ROOT(mContext, this);
+    ~AutoEnumStateRooter() {
+        if (!JSVAL_IS_NULL(stateValue)) {
+#ifdef DEBUG
+            JSBool ok =
+#endif
+            obj->enumerate(context, JSENUMERATE_DESTROY, &stateValue, 0);
+            JS_ASSERT(ok);
+        }
+    }
+
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
+    jsval state() const { return stateValue; }
+    jsval * addr() { return &stateValue; }
+
+  protected:
+    void trace(JSTracer *trc) {
+        JS_CALL_OBJECT_TRACER(trc, obj, "js::AutoEnumStateRooter.obj");
+        js_MarkEnumeratorState(trc, obj, stateValue);
     }
 
-    void mark(JSTracer *trc) {
-        JS_CALL_OBJECT_TRACER(trc, u.object, "enumerator_obj");
-        js_MarkEnumeratorState(trc, u.object, *mStatep);
+    JSObject * const obj;
+
+  private:
+    jsval stateValue;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+#ifdef JS_HAS_XML_SUPPORT
+class AutoXMLRooter : private AutoGCRooter {
+  public:
+    AutoXMLRooter(JSContext *cx, JSXML *xml)
+      : AutoGCRooter(cx, XML), xml(xml)
+    {
+        JS_ASSERT(xml);
     }
 
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
   private:
-    JSContext   *mContext;
-    jsval       *mStatep;
-    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+    JSXML * const xml;
 };
+#endif /* JS_HAS_XML_SUPPORT */
+
+}
 
 class JSAutoResolveFlags
 {
   public:
     JSAutoResolveFlags(JSContext *cx, uintN flags
                        JS_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mContext(cx), mSaved(cx->resolveFlags) {
+      : mContext(cx), mSaved(cx->resolveFlags)
+    {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
         cx->resolveFlags = flags;
     }
 
     ~JSAutoResolveFlags() { mContext->resolveFlags = mSaved; }
 
   private:
     JSContext *mContext;
new file mode 100644
--- /dev/null
+++ b/js/src/jscntxtinlines.h
@@ -0,0 +1,147 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SpiderMonkey code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jeff Walden <jwalden+code@mit.edu> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jscntxtinlines_h___
+#define jscntxtinlines_h___
+
+#include "jscntxt.h"
+#include "jsxml.h"
+
+#include "jsobjinlines.h"
+
+namespace js {
+
+void
+AutoIdArray::trace(JSTracer *trc) {
+    JS_ASSERT(tag == IDARRAY);
+    js::TraceValues(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray");
+}
+
+class AutoNamespaces : protected AutoGCRooter {
+  protected:
+    AutoNamespaces(JSContext *cx) : AutoGCRooter(cx, NAMESPACES) {
+    }
+
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
+  public:
+    JSXMLArray array;
+};
+
+inline void
+AutoGCRooter::trace(JSTracer *trc)
+{
+    switch (tag) {
+      case JSVAL:
+        JS_SET_TRACING_NAME(trc, "js::AutoValueRooter.val");
+        js_CallValueTracerIfGCThing(trc, static_cast<AutoValueRooter *>(this)->val);
+        return;
+
+      case SPROP:
+        static_cast<AutoScopePropertyRooter *>(this)->sprop->trace(trc);
+        return;
+
+      case WEAKROOTS:
+        static_cast<AutoSaveWeakRoots *>(this)->savedRoots.mark(trc);
+        return;
+
+      case COMPILER:
+        static_cast<JSCompiler *>(this)->trace(trc);
+        return;
+
+      case SCRIPT:
+        if (JSScript *script = static_cast<AutoScriptRooter *>(this)->script)
+            js_TraceScript(trc, script);
+        return;
+
+      case ENUMERATOR:
+        static_cast<AutoEnumStateRooter *>(this)->trace(trc);
+        return;
+
+      case IDARRAY: {
+        JSIdArray *ida = static_cast<AutoIdArray *>(this)->idArray;
+        TraceValues(trc, ida->length, ida->vector, "js::AutoIdArray.idArray");
+        return;
+      }
+
+      case DESCRIPTORS: {
+        PropertyDescriptorArray &descriptors =
+            static_cast<AutoDescriptorArray *>(this)->descriptors;
+        for (size_t i = 0, len = descriptors.length(); i < len; i++) {
+            PropertyDescriptor &desc = descriptors[i];
+
+            JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value");
+            JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get");
+            JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set");
+            js_TraceId(trc, desc.id);
+        }
+        return;
+      }
+
+      case NAMESPACES: {
+        JSXMLArray &array = static_cast<AutoNamespaces *>(this)->array;
+        TraceObjectVector(trc, reinterpret_cast<JSObject **>(array.vector), array.length);
+        array.cursors->trace(trc);
+        return;
+      }
+
+      case XML:
+        js_TraceXML(trc, static_cast<AutoXMLRooter *>(this)->xml);
+        return;
+
+      case OBJECT:
+        if (JSObject *obj = static_cast<AutoObjectRooter *>(this)->obj) {
+            JS_SET_TRACING_NAME(trc, "js::AutoObjectRooter.obj");
+            js_CallGCMarker(trc, obj, JSTRACE_OBJECT);
+        }
+        return;
+
+      case ID:
+        JS_SET_TRACING_NAME(trc, "js::AutoIdRooter.val");
+        js_CallValueTracerIfGCThing(trc, static_cast<AutoIdRooter *>(this)->idval);
+        return;
+    }
+
+    JS_ASSERT(tag >= 0);
+    TraceValues(trc, tag, static_cast<AutoArrayRooter *>(this)->array, "js::AutoArrayRooter.array");
+}
+
+}
+
+#endif /* jscntxtinlines_h___ */
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1460,18 +1460,18 @@ JS_PropertyIterator(JSObject *obj, JSSco
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
                    JSPropertyDesc *pd)
 {
     pd->id = ID_TO_VALUE(sprop->id);
 
-    JSBool wasThrowing = cx->throwing;
-    JSAutoTempValueRooter lastException(cx, cx->exception);
+    bool wasThrowing = cx->throwing;
+    AutoValueRooter lastException(cx, cx->exception);
     cx->throwing = JS_FALSE;
 
     if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) {
         if (!cx->throwing) {
             pd->flags = JSPD_ERROR;
             pd->value = JSVAL_VOID;
         } else {
             pd->flags = JSPD_EXCEPTION;
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -58,16 +58,18 @@
 #include "jsinterp.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstaticcheck.h"
 
+using namespace js;
+
 /* Forward declarations for js_ErrorClass's initializer. */
 static JSBool
 Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
 
 static void
 exn_trace(JSTracer *trc, JSObject *obj);
 
 static void
@@ -819,141 +821,129 @@ exn_toString(JSContext *cx, uintN argc, 
  * Return a string that may eval to something similar to the original object.
  */
 static JSBool
 exn_toSource(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *obj;
     JSString *name, *message, *filename, *lineno_as_str, *result;
     jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
-    JSTempValueRooter tvr;
-    JSBool ok;
     uint32 lineno;
     size_t lineno_length, name_length, message_length, filename_length, length;
     jschar *chars, *cp;
 
     obj = JS_THIS_OBJECT(cx, vp);
     if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp))
-        return JS_FALSE;
+        return false;
     name = js_ValueToString(cx, *vp);
     if (!name)
-        return JS_FALSE;
+        return false;
     *vp = STRING_TO_JSVAL(name);
 
-    MUST_FLOW_THROUGH("out");
-    JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr);
+    {
+        AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroots), localroots);
 
 #ifdef __GNUC__
-    message = filename = NULL;
+        message = filename = NULL;
 #endif
-    ok = JS_GetProperty(cx, obj, js_message_str, &localroots[0]) &&
-         (message = js_ValueToSource(cx, localroots[0]));
-    if (!ok)
-        goto out;
-    localroots[0] = STRING_TO_JSVAL(message);
+        if (!JS_GetProperty(cx, obj, js_message_str, &localroots[0]) ||
+            !(message = js_ValueToSource(cx, localroots[0]))) {
+            return false;
+        }
+        localroots[0] = STRING_TO_JSVAL(message);
+
+        if (!JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) ||
+            !(filename = js_ValueToSource(cx, localroots[1]))) {
+            return false;
+        }
+        localroots[1] = STRING_TO_JSVAL(filename);
 
-    ok = JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) &&
-         (filename = js_ValueToSource(cx, localroots[1]));
-    if (!ok)
-        goto out;
-    localroots[1] = STRING_TO_JSVAL(filename);
+        if (!JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]))
+            return false;
+        lineno = js_ValueToECMAUint32 (cx, &localroots[2]);
+        if (JSVAL_IS_NULL(localroots[2]))
+            return false;
 
-    ok = JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]);
-    if (!ok)
-        goto out;
-    lineno = js_ValueToECMAUint32 (cx, &localroots[2]);
-    ok = !JSVAL_IS_NULL(localroots[2]);
-    if (!ok)
-        goto out;
+        if (lineno != 0) {
+            lineno_as_str = js_ValueToString(cx, localroots[2]);
+            if (!lineno_as_str)
+                return false;
+            lineno_length = lineno_as_str->length();
+        } else {
+            lineno_as_str = NULL;
+            lineno_length = 0;
+        }
+
+        /* Magic 8, for the characters in ``(new ())''. */
+        name_length = name->length();
+        message_length = message->length();
+        length = 8 + name_length + message_length;
 
-    if (lineno != 0) {
-        lineno_as_str = js_ValueToString(cx, localroots[2]);
-        if (!lineno_as_str) {
-            ok = JS_FALSE;
-            goto out;
+        filename_length = filename->length();
+        if (filename_length != 0) {
+            /* append filename as ``, {filename}'' */
+            length += 2 + filename_length;
+            if (lineno_as_str) {
+                /* append lineno as ``, {lineno_as_str}'' */
+                length += 2 + lineno_length;
+            }
+        } else {
+            if (lineno_as_str) {
+                /*
+                 * no filename, but have line number,
+                 * need to append ``, "", {lineno_as_str}''
+                 */
+                length += 6 + lineno_length;
+            }
         }
-        lineno_length = lineno_as_str->length();
-    } else {
-        lineno_as_str = NULL;
-        lineno_length = 0;
-    }
+
+        cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
+        if (!chars)
+            return false;
+
+        *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' ';
+        js_strncpy(cp, name->chars(), name_length);
+        cp += name_length;
+        *cp++ = '(';
+        if (message_length != 0) {
+            js_strncpy(cp, message->chars(), message_length);
+            cp += message_length;
+        }
 
-    /* Magic 8, for the characters in ``(new ())''. */
-    name_length = name->length();
-    message_length = message->length();
-    length = 8 + name_length + message_length;
-
-    filename_length = filename->length();
-    if (filename_length != 0) {
-        /* append filename as ``, {filename}'' */
-        length += 2 + filename_length;
+        if (filename_length != 0) {
+            /* append filename as ``, {filename}'' */
+            *cp++ = ','; *cp++ = ' ';
+            js_strncpy(cp, filename->chars(), filename_length);
+            cp += filename_length;
+        } else {
+            if (lineno_as_str) {
+                /*
+                 * no filename, but have line number,
+                 * need to append ``, "", {lineno_as_str}''
+                 */
+                *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"';
+            }
+        }
         if (lineno_as_str) {
             /* append lineno as ``, {lineno_as_str}'' */
-            length += 2 + lineno_length;
+            *cp++ = ','; *cp++ = ' ';
+            js_strncpy(cp, lineno_as_str->chars(), lineno_length);
+            cp += lineno_length;
         }
-    } else {
-        if (lineno_as_str) {
-            /*
-             * no filename, but have line number,
-             * need to append ``, "", {lineno_as_str}''
-             */
-            length += 6 + lineno_length;
-        }
-    }
 
-    cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
-    if (!chars) {
-        ok = JS_FALSE;
-        goto out;
-    }
-
-    *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' ';
-    js_strncpy(cp, name->chars(), name_length);
-    cp += name_length;
-    *cp++ = '(';
-    if (message_length != 0) {
-        js_strncpy(cp, message->chars(), message_length);
-        cp += message_length;
-    }
+        *cp++ = ')'; *cp++ = ')'; *cp = 0;
 
-    if (filename_length != 0) {
-        /* append filename as ``, {filename}'' */
-        *cp++ = ','; *cp++ = ' ';
-        js_strncpy(cp, filename->chars(), filename_length);
-        cp += filename_length;
-    } else {
-        if (lineno_as_str) {
-            /*
-             * no filename, but have line number,
-             * need to append ``, "", {lineno_as_str}''
-             */
-            *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"';
+        result = js_NewString(cx, chars, length);
+        if (!result) {
+            cx->free(chars);
+            return false;
         }
+        *vp = STRING_TO_JSVAL(result);
+        return true;
     }
-    if (lineno_as_str) {
-        /* append lineno as ``, {lineno_as_str}'' */
-        *cp++ = ','; *cp++ = ' ';
-        js_strncpy(cp, lineno_as_str->chars(), lineno_length);
-        cp += lineno_length;
-    }
-
-    *cp++ = ')'; *cp++ = ')'; *cp = 0;
-
-    result = js_NewString(cx, chars, length);
-    if (!result) {
-        cx->free(chars);
-        ok = JS_FALSE;
-        goto out;
-    }
-    *vp = STRING_TO_JSVAL(result);
-    ok = JS_TRUE;
-
-out:
-    JS_POP_TEMP_ROOT(cx, &tvr);
-    return ok;
 }
 #endif
 
 static JSFunctionSpec exception_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,   exn_toSource,           0,0),
 #endif
     JS_FN(js_toString_str,   exn_toString,           0,0),
@@ -994,17 +984,17 @@ js_InitExceptionClasses(JSContext *cx, J
      *
      * See the equivalent code to ensure that parent_proto is non-null when
      * JS_InitClass calls js_NewObject, in jsapi.c.
      */
     if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
         return NULL;
 
     memset(roots, 0, sizeof(roots));
-    JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
 
 #ifdef __GNUC__
     error_proto = NULL;   /* quell GCC overwarning */
 #endif
 
     /* Initialize the prototypes first. */
     for (intN i = JSEXN_ERR; i != JSEXN_LIMIT; i++) {
         JSObject *proto;
@@ -1104,17 +1094,16 @@ static struct exnname { char *name; char
 JSBool
 js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
                     JSErrorCallback callback, void *userRef)
 {
     JSErrNum errorNumber;
     const JSErrorFormatString *errorString;
     JSExnType exn;
     jsval tv[4];
-    JSTempValueRooter tvr;
     JSBool ok;
     JSObject *errProto, *errObject;
     JSString *messageStr, *filenameStr;
 
     /*
      * Tell our caller to report immediately if this report is just a warning.
      */
     JS_ASSERT(reportp);
@@ -1153,17 +1142,17 @@ js_ErrorToException(JSContext *cx, const
     if (cx->generatingError)
         return JS_FALSE;
 
     MUST_FLOW_THROUGH("out");
     cx->generatingError = JS_TRUE;
 
     /* Protect the newly-created strings below from nesting GCs. */
     memset(tv, 0, sizeof tv);
-    JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tv), tv);
 
     /*
      * Try to get an appropriate prototype by looking up the corresponding
      * exception constructor name in the scope chain of the current context's
      * top stack frame, or in the global object if no frame is active.
      */
     ok = js_GetClassPrototype(cx, NULL, GetExceptionProtoKey(exn), &errProto);
     if (!ok)
@@ -1197,41 +1186,38 @@ js_ErrorToException(JSContext *cx, const
         goto out;
 
     JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject));
 
     /* Flag the error report passed in to indicate an exception was raised. */
     reportp->flags |= JSREPORT_EXCEPTION;
 
 out:
-    JS_POP_TEMP_ROOT(cx, &tvr);
     cx->generatingError = JS_FALSE;
     return ok;
 }
 
 JSBool
 js_ReportUncaughtException(JSContext *cx)
 {
     jsval exn;
     JSObject *exnObject;
     jsval roots[5];
-    JSTempValueRooter tvr;
     JSErrorReport *reportp, report;
     JSString *str;
     const char *bytes;
-    JSBool ok;
 
     if (!JS_IsExceptionPending(cx))
-        return JS_TRUE;
+        return true;
 
     if (!JS_GetPendingException(cx, &exn))
-        return JS_FALSE;
+        return false;
 
     memset(roots, 0, sizeof roots);
-    JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
 
     /*
      * Because js_ValueToString below could error and an exception object
      * could become unrooted, we must root exnObject.  Later, if exnObject is
      * non-null, we need to root other intermediates, so allocate an operand
      * stack segment to protect all of these values.
      */
     if (JSVAL_IS_PRIMITIVE(exn)) {
@@ -1246,61 +1232,46 @@ js_ReportUncaughtException(JSContext *cx
 
     /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */
     str = js_ValueToString(cx, exn);
     if (!str) {
         bytes = "unknown (can't convert to string)";
     } else {
         roots[1] = STRING_TO_JSVAL(str);
         bytes = js_GetStringBytes(cx, str);
-        if (!bytes) {
-            ok = JS_FALSE;
-            goto out;
-        }
+        if (!bytes)
+            return false;
     }
-    ok = JS_TRUE;
 
-    if (!reportp &&
-        exnObject &&
-        OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) {
+    if (!reportp && exnObject && OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) {
         const char *filename;
         uint32 lineno;
 
-        ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]);
-        if (!ok)
-            goto out;
+        if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2]))
+            return false;
         if (JSVAL_IS_STRING(roots[2])) {
             bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2]));
-            if (!bytes) {
-                ok = JS_FALSE;
-                goto out;
-            }
+            if (!bytes)
+                return false;
         }
 
-        ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]);
-        if (!ok)
-            goto out;
+        if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]))
+            return false;
         str = js_ValueToString(cx, roots[3]);
-        if (!str) {
-            ok = JS_FALSE;
-            goto out;
-        }
+        if (!str)
+            return false;
         filename = StringToFilename(cx, str);
-        if (!filename) {
-            ok = JS_FALSE;
-            goto out;
-        }
+        if (!filename)
+            return false;
 
-        ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]);
-        if (!ok)
-            goto out;
+        if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]))
+            return false;
         lineno = js_ValueToECMAUint32 (cx, &roots[4]);
-        ok = !JSVAL_IS_NULL(roots[4]);
-        if (!ok)
-            goto out;
+        if (JSVAL_IS_NULL(roots[4]))
+            return false;
 
         reportp = &report;
         memset(&report, 0, sizeof report);
         report.filename = filename;
         report.lineno = (uintN) lineno;
     }
 
     if (!reportp) {
@@ -1311,12 +1282,10 @@ js_ReportUncaughtException(JSContext *cx
         reportp->flags |= JSREPORT_EXCEPTION;
 
         /* Pass the exception object. */
         JS_SetPendingException(cx, exn);
         js_ReportErrorAgain(cx, bytes, reportp);
         JS_ClearPendingException(cx);
     }
 
-out:
-    JS_POP_TEMP_ROOT(cx, &tvr);
-    return ok;
+    return true;
 }
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -346,17 +346,17 @@ WrapEscapingClosure(JSContext *cx, JSSta
     JSObject *scopeChain = js_GetScopeChain(cx, fp);
     if (!scopeChain)
         return NULL;
 
     JSObject *wfunobj = js_NewObjectWithGivenProto(cx, &js_FunctionClass,
                                                    funobj, scopeChain);
     if (!wfunobj)
         return NULL;
-    JSAutoTempValueRooter tvr(cx, wfunobj);
+    AutoValueRooter tvr(cx, wfunobj);
 
     JSFunction *wfun = (JSFunction *) wfunobj;
     wfunobj->setPrivate(wfun);
     wfun->nargs = 0;
     wfun->flags = fun->flags | JSFUN_HEAVYWEIGHT;
     wfun->u.i.nvars = 0;
     wfun->u.i.nupvars = 0;
     wfun->u.i.skipmin = fun->u.i.skipmin;
@@ -594,17 +594,17 @@ ArgSetter(JSContext *cx, JSObject *obj, 
      * backed by the default Object getter and setter. Note the we rely on
      * args_delete to clear the corresponding reserved slot so the GC can
      * collect its value.
      */
     jsid id;
     if (!JS_ValueToId(cx, idval, &id))
         return false;
 
-    JSAutoTempValueRooter tvr(cx);
+    AutoValueRooter tvr(cx);
     return js_DeleteProperty(cx, obj, id, tvr.addr()) &&
            js_SetProperty(cx, obj, id, vp);
 }
 
 static JSBool
 args_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
              JSObject **objp)
 {
@@ -1579,64 +1579,59 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
     JSContext *cx;
     JSFunction *fun;
     uint32 firstword;           /* flag telling whether fun->atom is non-null,
                                    plus for fun->u.i.skipmin, fun->u.i.wrapper,
                                    and 14 bits reserved for future use */
     uintN nargs, nvars, nupvars, n;
     uint32 localsword;          /* word for argument and variable counts */
     uint32 flagsword;           /* word for fun->u.i.nupvars and fun->flags */
-    JSTempValueRooter tvr;
-    JSBool ok;
 
     cx = xdr->cx;
     if (xdr->mode == JSXDR_ENCODE) {
         fun = GET_FUNCTION_PRIVATE(cx, *objp);
         if (!FUN_INTERPRETED(fun)) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_NOT_SCRIPTED_FUNCTION,
                                  JS_GetFunctionName(fun));
-            return JS_FALSE;
+            return false;
         }
         if (fun->u.i.wrapper) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_XDR_CLOSURE_WRAPPER,
                                  JS_GetFunctionName(fun));
-            return JS_FALSE;
+            return false;
         }
         JS_ASSERT((fun->u.i.wrapper & ~1U) == 0);
         firstword = (fun->u.i.skipmin << 2) | (fun->u.i.wrapper << 1) | !!fun->atom;
         nargs = fun->nargs;
         nvars = fun->u.i.nvars;
         nupvars = fun->u.i.nupvars;
         localsword = (nargs << 16) | nvars;
         flagsword = (nupvars << 16) | fun->flags;
     } else {
         fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
         if (!fun)
-            return JS_FALSE;
+            return false;
         FUN_OBJECT(fun)->clearParent();
         FUN_OBJECT(fun)->clearProto();
 #ifdef __GNUC__
         nvars = nargs = nupvars = 0;    /* quell GCC uninitialized warning */
 #endif
     }
 
-    /* From here on, control flow must flow through label out. */
-    MUST_FLOW_THROUGH("out");
-    JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr);
-    ok = JS_TRUE;
+    AutoValueRooter tvr(cx, FUN_OBJECT(fun));
 
     if (!JS_XDRUint32(xdr, &firstword))
-        goto bad;
+        return false;
     if ((firstword & 1U) && !js_XDRStringAtom(xdr, &fun->atom))
-        goto bad;
+        return false;
     if (!JS_XDRUint32(xdr, &localsword) ||
         !JS_XDRUint32(xdr, &flagsword)) {
-        goto bad;
+        return false;
     }
 
     if (xdr->mode == JSXDR_DECODE) {
         nargs = localsword >> 16;
         nvars = uint16(localsword);
         JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
         nupvars = flagsword >> 16;
         fun->flags = uint16(flagsword);
@@ -1650,16 +1645,17 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
         void *mark;
         uintN i;
         uintN bitmapLength;
         uint32 *bitmap;
         jsuword *names;
         JSAtom *name;
         JSLocalKind localKind;
 
+        bool ok = true;
         mark = JS_ARENA_MARK(&xdr->cx->tempPool);
 
         /*
          * From this point the control must flow via the label release_mark.
          *
          * To xdr the names we prefix the names with a bitmap descriptor and
          * then xdr the names as strings. For argument names (indexes below
          * nargs) the corresponding bit in the bitmap is unset when the name
@@ -1668,23 +1664,23 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
          * name is declared as const, not as ordinary var.
          * */
         MUST_FLOW_THROUGH("release_mark");
         bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32);
         JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool,
                                bitmapLength * sizeof *bitmap);
         if (!bitmap) {
             js_ReportOutOfScriptQuota(xdr->cx);
-            ok = JS_FALSE;
+            ok = false;
             goto release_mark;
         }
         if (xdr->mode == JSXDR_ENCODE) {
             names = js_GetLocalNameArray(xdr->cx, fun, &xdr->cx->tempPool);
             if (!names) {
-                ok = JS_FALSE;
+                ok = false;
                 goto release_mark;
             }
             memset(bitmap, 0, bitmapLength * sizeof *bitmap);
             for (i = 0; i != n; ++i) {
                 if (i < fun->nargs
                     ? JS_LOCAL_NAME_TO_ATOM(names[i]) != NULL
                     : JS_LOCAL_NAME_IS_CONST(names[i])) {
                     bitmap[i >> JS_BITS_PER_UINT32_LOG2] |=
@@ -1729,47 +1725,40 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
                                ? JSLOCAL_CONST
                                : JSLOCAL_VAR)
                             : JSLOCAL_UPVAR;
                 ok = js_AddLocal(xdr->cx, fun, name, localKind);
                 if (!ok)
                     goto release_mark;
             }
         }
-        ok = JS_TRUE;
 
       release_mark:
         JS_ARENA_RELEASE(&xdr->cx->tempPool, mark);
         if (!ok)
-            goto out;
+            return false;
 
         if (xdr->mode == JSXDR_DECODE)
             js_FreezeLocalNames(cx, fun);
     }
 
     if (!js_XDRScript(xdr, &fun->u.i.script, false, NULL))
-        goto bad;
+        return false;
 
     if (xdr->mode == JSXDR_DECODE) {
         *objp = FUN_OBJECT(fun);
         if (fun->u.i.script != JSScript::emptyScript()) {
 #ifdef CHECK_SCRIPT_OWNER
             fun->u.i.script->owner = NULL;
 #endif
             js_CallNewScriptHook(cx, fun->u.i.script, fun);
         }
     }
 
-out:
-    JS_POP_TEMP_ROOT(cx, &tvr);
-    return ok;
-
-bad:
-    ok = JS_FALSE;
-    goto out;
+    return true;
 }
 
 #else  /* !JS_HAS_XDR */
 
 #define js_XDRFunctionObject NULL
 
 #endif /* !JS_HAS_XDR */
 
@@ -2676,54 +2665,51 @@ js_ValueToCallableObject(JSContext *cx, 
 }
 
 void
 js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
 {
     JSStackFrame *fp;
     uintN error;
     const char *name, *source;
-    JSTempValueRooter tvr;
 
     for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down)
         continue;
     name = source = NULL;
-    JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr);
+
+    AutoValueRooter tvr(cx);
     if (flags & JSV2F_ITERATOR) {
         error = JSMSG_BAD_ITERATOR;
         name = js_iterator_str;
         JSString *src = js_ValueToSource(cx, *vp);
         if (!src)
-            goto out;
-        tvr.u.value = STRING_TO_JSVAL(src);
+            return;
+        tvr.setString(src);
         JSString *qsrc = js_QuoteString(cx, src, 0);
         if (!qsrc)
-            goto out;
-        tvr.u.value = STRING_TO_JSVAL(qsrc);
+            return;
+        tvr.setString(qsrc);
         source = js_GetStringBytes(cx, qsrc);
         if (!source)
-            goto out;
+            return;
     } else if (flags & JSV2F_CONSTRUCT) {
         error = JSMSG_NOT_CONSTRUCTOR;
     } else {
         error = JSMSG_NOT_FUNCTION;
     }
 
     js_ReportValueError3(cx, error,
                          (fp && fp->regs &&
                           StackBase(fp) <= vp && vp < fp->regs->sp)
                          ? vp - fp->regs->sp
                          : (flags & JSV2F_SEARCH_STACK)
                          ? JSDVG_SEARCH_STACK
                          : JSDVG_IGNORE_STACK,
                          *vp, NULL,
                          name, source);
-
-  out:
-    JS_POP_TEMP_ROOT(cx, &tvr);
 }
 
 /*
  * When a function has between 2 and MAX_ARRAY_LOCALS arguments and variables,
  * their name are stored as the JSLocalNames.array.
  */
 #define MAX_ARRAY_LOCALS 8
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -82,16 +82,17 @@
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
 #ifdef INCLUDE_MOZILLA_DTRACE
 #include "jsdtracef.h"
 #endif
 
+#include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 
 /*
  * Include the headers for mmap.
  */
 #if defined(XP_WIN)
 # include <windows.h>
 #endif
@@ -105,24 +106,16 @@
 #endif
 #if !defined(MAP_ANONYMOUS)
 # define MAP_ANONYMOUS 0
 #endif
 
 using namespace js;
 
 /*
- * Check JSTempValueUnion has the size of jsval and void * so we can
- * reinterpret jsval as void* GC-thing pointer and use JSTVU_SINGLE for
- * different GC-things.
- */
-JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval));
-JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(void *));
-
-/*
  * Check that JSTRACE_XML follows JSTRACE_OBJECT, JSTRACE_DOUBLE and
  * JSTRACE_STRING.
  */
 JS_STATIC_ASSERT(JSTRACE_OBJECT == 0);
 JS_STATIC_ASSERT(JSTRACE_DOUBLE == 1);
 JS_STATIC_ASSERT(JSTRACE_STRING == 2);
 JS_STATIC_ASSERT(JSTRACE_XML    == 3);
 
@@ -2254,29 +2247,30 @@ gc_lock_traversal(JSDHashTable *table, J
     uint32 traceKind;
 
     JS_ASSERT(lhe->count >= 1);
     traceKind = js_GetGCThingTraceKind(thing);
     JS_CALL_TRACER(trc, thing, traceKind, "locked object");
     return JS_DHASH_NEXT;
 }
 
-#define TRACE_JSVALS(trc, len, vec, name)                                     \
-    JS_BEGIN_MACRO                                                            \
-    jsval _v, *_vp, *_end;                                                    \
-                                                                              \
-        for (_vp = vec, _end = _vp + len; _vp < _end; _vp++) {                \
-            _v = *_vp;                                                        \
-            if (JSVAL_IS_TRACEABLE(_v)) {                                     \
-                JS_SET_TRACING_INDEX(trc, name, _vp - (vec));                 \
-                js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(_v),                  \
-                                JSVAL_TRACE_KIND(_v));                        \
-            }                                                                 \
-        }                                                                     \
-    JS_END_MACRO
+namespace js {
+
+void
+TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len)
+{
+    for (uint32 i = 0; i < len; i++) {
+        if (JSObject *obj = vec[i]) {
+            JS_SET_TRACING_INDEX(trc, "vector", i);
+            js_CallGCMarker(trc, obj, JSTRACE_OBJECT);
+        }
+    }
+}
+
+}
 
 void
 js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
 {
     uintN nslots, minargs, skip;
 
     if (fp->callobj)
         JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call");
@@ -2292,17 +2286,17 @@ js_TraceStackFrame(JSTracer *trc, JSStac
              * popped already.
              */
             if (fp->regs && fp->regs->sp) {
                 nslots = (uintN) (fp->regs->sp - fp->slots);
                 JS_ASSERT(nslots >= fp->script->nfixed);
             } else {
                 nslots = fp->script->nfixed;
             }
-            TRACE_JSVALS(trc, nslots, fp->slots, "slot");
+            js::TraceValues(trc, nslots, fp->slots, "slot");
         }
     } else {
         JS_ASSERT(!fp->slots);
         JS_ASSERT(!fp->regs);
     }
 
     /* Allow for primitive this parameter due to JSFUN_THISP_* flags. */
     JS_CALL_VALUE_TRACER(trc, fp->thisv, "this");
@@ -2317,17 +2311,17 @@ js_TraceStackFrame(JSTracer *trc, JSStac
                 nslots = minargs;
             if (!FUN_INTERPRETED(fp->fun)) {
                 JS_ASSERT(!(fp->fun->flags & JSFUN_FAST_NATIVE));
                 nslots += fp->fun->u.n.extra;
             }
             if (fp->fun->flags & JSFRAME_ROOTED_ARGV)
                 skip = 2 + fp->argc;
         }
-        TRACE_JSVALS(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand");
+        js::TraceValues(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand");
     }
 
     JS_CALL_VALUE_TRACER(trc, fp->rval, "rval");
     if (fp->scopeChain)
         JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain");
 }
 
 void
@@ -2372,17 +2366,16 @@ TraceFrameChain(JSTracer *trc, JSStackFr
         js_TraceStackFrame(trc, fp);
     } while ((fp = fp->down) != NULL);
 }
 
 JS_REQUIRES_STACK JS_FRIEND_API(void)
 js_TraceContext(JSTracer *trc, JSContext *acx)
 {
     JSStackHeader *sh;
-    JSTempValueRooter *tvr;
 
     /*
      * Trace active and suspended callstacks.
      *
      * Since js_GetTopStackFrame needs to dereference cx->thread to check for
      * JIT frames, we check for non-null thread here and avoid null checks
      * there. See bug 471197.
      */
@@ -2422,59 +2415,32 @@ js_TraceContext(JSTracer *trc, JSContext
     } else {
         /* Avoid keeping GC-ed junk stored in JSContext.exception. */
         acx->exception = JSVAL_NULL;
     }
 
     for (sh = acx->stackHeaders; sh; sh = sh->down) {
         METER(trc->context->runtime->gcStats.stackseg++);
         METER(trc->context->runtime->gcStats.segslots += sh->nslots);
-        TRACE_JSVALS(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack");
+        js::TraceValues(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack");
     }
 
-    for (tvr = acx->tempValueRooters; tvr; tvr = tvr->down) {
-        switch (tvr->count) {
-          case JSTVU_SINGLE:
-            JS_SET_TRACING_NAME(trc, "tvr->u.value");
-            js_CallValueTracerIfGCThing(trc, tvr->u.value);
-            break;
-          case JSTVU_TRACE:
-            tvr->u.trace(trc, tvr);
-            break;
-          case JSTVU_SPROP:
-            tvr->u.sprop->trace(trc);
-            break;
-          case JSTVU_WEAK_ROOTS:
-            tvr->u.weakRoots->mark(trc);
-            break;
-          case JSTVU_COMPILER:
-            tvr->u.compiler->trace(trc);
-            break;
-          case JSTVU_SCRIPT:
-            js_TraceScript(trc, tvr->u.script);
-            break;
-          case JSTVU_ENUMERATOR:
-            static_cast<JSAutoEnumStateRooter *>(tvr)->mark(trc);
-            break;
-          default:
-            JS_ASSERT(tvr->count >= 0);
-            TRACE_JSVALS(trc, tvr->count, tvr->u.array, "tvr->u.array");
-        }
-    }
+    for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down)
+        gcr->trace(trc);
 
     if (acx->sharpObjectMap.depth > 0)
         js_TraceSharpMap(trc, &acx->sharpObjectMap);
 
     js_TraceRegExpStatics(trc, acx);
 
 #ifdef JS_TRACER
     InterpState* state = acx->interpState;
     while (state) {
         if (state->nativeVp)
-            TRACE_JSVALS(trc, state->nativeVpLen, state->nativeVp, "nativeVp");
+            js::TraceValues(trc, state->nativeVpLen, state->nativeVp, "nativeVp");
         state = state->prev;
     }
 #endif
 }
 
 JS_REQUIRES_STACK void
 js_TraceRuntime(JSTracer *trc, JSBool allAtoms)
 {
@@ -3360,38 +3326,35 @@ out:
 #endif
 
     /*
      * Execute JSGC_END callback outside the lock. Again, sample the callback
      * pointer in case it changes, since we are outside of the GC vs. requests
      * interlock mechanism here.
      */
     if (gckind != GC_SET_SLOT_REQUEST && (callback = rt->gcCallback)) {
-        JSWeakRoots savedWeakRoots;
-        JSTempValueRooter tvr;
-
-        if (gckind & GC_KEEP_ATOMS) {
+        if (!(gckind & GC_KEEP_ATOMS)) {
+            (void) callback(cx, JSGC_END);
+
+            /*
+             * On shutdown iterate until JSGC_END callback stops creating
+             * garbage.
+             */
+            if (gckind == GC_LAST_CONTEXT && rt->gcPoke)
+                goto restart_at_beginning;
+        } else {
             /*
              * We allow JSGC_END implementation to force a full GC or allocate
              * new GC things. Thus we must protect the weak roots from garbage
              * collection and overwrites.
              */
-            savedWeakRoots = cx->weakRoots;
-            JS_PUSH_TEMP_ROOT_WEAK_COPY(cx, &savedWeakRoots, &tvr);
+            AutoSaveWeakRoots save(cx);
+
             JS_KEEP_ATOMS(rt);
             JS_UNLOCK_GC(rt);
-        }
-
-        (void) callback(cx, JSGC_END);
-
-        if (gckind & GC_KEEP_ATOMS) {
+
+            (void) callback(cx, JSGC_END);
+
             JS_LOCK_GC(rt);
             JS_UNKEEP_ATOMS(rt);
-            JS_POP_TEMP_ROOT(cx, &tvr);
-        } else if (gckind == GC_LAST_CONTEXT && rt->gcPoke) {
-            /*
-             * On shutdown iterate until JSGC_END callback stops creating
-             * garbage.
-             */
-            goto restart_at_beginning;
         }
     }
 }
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -449,9 +449,28 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp);
  * This function is defined in jsdbgapi.cpp but is declared here to avoid
  * polluting jsdbgapi.h, a public API header, with internal functions.
  */
 extern void
 js_MarkTraps(JSTracer *trc);
 
 JS_END_EXTERN_C
 
+namespace js {
+
+void
+TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len);
+
+inline void
+TraceValues(JSTracer *trc, size_t len, jsval *vec, const char *name)
+{
+    for (jsval *vp = vec, *end = vp + len; vp < end; vp++) {
+        jsval v = *vp;
+        if (JSVAL_IS_TRACEABLE(v)) {
+            JS_SET_TRACING_INDEX(trc, name, vp - vec);
+            js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
+        }
+    }
+}
+
+}
+
 #endif /* jsgc_h___ */
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -795,17 +795,17 @@ js_GetScopeChain(JSContext *cx, JSStackF
      * common with subsequent steps to include in the loop.
      *
      * js_CloneBlockObject leaves the clone's parent slot uninitialized. We
      * populate it below.
      */
     JSObject *innermostNewChild = js_CloneBlockObject(cx, sharedBlock, fp);
     if (!innermostNewChild)
         return NULL;
-    JSAutoTempValueRooter tvr(cx, innermostNewChild);
+    AutoValueRooter tvr(cx, innermostNewChild);
 
     /*
      * Clone our way towards outer scopes until we reach the innermost
      * enclosing function, or the innermost block we've already cloned.
      */
     JSObject *newChild = innermostNewChild;
     for (;;) {
         JS_ASSERT(newChild->getProto() == sharedBlock);
@@ -1000,17 +1000,17 @@ JSClass js_NoSuchMethodClass = {
  */
 JS_STATIC_INTERPRET JSBool
 js_OnUnknownMethod(JSContext *cx, jsval *vp)
 {
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
 
     JSObject *obj = JSVAL_TO_OBJECT(vp[1]);
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
-    JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
+    AutoValueRooter tvr(cx, JSVAL_NULL);
     if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr()))
         return false;
     if (JSVAL_IS_PRIMITIVE(tvr.value())) {
         vp[0] = tvr.value();
     } else {
 #if JS_HAS_XML_SUPPORT
         /* Extract the function name from function::name qname. */
         if (!JSVAL_IS_PRIMITIVE(vp[0])) {
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -210,28 +210,21 @@ Iterator(JSContext *cx, JSObject *iterob
 
     *rval = argv[0];
     return js_ValueToIterator(cx, flags, rval);
 }
 
 static JSBool
 NewKeyValuePair(JSContext *cx, jsid key, jsval val, jsval *rval)
 {
-    jsval vec[2];
-    JSTempValueRooter tvr;
-    JSObject *aobj;
+    jsval vec[2] = { ID_TO_VALUE(key), val };
+    AutoArrayRooter tvr(cx, 2, vec);
 
-    vec[0] = ID_TO_VALUE(key);
-    vec[1] = val;
-
-    JS_PUSH_TEMP_ROOT(cx, 2, vec, &tvr);
-    aobj = js_NewArrayObject(cx, 2, vec);
+    JSObject *aobj = js_NewArrayObject(cx, 2, vec);
     *rval = OBJECT_TO_JSVAL(aobj);
-    JS_POP_TEMP_ROOT(cx, &tvr);
-
     return aobj != NULL;
 }
 
 static JSBool
 IteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval)
 {
     JSObject *iterable;
     jsval state;
@@ -342,109 +335,99 @@ js_GetNativeIteratorFlags(JSContext *cx,
 /*
  * Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists.
  * Otherwise construct the default iterator.
  */
 JS_FRIEND_API(JSBool)
 js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)
 {
     JSObject *obj;
-    JSTempValueRooter tvr;
     JSAtom *atom;
     JSClass *clasp;
     JSExtendedClass *xclasp;
-    JSBool ok;
     JSObject *iterobj;
     jsval arg;
 
-    JS_ASSERT(!(flags & ~(JSITER_ENUMERATE |
-                          JSITER_FOREACH |
-                          JSITER_KEYVALUE)));
+    JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | JSITER_FOREACH | JSITER_KEYVALUE)));
 
     /* JSITER_KEYVALUE must always come with JSITER_FOREACH */
     JS_ASSERT(!(flags & JSITER_KEYVALUE) || (flags & JSITER_FOREACH));
 
+    AutoValueRooter tvr(cx);
+
     /* XXX work around old valueOf call hidden beneath js_ValueToObject */
     if (!JSVAL_IS_PRIMITIVE(*vp)) {
         obj = JSVAL_TO_OBJECT(*vp);
     } else {
         /*
          * Enumerating over null and undefined gives an empty enumerator.
          * This is contrary to ECMA-262 9.9 ToObject, invoked from step 3 of
          * the first production in 12.6.4 and step 4 of the second production,
          * but it's "web JS" compatible.
          */
         if ((flags & JSITER_ENUMERATE)) {
             if (!js_ValueToObject(cx, *vp, &obj))
-                return JS_FALSE;
+                return false;
             if (!obj)
                 goto default_iter;
         } else {
             obj = js_ValueToNonNullObject(cx, *vp);
             if (!obj)
-                return JS_FALSE;
+                return false;
         }
     }
 
-    JS_ASSERT(obj);
-    JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
+    tvr.setObject(obj);
 
     clasp = OBJ_GET_CLASS(cx, obj);
     if ((clasp->flags & JSCLASS_IS_EXTENDED) &&
         (xclasp = (JSExtendedClass *) clasp)->iteratorObject) {
         iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH));
         if (!iterobj)
-            goto bad;
+            return false;
         *vp = OBJECT_TO_JSVAL(iterobj);
     } else {
         atom = cx->runtime->atomState.iteratorAtom;
         if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, vp))
-            goto bad;
+            return false;
         if (JSVAL_IS_VOID(*vp)) {
           default_iter:
             /*
              * Fail over to the default enumerating native iterator.
              *
              * Create iterobj with a NULL parent to ensure that we use the
              * correct scope chain to lookup the iterator's constructor. Since
              * we use the parent slot to keep track of the iterable, we must
              * fix it up after.
              */
             iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL);
             if (!iterobj)
-                goto bad;
+                return false;
 
             /* Store in *vp to protect it from GC (callers must root vp). */
             *vp = OBJECT_TO_JSVAL(iterobj);
 
             if (!InitNativeIterator(cx, iterobj, obj, flags))
-                goto bad;
+                return false;
         } else {
             LeaveTrace(cx);
             arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0);
             if (!js_InternalInvoke(cx, obj, *vp, JSINVOKE_ITERATOR, 1, &arg,
                                    vp)) {
-                goto bad;
+                return false;
             }
             if (JSVAL_IS_PRIMITIVE(*vp)) {
                 js_ReportValueError(cx, JSMSG_BAD_ITERATOR_RETURN,
                                     JSDVG_SEARCH_STACK, *vp, NULL);
-                goto bad;
+                return false;
             }
         }
     }
 
-    ok = JS_TRUE;
-  out:
-    if (obj)
-        JS_POP_TEMP_ROOT(cx, &tvr);
-    return ok;
-  bad:
-    ok = JS_FALSE;
-    goto out;
+    return true;
 }
 
 JS_FRIEND_API(JSBool) JS_FASTCALL
 js_CloseIterator(JSContext *cx, jsval v)
 {
     JSObject *obj;
     JSClass *clasp;
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -984,21 +984,21 @@ js_ValueToNumber(JSContext *cx, jsval *v
 
         JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
         obj = JSVAL_TO_OBJECT(v);
 
         /*
          * vp roots obj so we cannot use it as an extra root for
          * obj->defaultValue result when calling the hook.
          */
-        JSAutoTempValueRooter tvr(cx, v);
-        if (!obj->defaultValue(cx, JSTYPE_NUMBER, tvr.addr()))
+        AutoValueRooter gcr(cx, v);
+        if (!obj->defaultValue(cx, JSTYPE_NUMBER, gcr.addr()))
             obj = NULL;
         else
-            v = *vp = tvr.value();
+            v = *vp = gcr.value();
         if (!obj) {
             *vp = JSVAL_NULL;
             return 0.0;
         }
         if (!JSVAL_IS_PRIMITIVE(v))
             break;
     }
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -240,42 +240,34 @@ obj_setSlot(JSContext *cx, JSObject *obj
         return JS_FALSE;
 
     return js_SetProtoOrParent(cx, obj, slot, pobj, JS_TRUE);
 }
 
 static JSBool
 obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
-    jsval iter_state;
     jsid num_properties;
-    JSBool ok;
 
     if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, JSSLOT_COUNT))
-        return JS_FALSE;
-
-    iter_state = JSVAL_NULL;
-    JSAutoEnumStateRooter tvr(cx, obj, &iter_state);
+        return false;
 
     /* Get the number of properties to enumerate. */
-    ok = obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties);
-    if (!ok)
-        goto out;
+    AutoEnumStateRooter iterState(cx, obj);
+    if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties))
+        return false;
 
     if (!JSVAL_IS_INT(num_properties)) {
         JS_ASSERT(0);
         *vp = JSVAL_ZERO;
-        goto out;
+        return true;
     }
     *vp = num_properties;
 
-out:
-    if (!JSVAL_IS_NULL(iter_state))
-        ok &= obj->enumerate(cx, JSENUMERATE_DESTROY, &iter_state, 0);
-    return ok;
+    return true;
 }
 
 #else  /* !JS_HAS_OBJ_PROTO_PROP */
 
 #define object_props NULL
 
 #endif /* !JS_HAS_OBJ_PROTO_PROP */
 
@@ -659,25 +651,23 @@ obj_toSource(JSContext *cx, uintN argc, 
     jsid id;
 #if JS_HAS_GETTER_SETTER
     JSObject *obj2;
     JSProperty *prop;
     uintN attrs;
 #endif
     jsval *val;
     jsval localroot[4] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
-    JSTempValueRooter tvr;
     JSString *gsopold[2];
     JSString *gsop[2];
     JSString *idstr, *valstr, *str;
 
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
-    MUST_FLOW_THROUGH("out");
-    JS_PUSH_TEMP_ROOT(cx, 4, localroot, &tvr);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroot), localroot);
 
     /* If outermost, we need parentheses to be an expression, not a block. */
     outermost = (cx->sharpObjectMap.depth == 0);
     obj = JS_THIS_OBJECT(cx, vp);
     if (!obj || !(he = js_EnterSharpObject(cx, obj, &ida, &chars))) {
         ok = JS_FALSE;
         goto out;
     }
@@ -1032,17 +1022,16 @@ obj_toSource(JSContext *cx, uintN argc, 
     if (!str) {
         js_free(chars);
         ok = JS_FALSE;
         goto out;
     }
     *vp = STRING_TO_JSVAL(str);
     ok = JS_TRUE;
   out:
-    JS_POP_TEMP_ROOT(cx, &tvr);
     return ok;
 
   overflow:
     cx->free(vsharp);
     js_free(chars);
     chars = NULL;
     goto error;
 }
@@ -1961,17 +1950,17 @@ obj_getOwnPropertyDescriptor(JSContext *
 {
     if (argc == 0 || JSVAL_IS_PRIMITIVE(vp[2])) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
         return JS_FALSE;
     }
 
     JSObject *obj = JSVAL_TO_OBJECT(vp[2]);
 
-    JSAutoTempIdRooter nameidr(cx);
+    AutoIdRooter nameidr(cx);
     if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr()))
         return JS_FALSE;
 
     JSObject *pobj;
     JSProperty *prop;
     if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, nameidr.id(), &pobj, &prop))
         return JS_FALSE;
     if (!prop) {
@@ -1981,17 +1970,17 @@ obj_getOwnPropertyDescriptor(JSContext *
 
     uintN attrs;
     if (!pobj->getAttributes(cx, nameidr.id(), prop, &attrs)) {
         pobj->dropProperty(cx, prop);
         return JS_FALSE;
     }
 
     jsval roots[] = { JSVAL_VOID, JSVAL_VOID };
-    JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
     if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
         if (OBJ_IS_NATIVE(obj)) {
             JSScopeProperty *sprop = reinterpret_cast<JSScopeProperty *>(prop);
             if (attrs & JSPROP_GETTER)
                 roots[0] = sprop->getterValue();
             if (attrs & JSPROP_SETTER)
                 roots[1] = sprop->setterValue();
         }
@@ -2042,17 +2031,17 @@ obj_keys(JSContext *cx, uintN argc, jsva
 {
     jsval v = argc == 0 ? JSVAL_VOID : vp[2];
     if (JSVAL_IS_PRIMITIVE(v)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
         return JS_FALSE;
     }
 
     JSObject *obj = JSVAL_TO_OBJECT(v);
-    JSAutoIdArray ida(cx, JS_Enumerate(cx, obj));
+    AutoIdArray ida(cx, JS_Enumerate(cx, obj));
     if (!ida)
         return JS_FALSE;
 
     JSObject *proto;
     if (!js_GetClassPrototype(cx, NULL, JSProto_Array, &proto))
         return JS_FALSE;
     vp[1] = OBJECT_TO_JSVAL(proto);
 
@@ -2207,60 +2196,16 @@ PropertyDescriptor::initialize(JSContext
     if ((hasGet || hasSet) && (hasValue || hasWritable)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DESCRIPTOR);
         return false;
     }
 
     return true;
 }
 
-typedef js::Vector<PropertyDescriptor, 1> PropertyDescriptorArray;
-
-class AutoDescriptorArray : private JSTempValueRooter
-{
-  private:
-    JSContext *cx;
-    PropertyDescriptorArray descriptors;
-
-  public:
-    AutoDescriptorArray(JSContext *cx)
-      : cx(cx), descriptors(cx)
-    {
-        JS_PUSH_TEMP_ROOT_TRACE(cx, trace, this);
-    }
-    ~AutoDescriptorArray() {
-        JS_POP_TEMP_ROOT(cx, this);
-    }
-
-    PropertyDescriptor *append() {
-        if (!descriptors.append(PropertyDescriptor()))
-            return NULL;
-        return &descriptors.back();
-    }
-
-    PropertyDescriptor& operator[](size_t i) {
-        JS_ASSERT(i < descriptors.length());
-        return descriptors[i];
-    }
-
-  private:
-    static void trace(JSTracer *trc, JSTempValueRooter *tvr) {
-        PropertyDescriptorArray &descs =
-            static_cast<AutoDescriptorArray *>(tvr)->descriptors;
-        for (size_t i = 0, len = descs.length(); i < len; i++) {
-            PropertyDescriptor &desc = descs[i];
-
-            JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value");
-            JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get");
-            JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set");
-            js_TraceId(trc, desc.id);
-        }
-    }
-};
-
 static JSBool
 Reject(JSContext *cx, uintN errorNumber, bool throwError, jsid id, bool *rval)
 {
     if (throwError) {
         jsid idstr;
         if (!js_ValueToStringId(cx, ID_TO_VALUE(id), &idstr))
            return JS_FALSE;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber,
@@ -2634,17 +2579,17 @@ obj_defineProperty(JSContext* cx, uintN 
     if (JSVAL_IS_PRIMITIVE(v)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
         return JS_FALSE;
     }
     *vp = vp[2];
     JSObject* obj = JSVAL_TO_OBJECT(*vp);
 
     /* 15.2.3.6 step 2. */
-    JSAutoTempIdRooter nameidr(cx);
+    AutoIdRooter nameidr(cx);
     if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr()))
         return JS_FALSE;
 
     /* 15.2.3.6 step 3. */
     AutoDescriptorArray descs(cx);
     PropertyDescriptor *desc = descs.append();
     if (!desc || !desc->initialize(cx, nameidr.id(), argc >= 3 ? vp[4] : JSVAL_VOID))
         return JS_FALSE;
@@ -2671,17 +2616,17 @@ obj_defineProperties(JSContext* cx, uint
         return JS_FALSE;
     }
 
     JSObject* props = js_ValueToNonNullObject(cx, vp[3]);
     if (!props)
         return JS_FALSE;
     vp[3] = OBJECT_TO_JSVAL(props);
 
-    JSAutoIdArray ida(cx, JS_Enumerate(cx, props));
+    AutoIdArray ida(cx, JS_Enumerate(cx, props));
     if (!ida)
         return JS_FALSE;
 
     AutoDescriptorArray descs(cx);
     size_t len = ida.length();
     for (size_t i = 0; i < len; i++) {
         jsid id = ida[i];
         PropertyDescriptor* desc = descs.append();
@@ -2735,17 +2680,17 @@ obj_create(JSContext *cx, uintN argc, js
     /* 15.2.3.5 step 4. */
     if (argc > 1 && vp[3] != JSVAL_VOID) {
         if (JSVAL_IS_PRIMITIVE(vp[3])) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
             return JS_FALSE;
         }
 
         JSObject *props = JSVAL_TO_OBJECT(vp[3]);
-        JSAutoIdArray ida(cx, JS_Enumerate(cx, props));
+        AutoIdArray ida(cx, JS_Enumerate(cx, props));
         if (!ida)
             return JS_FALSE;
 
         AutoDescriptorArray descs(cx);
         size_t len = ida.length();
         for (size_t i = 0; i < len; i++) {
             jsid id = ida[i];
             PropertyDescriptor *desc = descs.append();
@@ -2933,17 +2878,17 @@ js_NewObjectWithGivenProto(JSContext *cx
         obj->map = const_cast<JSObjectMap *>(ops->objectMap);
     }
 
     /*
      * Do not call debug hooks on trace, because we might be in a non-_FAIL
      * builtin. See bug 481444.
      */
     if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
-        JSAutoTempValueRooter tvr(cx, obj);
+        AutoValueRooter tvr(cx, obj);
         JS_KEEP_ATOMS(cx->runtime);
         cx->debugHooks->objectHook(cx, obj, JS_TRUE,
                                    cx->debugHooks->objectHookData);
         JS_UNKEEP_ATOMS(cx->runtime);
         cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
     }
 
 out:
@@ -3609,17 +3554,17 @@ js_XDRBlockObject(JSXDRState *xdr, JSObj
          */
         if (parentId == NO_PARENT_INDEX)
             parent = NULL;
         else
             parent = xdr->script->getObject(parentId);
         obj->setParent(parent);
     }
 
-    JSAutoTempValueRooter tvr(cx, obj);
+    AutoValueRooter tvr(cx, obj);
 
     if (!JS_XDRUint32(xdr, &tmp))
         return false;
 
     if (xdr->mode == JSXDR_DECODE) {
         depth = (uint16)(tmp >> 16);
         count = (uint16)tmp;
         STOBJ_SET_SLOT(obj, JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth));
@@ -3702,17 +3647,16 @@ JSObject *
 js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
              JSClass *clasp, JSNative constructor, uintN nargs,
              JSPropertySpec *ps, JSFunctionSpec *fs,
              JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
 {
     JSAtom *atom;
     JSProtoKey key;
     JSObject *proto, *ctor;
-    JSTempValueRooter tvr;
     jsval cval, rval;
     JSBool named;
     JSFunction *fun;
 
     atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
     if (!atom)
         return NULL;
 
@@ -3738,17 +3682,17 @@ js_InitClass(JSContext *cx, JSObject *ob
     }
 
     /* Create a prototype object for this class. */
     proto = js_NewObject(cx, clasp, parent_proto, obj);
     if (!proto)
         return NULL;
 
     /* After this point, control must exit via label bad or out. */
-    JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr);
+    AutoValueRooter tvr(cx, proto);
 
     if (!constructor) {
         /*
          * Lacking a constructor, name the prototype (e.g., Math) unless this
          * class (a) is anonymous, i.e. for internal use only; (b) the class
          * of obj (the global object) is has a reserved slot indexed by key;
          * and (c) key is not the null key.
          */
@@ -3828,17 +3772,16 @@ js_InitClass(JSContext *cx, JSObject *ob
     if (!OBJ_SCOPE(proto)->ensureEmptyScope(cx, clasp))
         goto bad;
 
     /* If this is a standard class, cache its prototype. */
     if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor))
         goto bad;
 
 out:
-    JS_POP_TEMP_ROOT(cx, &tvr);
     return proto;
 
 bad:
     if (named)
         (void) obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval);
     proto = NULL;
     goto out;
 }
@@ -4136,29 +4079,29 @@ js_FindClassObject(JSContext *cx, JSObje
 
 JSObject *
 js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
                    JSObject *parent, uintN argc, jsval *argv)
 {
     jsval cval, rval;
     JSObject *obj, *ctor;
 
-    JSAutoTempValueRooter argtvr(cx, argc, argv);
+    AutoArrayRooter argtvr(cx, argc, argv);
 
     JSProtoKey protoKey = GetClassProtoKey(clasp);
     if (!js_FindClassObject(cx, parent, protoKey, &cval, clasp))
         return NULL;
 
     if (JSVAL_IS_PRIMITIVE(cval)) {
         js_ReportIsNotFunction(cx, &cval, JSV2F_CONSTRUCT | JSV2F_SEARCH_STACK);
         return NULL;
     }
 
     /* Protect cval in case a crazy getter for .prototype uproots it. */
-    JSAutoTempValueRooter tvr(cx, cval);
+    AutoValueRooter tvr(cx, cval);
 
     /*
      * If proto or parent are NULL, set them to Constructor.prototype and/or
      * Constructor.__parent__, just like JSOP_NEW does.
      */
     ctor = JSVAL_TO_OBJECT(cval);
     if (!parent)
         parent = ctor->getParent();
@@ -4948,18 +4891,16 @@ JSBool
 js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
              JSScopeProperty *sprop, uintN getHow, jsval *vp)
 {
     LeaveTraceIfGlobalObject(cx, pobj);
 
     JSScope *scope;
     uint32 slot;
     int32 sample;
-    JSTempValueRooter tvr, tvr2;
-    JSBool ok;
 
     JS_ASSERT(OBJ_IS_NATIVE(pobj));
     JS_ASSERT(JS_IS_OBJ_LOCKED(cx, pobj));
     scope = OBJ_SCOPE(pobj);
 
     slot = sprop->slot;
     *vp = (slot != SPROP_INVALID_SLOT)
           ? LOCKED_OBJ_GET_SLOT(pobj, slot)
@@ -4969,25 +4910,24 @@ js_NativeGet(JSContext *cx, JSObject *ob
 
     if (JS_UNLIKELY(sprop->isMethod()) && (getHow & JSGET_NO_METHOD_BARRIER)) {
         JS_ASSERT(sprop->methodValue() == *vp);
         return true;
     }
 
     sample = cx->runtime->propertyRemovals;
     JS_UNLOCK_SCOPE(cx, scope);
-    JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);
-    JS_PUSH_TEMP_ROOT_OBJECT(cx, pobj, &tvr2);
-    ok = sprop->get(cx, obj, pobj, vp);
-    JS_POP_TEMP_ROOT(cx, &tvr2);
-    JS_POP_TEMP_ROOT(cx, &tvr);
-    if (!ok)
-        return false;
-
+    {
+        AutoScopePropertyRooter tvr(cx, sprop);
+        AutoValueRooter tvr2(cx, pobj);
+        if (!sprop->get(cx, obj, pobj, vp))
+            return false;
+    }
     JS_LOCK_SCOPE(cx, scope);
+
     if (SLOT_IN_SCOPE(slot, scope) &&
         (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
          scope->hasProperty(sprop))) {
         jsval v = *vp;
         if (!scope->methodWriteBarrier(cx, sprop, v)) {
             JS_UNLOCK_SCOPE(cx, scope);
             return false;
         }
@@ -5001,18 +4941,16 @@ JSBool
 js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added,
              jsval *vp)
 {
     LeaveTraceIfGlobalObject(cx, obj);
 
     JSScope *scope;
     uint32 slot;
     int32 sample;
-    JSTempValueRooter tvr;
-    JSBool ok;
 
     JS_ASSERT(OBJ_IS_NATIVE(obj));
     JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj));
     scope = OBJ_SCOPE(obj);
 
     slot = sprop->slot;
     if (slot != SPROP_INVALID_SLOT) {
         OBJ_CHECK_SLOT(obj, slot);
@@ -5034,21 +4972,21 @@ js_NativeSet(JSContext *cx, JSObject *ob
          * or throw if we're in strict mode.
          */
         if (!(sprop->attrs & JSPROP_GETTER) && SPROP_HAS_STUB_SETTER(sprop))
             return js_ReportGetterOnlyAssignment(cx);
     }
 
     sample = cx->runtime->propertyRemovals;
     JS_UNLOCK_SCOPE(cx, scope);
-    JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);
-    ok = sprop->set(cx, obj, vp);
-    JS_POP_TEMP_ROOT(cx, &tvr);
-    if (!ok)
-        return false;
+    {
+        AutoScopePropertyRooter tvr(cx, sprop);
+        if (!sprop->set(cx, obj, vp))
+            return false;
+    }
 
     JS_LOCK_SCOPE(cx, scope);
     if (SLOT_IN_SCOPE(slot, scope) &&
         (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
          scope->hasProperty(sprop))) {
         jsval v = *vp;
         if (!added && !scope->methodWriteBarrier(cx, sprop, v)) {
             JS_UNLOCK_SCOPE(cx, scope);
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -47,22 +47,24 @@
  * ordered property names, called the map; and a dense vector of property
  * values, called slots.  The map/slot pointer pair is GC'ed, while the map
  * is reference counted and the slot vector is malloc'ed.
  */
 #include "jshash.h" /* Added by JSIFY */
 #include "jspubtd.h"
 #include "jsprvtd.h"
 
+namespace js { class AutoDescriptorArray; }
+
 /*
  * A representation of ECMA-262 ed. 5's internal property descriptor data
  * structure.
  */
 struct PropertyDescriptor {
-  friend class AutoDescriptorArray;
+  friend class js::AutoDescriptorArray;
 
   private:
     PropertyDescriptor();
 
   public:
     /* 8.10.5 ToPropertyDescriptor(Obj) */
     bool initialize(JSContext* cx, jsid id, jsval v);
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -78,9 +78,39 @@ JSObject::unbrand(JSContext *cx)
             }
         }
         scope->setGeneric();
         JS_UNLOCK_SCOPE(cx, scope);
     }
     return true;
 }
 
+namespace js {
+
+typedef Vector<PropertyDescriptor, 1> PropertyDescriptorArray;
+
+class AutoDescriptorArray : private AutoGCRooter
+{
+  public:
+    AutoDescriptorArray(JSContext *cx)
+      : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx)
+    { }
+
+    PropertyDescriptor *append() {
+        if (!descriptors.append(PropertyDescriptor()))
+            return NULL;
+        return &descriptors.back();
+    }
+
+    PropertyDescriptor& operator[](size_t i) {
+        JS_ASSERT(i < descriptors.length());
+        return descriptors[i];
+    }
+
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
+  private:
+    PropertyDescriptorArray descriptors;
+};
+
+}
+
 #endif /* jsobjinlines_h___ */
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -60,16 +60,18 @@
 #include "jsutil.h"
 #include "jsxml.h"
 #include "jsvector.h"
 
 #include "json.h"
 
 #include "jsatominlines.h"
 
+using namespace js;
+
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4351)
 #endif
 
 struct JSONParser
 {
     JSONParser(JSContext *cx)
@@ -101,51 +103,48 @@ JSClass js_JSONClass = {
     JSCLASS_NO_OPTIONAL_MEMBERS
 };
 
 JSBool
 js_json_parse(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *s = NULL;
     jsval *argv = vp + 2;
-    jsval reviver = JSVAL_NULL;
-    JSAutoTempValueRooter tvr(cx, 1, &reviver);
+    AutoValueRooter reviver(cx, JSVAL_NULL);
 
-    if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, &reviver))
+    if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, reviver.addr()))
         return JS_FALSE;
 
     JSONParser *jp = js_BeginJSONParse(cx, vp);
     JSBool ok = jp != NULL;
     if (ok) {
         const jschar *chars;
         size_t length;
         s->getCharsAndLength(chars, length);
         ok = js_ConsumeJSONText(cx, jp, chars, length);
-        ok &= js_FinishJSONParse(cx, jp, reviver);
+        ok &= js_FinishJSONParse(cx, jp, reviver.value());
     }
 
     return ok;
 }
 
 JSBool
 js_json_stringify(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval *argv = vp + 2;
-    JSObject *replacer = NULL;
-    jsval space = JSVAL_NULL;
-    JSAutoTempValueRooter tvr(cx, replacer);
-    JSAutoTempValueRooter tvr2(cx, 1, &space);
+    AutoValueRooter space(cx, JSVAL_NULL);
+    AutoObjectRooter replacer(cx);
 
     // Must throw an Error if there isn't a first arg
-    if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, &replacer, &space))
+    if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, replacer.addr(), space.addr()))
         return JS_FALSE;
 
     JSCharBuffer cb(cx);
 
-    if (!js_Stringify(cx, vp, replacer, space, cb))
+    if (!js_Stringify(cx, vp, replacer.object(), space.value(), cb))
         return JS_FALSE;
 
     // XXX This can never happen to nsJSON.cpp, but the JSON object
     // needs to support returning undefined. So this is a little awkward
     // for the API, because we want to support streaming writers.
     if (!cb.empty()) {
         JSString *str = js_NewStringFromCharBuffer(cx, cb);
         if (!str)
@@ -253,17 +252,17 @@ static JSBool
 JO(JSContext *cx, jsval *vp, StringifyContext *scx)
 {
     JSObject *obj = JSVAL_TO_OBJECT(*vp);
 
     if (!scx->cb.append('{'))
         return JS_FALSE;
 
     jsval vec[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
-    JSAutoTempValueRooter tvr(cx, 3, vec);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec);
     jsval& key = vec[0];
     jsval& outputValue = vec[1];
 
     JSObject *iterObj = NULL;
     jsval *keySource = vp;
     bool usingWhitelist = false;
 
     // if the replacer is an array, we use the keys from it
@@ -302,17 +301,17 @@ JO(JSContext *cx, jsval *vp, StringifyCo
         JSString *ks;
         if (JSVAL_IS_STRING(key)) {
             ks = JSVAL_TO_STRING(key);
         } else {
             ks = js_ValueToString(cx, key);
             if (!ks)
                 goto error_break;
         }
-        JSAutoTempValueRooter keyStringRoot(cx, ks);
+        AutoValueRooter keyStringRoot(cx, ks);
 
         // Don't include prototype properties, since this operation is
         // supposed to be implemented as if by ES3.1 Object.keys()
         jsid id;
         JSObject *obj2;
         JSProperty *prop;
         if (!js_ValueToStringId(cx, STRING_TO_JSVAL(ks), &id) ||
             !js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &obj2, &prop)) {
@@ -388,31 +387,30 @@ JA(JSContext *cx, jsval *vp, StringifyCo
 
     if (!scx->cb.append('['))
         return JS_FALSE;
 
     jsuint length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
-    jsval outputValue = JSVAL_NULL;
-    JSAutoTempValueRooter tvr(cx, 1, &outputValue);
+    AutoValueRooter outputValue(cx, JSVAL_NULL);
 
     jsid id;
     jsuint i;
     for (i = 0; i < length; i++) {
         id = INT_TO_JSID(i);
 
-        if (!obj->getProperty(cx, id, &outputValue))
+        if (!obj->getProperty(cx, id, outputValue.addr()))
             return JS_FALSE;
 
-        if (!Str(cx, id, obj, scx, &outputValue))
+        if (!Str(cx, id, obj, scx, outputValue.addr()))
             return JS_FALSE;
 
-        if (outputValue == JSVAL_VOID) {
+        if (outputValue.value() == JSVAL_VOID) {
             if (!js_AppendLiteral(scx->cb, "null"))
                 return JS_FALSE;
         }
 
         if (i < length - 1) {
             if (!scx->cb.append(','))
                 return JS_FALSE;
             if (!WriteIndent(cx, scx, scx->depth))
@@ -565,105 +563,94 @@ js_Stringify(JSContext *cx, jsval *vp, J
 static JSBool IsNumChar(jschar c)
 {
     return ((c <= '9' && c >= '0') || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E');
 }
 
 static JSBool HandleData(JSContext *cx, JSONParser *jp, JSONDataType type);
 static JSBool PopState(JSContext *cx, JSONParser *jp);
 
-static JSBool
-DestroyIdArrayOnError(JSContext *cx, JSIdArray *ida) {
-    JS_DestroyIdArray(cx, ida);
-    return JS_FALSE;
-}
-
-static JSBool
+static bool
 Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp)
 {
-    JS_CHECK_RECURSION(cx, return JS_FALSE);
+    JS_CHECK_RECURSION(cx, return false);
 
     if (!holder->getProperty(cx, id, vp))
-        return JS_FALSE;
+        return false;
 
     JSObject *obj;
 
     if (!JSVAL_IS_PRIMITIVE(*vp) && !(obj = JSVAL_TO_OBJECT(*vp))->isCallable()) {
-        jsval propValue = JSVAL_NULL;
-        JSAutoTempValueRooter tvr(cx, 1, &propValue);
+        AutoValueRooter propValue(cx, JSVAL_NULL);
 
         if(obj->isArray()) {
             jsuint length = 0;
             if (!js_GetLengthProperty(cx, obj, &length))
-                return JS_FALSE;
+                return false;
 
             for (jsuint i = 0; i < length; i++) {
                 jsid index;
                 if (!js_IndexToId(cx, i, &index))
-                    return JS_FALSE;
+                    return false;
 
-                if (!Walk(cx, index, obj, reviver, &propValue))
-                    return JS_FALSE;
+                if (!Walk(cx, index, obj, reviver, propValue.addr()))
+                    return false;
 
-                if (!obj->defineProperty(cx, index, propValue, NULL, NULL, JSPROP_ENUMERATE))
-                    return JS_FALSE;
+                if (!obj->defineProperty(cx, index, propValue.value(), NULL, NULL, JSPROP_ENUMERATE))
+                    return false;
             }
         } else {
-            JSIdArray *ida = JS_Enumerate(cx, obj);
+            AutoIdArray ida(cx, JS_Enumerate(cx, obj));
             if (!ida)
-                return JS_FALSE;
-
-            JSAutoTempValueRooter idaroot(cx, JS_ARRAY_LENGTH(ida), (jsval*)ida);
+                return false;
 
-            for(jsint i = 0; i < ida->length; i++) {
-                jsid idName = ida->vector[i];
-                if (!Walk(cx, idName, obj, reviver, &propValue))
-                    return DestroyIdArrayOnError(cx, ida);
-                if (propValue == JSVAL_VOID) {
-                    if (!js_DeleteProperty(cx, obj, idName, &propValue))
-                        return DestroyIdArrayOnError(cx, ida);
+            for (jsint i = 0, len = ida.length(); i < len; i++) {
+                jsid idName = ida[i];
+                if (!Walk(cx, idName, obj, reviver, propValue.addr()))
+                    return false;
+                if (propValue.value() == JSVAL_VOID) {
+                    if (!js_DeleteProperty(cx, obj, idName, propValue.addr()))
+                        return false;
                 } else {
-                    if (!obj->defineProperty(cx, idName, propValue, NULL, NULL, JSPROP_ENUMERATE))
-                        return DestroyIdArrayOnError(cx, ida);
+                    if (!obj->defineProperty(cx, idName, propValue.value(), NULL, NULL,
+                                             JSPROP_ENUMERATE)) {
+                        return false;
+                    }
                 }
             }
-
-            JS_DestroyIdArray(cx, ida);
         }
     }
 
     // return reviver.call(holder, key, value);
     jsval value = *vp;
     JSString *key = js_ValueToString(cx, ID_TO_VALUE(id));
     if (!key)
-        return JS_FALSE;
+        return false;
 
     jsval vec[2] = {STRING_TO_JSVAL(key), value};
     jsval reviverResult;
     if (!JS_CallFunctionValue(cx, holder, reviver, 2, vec, &reviverResult))
-        return JS_FALSE;
+        return false;
 
     *vp = reviverResult;
-
-    return JS_TRUE;
+    return true;
 }
 
-static JSBool
+static bool
 Revive(JSContext *cx, jsval reviver, jsval *vp)
 {
 
     JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
     if (!obj)
-        return JS_FALSE;
+        return false;
 
-    jsval v = OBJECT_TO_JSVAL(obj);
-    JSAutoTempValueRooter tvr(cx, 1, &v);
+    AutoValueRooter tvr(cx, obj);
     if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom),
                              *vp, NULL, NULL, JSPROP_ENUMERATE)) {
-        return JS_FALSE;
+        return false;
     }
 
     return Walk(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), obj, reviver, vp);
 }
 
 JSONParser *
 js_BeginJSONParse(JSContext *cx, jsval *rootVal)
 {
@@ -688,21 +675,21 @@ js_BeginJSONParse(JSContext *cx, jsval *
 
     return jp;
 
 bad:
     js_FinishJSONParse(cx, jp, JSVAL_NULL);
     return NULL;
 }
 
-JSBool
+bool
 js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
 {
     if (!jp)
-        return JS_TRUE;
+        return true;
 
     JSBool early_ok = JS_TRUE;
 
     // Check for unprocessed primitives at the root. This doesn't happen for
     // strings because a closing quote triggers value processing.
     if ((jp->statep - jp->stateStack) == 1) {
         if (*jp->statep == JSON_PARSE_STATE_KEYWORD) {
             early_ok = HandleData(cx, jp, JSON_DATA_KEYWORD);
@@ -713,30 +700,30 @@ js_FinishJSONParse(JSContext *cx, JSONPa
             if (early_ok)
                 PopState(cx, jp);
         }
     }
 
     /* This internal API is infallible, in spite of its JSBool return type. */
     js_RemoveRoot(cx->runtime, &jp->objectStack);
 
-    JSBool ok = *jp->statep == JSON_PARSE_STATE_FINISHED;
+    bool ok = *jp->statep == JSON_PARSE_STATE_FINISHED;
     jsval *vp = jp->rootVal;
 
     cx->destroy(jp);
 
     if (!early_ok)
-        return JS_FALSE;
+        return false;
 
     if (!ok) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE);
-        return JS_FALSE;
+        return false;
     }
 
-    if (!JSVAL_IS_PRIMITIVE(reviver) && js_IsCallable(reviver))
+    if (!JSVAL_IS_PRIMITIVE(reviver) && JSVAL_TO_OBJECT(reviver)->isCallable())
         ok = Revive(cx, reviver, vp);
 
     return ok;
 }
 
 static JSBool
 PushState(JSContext *cx, JSONParser *jp, JSONParserState state)
 {
@@ -804,17 +791,17 @@ PushObject(JSContext *cx, JSONParser *jp
     if (!js_GetLengthProperty(cx, jp->objectStack, &len))
         return JS_FALSE;
     if (len >= JSON_MAX_DEPTH) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE);
         return JS_FALSE;
     }
 
     jsval v = OBJECT_TO_JSVAL(obj);
-    JSAutoTempValueRooter tvr(cx, v);
+    AutoValueRooter tvr(cx, v);
 
     // Check if this is the root object
     if (len == 0) {
         *jp->rootVal = v;
         // This property must be enumerable to keep the array dense
         if (!jp->objectStack->defineProperty(cx, INT_TO_JSID(0), *jp->rootVal,
                                              NULL, NULL, JSPROP_ENUMERATE)) {
             return JS_FALSE;
@@ -877,17 +864,17 @@ static JSBool
 CloseArray(JSContext *cx, JSONParser *jp)
 {
     return CloseObject(cx, jp);
 }
 
 static JSBool
 PushPrimitive(JSContext *cx, JSONParser *jp, jsval value)
 {
-    JSAutoTempValueRooter tvr(cx, 1, &value);
+    AutoValueRooter tvr(cx, value);
 
     jsuint len;
     if (!js_GetLengthProperty(cx, jp->objectStack, &len))
         return JS_FALSE;
 
     if (len > 0) {
         jsval o;
         if (!jp->objectStack->getProperty(cx, INT_TO_JSID(len - 1), &o))
--- a/js/src/json.h
+++ b/js/src/json.h
@@ -84,14 +84,14 @@ enum JSONDataType {
 struct JSONParser;
 
 extern JSONParser *
 js_BeginJSONParse(JSContext *cx, jsval *rootVal);
 
 extern JSBool
 js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len);
 
-extern JSBool
+extern bool
 js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver);
 
 JS_END_EXTERN_C
 
 #endif /* json_h___ */
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -74,16 +74,18 @@
 #include "jsstaticcheck.h"
 #include "jstracer.h"
 #include "jsvector.h"
 
 #include "jsscriptinlines.h"
 
 #include "jsautooplen.h"
 
+using namespace js;
+
 /*
  * Index limit must stay within 32 bits.
  */
 JS_STATIC_ASSERT(sizeof(uint32) * JS_BITS_PER_BYTE >= INDEX_LIMIT_LOG2 + 1);
 
 /* Verify JSOP_XXX_LENGTH constant definitions. */
 #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)               \
     JS_STATIC_ASSERT(op##_LENGTH == length);
@@ -302,17 +304,17 @@ ToDisassemblySource(JSContext *cx, jsval
             JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
             JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
             if (!str)
                 return NULL;
             return js_GetStringBytes(cx, str);
         }
 
         if (clasp == &js_RegExpClass) {
-            JSAutoTempValueRooter tvr(cx);
+            AutoValueRooter tvr(cx);
             if (!js_regexp_toString(cx, obj, tvr.addr()))
                 return NULL;
             return js_GetStringBytes(cx, JSVAL_TO_STRING(tvr.value()));
         }
     }
 
     return js_ValueToPrintableSource(cx, v);
 }
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -83,16 +83,18 @@
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
 #if JS_HAS_DESTRUCTURING
 #include "jsdhash.h"
 #endif
 
+using namespace js;
+
 /*
  * Asserts to verify assumptions behind pn_ macros.
  */
 #define pn_offsetof(m)  offsetof(JSParseNode, m)
 
 JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses));
 JS_STATIC_ASSERT(pn_offsetof(pn_u.name.atom) == pn_offsetof(pn_u.apair.atom));
 
@@ -217,28 +219,25 @@ JSCompiler::init(const jschar *base, siz
     tempPoolMark = JS_ARENA_MARK(&cx->tempPool);
     if (!tokenStream.init(cx, base, length, fp, filename, lineno)) {
         JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
         return false;
     }
 
     /* Root atoms and objects allocated for the parsed tree. */
     JS_KEEP_ATOMS(cx->runtime);
-    JS_PUSH_TEMP_ROOT_COMPILER(cx, this, &tempRoot);
     return true;
 }
 
 JSCompiler::~JSCompiler()
 {
     JSContext *cx = context;
 
     if (principals)
         JSPRINCIPALS_DROP(cx, principals);
-    JS_ASSERT(tempRoot.u.compiler == this);
-    JS_POP_TEMP_ROOT(cx, &tempRoot);
     JS_UNKEEP_ATOMS(cx->runtime);
     tokenStream.close(cx);
     JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
 }
 
 void
 JSCompiler::setPrincipals(JSPrincipals *prin)
 {
@@ -333,20 +332,17 @@ JSFunctionBox::shouldUnbrand(uintN metho
         }
     }
     return false;
 }
 
 void
 JSCompiler::trace(JSTracer *trc)
 {
-    JSObjectBox *objbox;
-
-    JS_ASSERT(tempRoot.u.compiler == this);
-    objbox = traceListHead;
+    JSObjectBox *objbox = traceListHead;
     while (objbox) {
         JS_CALL_OBJECT_TRACER(trc, objbox->object, "parser.object");
         objbox = objbox->traceLink;
     }
 }
 
 static void
 UnlinkFunctionBoxes(JSParseNode *pn, JSTreeContext *tc);
@@ -8825,17 +8821,16 @@ FoldBinaryNumeric(JSContext *cx, JSOp op
 
 static JSBool
 FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
 {
     JSTokenType tt;
     JSParseNode **pnp, *pn1, *pn2;
     JSString *accum, *str;
     uint32 i, j;
-    JSTempValueRooter tvr;
 
     JS_ASSERT(pn->pn_arity == PN_LIST);
     tt = PN_TYPE(pn);
     pnp = &pn->pn_head;
     pn1 = *pnp;
     accum = NULL;
     if ((pn->pn_xflags & PNX_CANTFOLD) == 0) {
         if (tt == TOK_XMLETAGO)
@@ -8916,21 +8911,22 @@ FoldXMLConstants(JSContext *cx, JSParseN
             }
             pnp = &pn2->pn_next;
             pn1 = *pnp;
             accum = NULL;
             continue;
         }
 
         if (accum) {
-            JS_PUSH_TEMP_ROOT_STRING(cx, accum, &tvr);
-            str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0)
-                  ? js_AddAttributePart(cx, i & 1, accum, str)
-                  : js_ConcatStrings(cx, accum, str);
-            JS_POP_TEMP_ROOT(cx, &tvr);
+            {
+                AutoValueRooter tvr(cx, accum);
+                str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0)
+                      ? js_AddAttributePart(cx, i & 1, accum, str)
+                      : js_ConcatStrings(cx, accum, str);
+            }
             if (!str)
                 return JS_FALSE;
 #ifdef DEBUG_brendanXXX
             printf("2: %d, %d => ", i, j);
             js_FileEscapedString(stdout, str, 0);
             printf(" (%u)\n", str->length());
 #endif
             ++j;
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -827,40 +827,45 @@ struct JSFunctionBoxQueue {
         JSFunctionBox *funbox = vector[tail++ & lengthMask];
         funbox->queued = false;
         return funbox;
     }
 };
 
 #define NUM_TEMP_FREELISTS      6U      /* 32 to 2048 byte size classes (32 bit) */
 
-struct JSCompiler {
-    JSContext           *context;
+class JSTreeContext;
+
+struct JSCompiler : private js::AutoGCRooter {
+    JSContext           * const context; /* FIXME Bug 551291: use AutoGCRooter::context? */
     JSAtomListElement   *aleFreeList;
     void                *tempFreeList[NUM_TEMP_FREELISTS];
     JSTokenStream       tokenStream;
     void                *tempPoolMark;  /* initial JSContext.tempPool mark */
     JSPrincipals        *principals;    /* principals associated with source */
     JSStackFrame        *callerFrame;   /* scripted caller frame for eval and dbgapi */
     JSParseNode         *nodeList;      /* list of recyclable parse-node structs */
     uint32              functionCount;  /* number of functions in current unit */
     JSObjectBox         *traceListHead; /* list of parsed object for GC tracing */
-    JSTempValueRooter   tempRoot;       /* root to trace traceListHead */
 
     JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL)
-      : context(cx), aleFreeList(NULL), tokenStream(cx), principals(NULL),
+      : js::AutoGCRooter(cx, COMPILER), context(cx),
+        aleFreeList(NULL), tokenStream(cx), principals(NULL),
         callerFrame(cfp), nodeList(NULL), functionCount(0), traceListHead(NULL)
     {
         memset(tempFreeList, 0, sizeof tempFreeList);
         setPrincipals(prin);
         JS_ASSERT_IF(cfp, cfp->script);
     }
 
     ~JSCompiler();
 
+    friend void js::AutoGCRooter::trace(JSTracer *trc);
+    friend class JSTreeContext;
+
     /*
      * Initialize a compiler. Parameters are passed on to init tokenStream.
      * The compiler owns the arena pool "tops-of-stack" space above the current
      * JSContext.tempPool mark. This means you cannot allocate from tempPool
      * and save the pointer beyond the next JSCompiler destructor invocation.
      */
     bool init(const jschar *base, size_t length,
               FILE *fp, const char *filename, uintN lineno);
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -276,41 +276,16 @@ typedef struct JSDebugHooks {
     JSObjectHook        objectHook;
     void                *objectHookData;
     JSTrapHandler       throwHook;
     void                *throwHookData;
     JSDebugErrorHook    debugErrorHook;
     void                *debugErrorHookData;
 } JSDebugHooks;
 
-/*
- * Type definitions for temporary GC roots that register with GC local C
- * variables. See jscntxt.h for details.
- */
-typedef void
-(* JSTempValueTrace)(JSTracer *trc, JSTempValueRooter *tvr);
-
-typedef union JSTempValueUnion {
-    jsval               value;
-    JSObject            *object;
-    JSXML               *xml;
-    JSTempValueTrace    trace;
-    JSScopeProperty     *sprop;
-    JSWeakRoots         *weakRoots;
-    JSCompiler          *compiler;
-    JSScript            *script;
-    jsval               *array;
-} JSTempValueUnion;
-
-struct JSTempValueRooter {
-    JSTempValueRooter   *down;
-    ptrdiff_t           count;
-    JSTempValueUnion    u;
-};
-
 /* JSObjectOps function pointer typedefs. */
 
 /*
  * Look for id in obj and its prototype chain, returning false on error or
  * exception, true on success.  On success, return null in *propp if id was
  * not found.  If id was found, return the first object searching from obj
  * along its prototype chain in which id names a direct property in *objp, and
  * return a non-null, opaque property pointer in *propp.
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -5227,36 +5227,35 @@ js_InitRegExpStatics(JSContext *cx)
                      12 * 1024 - 40,  /* FIXME: bug 421435 */
                      sizeof(void *), &cx->scriptStackQuota);
 
     JS_ClearRegExpStatics(cx);
 }
 
 JS_FRIEND_API(void)
 js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
-                             JSTempValueRooter *tvr)
+                             AutoValueRooter *tvr)
 {
     *statics = cx->regExpStatics;
-    JS_PUSH_TEMP_ROOT_STRING(cx, statics->input, tvr);
+    tvr->setString(statics->input);
     /*
      * Prevent JS_ClearRegExpStatics from freeing moreParens, since we've only
      * moved it elsewhere (into statics->moreParens).
      */
     cx->regExpStatics.moreParens = NULL;
     JS_ClearRegExpStatics(cx);
 }
 
 JS_FRIEND_API(void)
 js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
-                        JSTempValueRooter *tvr)
+                        AutoValueRooter *tvr)
 {
     /* Clear/free any new JSRegExpStatics data before clobbering. */
     JS_ClearRegExpStatics(cx);
     cx->regExpStatics = *statics;
-    JS_POP_TEMP_ROOT(cx, tvr);
 }
 
 void
 js_TraceRegExpStatics(JSTracer *trc, JSContext *acx)
 {
     JSRegExpStatics *res = &acx->regExpStatics;
 
     if (res->input)
@@ -5839,17 +5838,17 @@ js_NewRegExpObject(JSContext *cx, JSToke
 {
     JSString *str;
     JSObject *obj;
     JSRegExp *re;
 
     str = js_NewStringCopyN(cx, chars, length);
     if (!str)
         return NULL;
-    JSAutoTempValueRooter tvr(cx, str);
+    AutoValueRooter tvr(cx, str);
     re = js_NewRegExp(cx, ts,  str, flags, JS_FALSE);
     if (!re)
         return NULL;
     obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL);
     if (!obj) {
         js_DestroyRegExp(cx, re);
         return NULL;
     }
--- a/js/src/jsregexp.h
+++ b/js/src/jsregexp.h
@@ -60,23 +60,25 @@ struct JSRegExpStatics {
     JSSubString parens[9];      /* last set of parens matched (perl $1, $2) */
     JSSubString *moreParens;    /* null or realloc'd vector for $10, etc. */
     JSSubString lastMatch;      /* last string matched (perl $&) */
     JSSubString lastParen;      /* last paren matched (perl $+) */
     JSSubString leftContext;    /* input to left of last match (perl $`) */
     JSSubString rightContext;   /* input to right of last match (perl $') */
 };
 
+namespace js { class AutoValueRooter; }
+
 extern JS_FRIEND_API(void)
 js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
-                             JSTempValueRooter *tvr);
+                             js::AutoValueRooter *tvr);
 
 extern JS_FRIEND_API(void)
 js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
-                        JSTempValueRooter *tvr);
+                        js::AutoValueRooter *tvr);
 
 /*
  * This struct holds a bitmap representation of a class from a regexp.
  * There's a list of these referenced by the classList field in the JSRegExp
  * struct below. The initial state has startIndex set to the offset in the
  * original regexp source of the beginning of the class contents. The first
  * use of the class converts the source representation into a bitmap.
  *
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -89,17 +89,16 @@ js_XDRScript(JSXDRState *xdr, JSScript *
 {
     JSContext *cx;
     JSScript *script, *oldscript;
     JSBool ok;
     jsbytecode *code;
     uint32 length, lineno, nslots, magic;
     uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, i;
     uint32 prologLength, version;
-    JSTempValueRooter tvr;
     JSPrincipals *principals;
     uint32 encodeable;
     JSBool filenameWasSaved;
     jssrcnote *notes, *sn;
     JSSecurityCallbacks *callbacks;
 
     cx = xdr->cx;
     script = *scriptp;
@@ -207,30 +206,32 @@ js_XDRScript(JSXDRState *xdr, JSScript *
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &nobjects))
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &nupvars))
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &nregexps))
         return JS_FALSE;
 
+    AutoScriptRooter tvr(cx, NULL);
+
     if (xdr->mode == JSXDR_DECODE) {
         script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars,
                               nregexps, ntrynotes);
         if (!script)
             return JS_FALSE;
 
         script->main += prologLength;
         script->version = JSVersion(version & 0xffff);
         script->nfixed = uint16(version >> 16);
 
         /* If we know nsrcnotes, we allocated space for notes in script. */
         notes = script->notes();
         *scriptp = script;
-        JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr);
+        tvr.setScript(script);
     }
 
     /*
      * Control hereafter must goto error on failure, in order for the
      * DECODE case to destroy script.
      */
     oldscript = xdr->script;
     code = script->code;
@@ -363,23 +364,20 @@ js_XDRScript(JSXDRState *xdr, JSScript *
             if (xdr->mode == JSXDR_DECODE) {
                 tn->kind = (uint8)(kindAndDepth >> 16);
                 tn->stackDepth = (uint16)kindAndDepth;
             }
         } while (tn != tnfirst);
     }
 
     xdr->script = oldscript;
-    if (xdr->mode == JSXDR_DECODE)
-        JS_POP_TEMP_ROOT(cx, &tvr);
     return JS_TRUE;
 
   error:
     if (xdr->mode == JSXDR_DECODE) {
-        JS_POP_TEMP_ROOT(cx, &tvr);
         if (script->filename && !filenameWasSaved) {
             cx->free((void *) script->filename);
             script->filename = NULL;
         }
         js_DestroyScript(cx, script);
         *scriptp = NULL;
     }
     xdr->script = oldscript;
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1598,17 +1598,17 @@ str_match(JSContext *cx, uintN argc, jsv
     RegExpGuard g(cx);
     if (!g.init(argc, vp))
         return false;
     if (g.tryFlatMatch(str, false, 1, argc))
         return BuildFlatMatchArray(cx, str, g, vp);
     if (!g.normalizeRegExp(false, 1, argc, vp))
         return false;
 
-    JSAutoTempValueRooter array(cx, JSVAL_NULL);
+    AutoValueRooter array(cx, JSVAL_NULL);
     if (!DoMatch(cx, vp, str, g, MatchCallback, array.addr(), MATCH_ARGS))
         return false;
 
     /* When not global, DoMatch will leave |RegEx.exec()| in *vp. */
     if (g.re()->flags & JSREG_GLOB)
         *vp = array.value();
     return true;
 }
@@ -3379,17 +3379,17 @@ js_ValueToSource(JSContext *cx, jsval v)
             static const jschar js_negzero_ucNstr[] = {'-', '0'};
 
             return js_NewStringCopyN(cx, js_negzero_ucNstr, 2);
         }
         return js_ValueToString(cx, v);
     }
 
     JSAtom *atom = cx->runtime->atomState.toSourceAtom;
-    JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
+    AutoValueRooter tvr(cx, JSVAL_NULL);
     if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v), atom, 0, NULL, tvr.addr()))
         return NULL;
     return js_ValueToString(cx, tvr.value());
 }
 
 /*
  * str is not necessarily a GC thing here.
  */
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -8809,23 +8809,22 @@ TraceRecorder::relational(LOpcode op, bo
           case JSVAL_DOUBLE:
           default:
             JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should "
                            "have been handled at start of method");
             RETURN_STOP_A("safety belt");
         }
     }
     {
-        jsval tmp = JSVAL_NULL;
-        JSAutoTempValueRooter tvr(cx, 1, &tmp);
-
-        tmp = l;
-        lnum = js_ValueToNumber(cx, &tmp);
-        tmp = r;
-        rnum = js_ValueToNumber(cx, &tmp);
+        AutoValueRooter tvr(cx);
+
+        *tvr.addr() = l;
+        lnum = js_ValueToNumber(cx, tvr.addr());
+        *tvr.addr() = r;
+        rnum = js_ValueToNumber(cx, tvr.addr());
     }
     cond = EvalCmp(op, lnum, rnum);
     fp = true;
 
     /* 11.8.5 steps 6-15. */
   do_comparison:
     /*
      * If the result is not a number or it's not a quad, we must use an integer
@@ -11205,17 +11204,17 @@ TraceRecorder::nativeSet(JSObject* obj, 
     }
 
     return RECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 MethodWriteBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj)
 {
-    JSAutoTempValueRooter tvr(cx, funobj);
+    AutoValueRooter tvr(cx, funobj);
 
     return OBJ_SCOPE(obj)->methodWriteBarrier(cx, sprop, tvr.value());
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, MethodWriteBarrier, CONTEXT, OBJECT, SCOPEPROP, OBJECT,
                      0, ACC_STORE_ANY)
 
 JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop,
@@ -11569,17 +11568,17 @@ TraceRecorder::getPropertyByName(LIns* o
     return RECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp)
 {
     LeaveTraceIfGlobalObject(cx, obj);
 
-    JSAutoTempIdRooter idr(cx);
+    AutoIdRooter idr(cx);
     if (!js_Int32ToId(cx, index, idr.addr()) || !obj->getProperty(cx, idr.id(), vp)) {
         SetBuiltinError(cx);
         return JS_FALSE;
     }
     return cx->interpState->builtinStatus == 0;
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyByIndex, CONTEXT, OBJECT, INT32, JSVALPTR, 0,
                      ACC_STORE_ANY)
@@ -11908,32 +11907,32 @@ TraceRecorder::initOrSetPropertyByName(L
     return RECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp)
 {
     LeaveTraceIfGlobalObject(cx, obj);
 
-    JSAutoTempIdRooter idr(cx);
+    AutoIdRooter idr(cx);
     if (!js_Int32ToId(cx, index, idr.addr()) || !obj->setProperty(cx, idr.id(), vp)) {
         SetBuiltinError(cx);
         return JS_FALSE;
     }
     return cx->interpState->builtinStatus == 0;
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, SetPropertyByIndex, CONTEXT, OBJECT, INT32, JSVALPTR, 0,
                      ACC_STORE_ANY)
 
 static JSBool FASTCALL
 InitPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval val)
 {
     LeaveTraceIfGlobalObject(cx, obj);
 
-    JSAutoTempIdRooter idr(cx);
+    AutoIdRooter idr(cx);
     if (!js_Int32ToId(cx, index, idr.addr()) ||
         !obj->defineProperty(cx, idr.id(), val, NULL, NULL, JSPROP_ENUMERATE)) {
         SetBuiltinError(cx);
         return JS_FALSE;
     }
     return cx->interpState->builtinStatus == 0;
 }
 JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByIndex, CONTEXT, OBJECT, INT32, JSVAL, 0,
@@ -12742,17 +12741,17 @@ TraceRecorder::name(jsval*& vp, LIns*& i
     ins = get(vp);
     nr.tracked = true;
     return ARECORD_CONTINUE;
 }
 
 static JSObject* FASTCALL
 MethodReadBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj)
 {
-    JSAutoTempValueRooter tvr(cx, funobj);
+    AutoValueRooter tvr(cx, funobj);
 
     if (!OBJ_SCOPE(obj)->methodReadBarrier(cx, sprop, tvr.addr()))
         return NULL;
     JS_ASSERT(VALUE_IS_FUNCTION(cx, tvr.value()));
     return JSVAL_TO_OBJECT(tvr.value());
 }
 JS_DEFINE_CALLINFO_4(static, OBJECT_FAIL, MethodReadBarrier, CONTEXT, OBJECT, SCOPEPROP, OBJECT,
                      0, ACC_STORE_ANY)
@@ -14863,17 +14862,17 @@ static JSBool
 CallIteratorNext(JSContext *cx, uintN argc, jsval *vp)
 {
     return js_CallIteratorNext(cx, JS_THIS_OBJECT(cx, vp), &JS_RVAL(cx, vp));
 }
 
 static jsval FASTCALL
 CallIteratorNext_tn(JSContext* cx, jsbytecode* pc, JSObject* iterobj)
 {
-    JSAutoTempValueRooter tvr(cx);
+    AutoValueRooter tvr(cx);
     JSBool ok = js_CallIteratorNext(cx, iterobj, tvr.addr());
 
     if (!ok) {
         SetBuiltinError(cx);
         return JSVAL_ERROR_COOKIE;
     }
     return tvr.value();
 }
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -1315,20 +1315,20 @@ js_IsTypedArray(JSObject *obj)
     return obj &&
            obj->getClass() >= &TypedArray::fastClasses[0] &&
            obj->getClass() <  &TypedArray::fastClasses[TypedArray::TYPE_MAX];
 }
 
 JS_FRIEND_API(JSObject *)
 js_CreateArrayBuffer(JSContext *cx, jsuint nbytes)
 {
-    JSAutoTempValueRooter tvr(cx);
+    AutoValueRooter tvr(cx);
     js_NewNumberInRootedValue(cx, jsdouble(nbytes), tvr.addr());
 
-    JSAutoTempValueRooter rval(cx);
+    AutoValueRooter rval(cx);
     if (!ArrayBuffer::class_constructor(cx, cx->globalObject,
                                         1, tvr.addr(), 
                                         rval.addr()))
         return NULL;
 
     return JSVAL_TO_OBJECT(rval.value());
 }
 
@@ -1370,34 +1370,34 @@ TypedArrayConstruct(JSContext *cx, jsint
 }
 
 JS_FRIEND_API(JSObject *)
 js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements)
 {
     JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
 
     jsval vals[2];
-    JSAutoTempValueRooter tvr(cx, 2, vals);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
 
     if (!js_NewNumberInRootedValue(cx, jsdouble(nelements), &vals[0]))
         return NULL;
 
     if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1]))
         return NULL;
 
     return JSVAL_TO_OBJECT(vals[1]);
 }
 
 JS_FRIEND_API(JSObject *)
 js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg)
 {
     JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
 
     jsval vals[2];
-    JSAutoTempValueRooter tvr(cx, 2, vals);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
 
     vals[0] = OBJECT_TO_JSVAL(arrayArg);
 
     if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1]))
         return NULL;
 
     return JSVAL_TO_OBJECT(vals[1]);
 }
@@ -1407,17 +1407,17 @@ js_CreateTypedArrayWithBuffer(JSContext 
                               jsint byteoffset, jsint length)
 {
     JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
     JS_ASSERT(bufArg && ArrayBuffer::fromJSObject(bufArg));
     /* if byteoffset is -1, length must be -1 */
     JS_ASSERT(length < 0 || byteoffset >= 0);
 
     jsval vals[4];
-    JSAutoTempValueRooter tvr(cx, 4, vals);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
 
     int argc = 1;
     vals[0] = OBJECT_TO_JSVAL(bufArg);
 
     if (byteoffset >= 0) {
         js_NewNumberInRootedValue(cx, jsdouble(byteoffset), &vals[1]);
         argc++;
     }
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -206,19 +206,19 @@ JS_END_EXTERN_C
 #ifdef __cplusplus
 
 /**
  * The following classes are designed to cause assertions to detect
  * inadvertent use of guard objects as temporaries.  In other words,
  * when we have a guard object whose only purpose is its constructor and
  * destructor (and is never otherwise referenced), the intended use
  * might be:
- *     JSAutoTempValueRooter tvr(cx, 1, &val);
+ *     js::AutoValueRooter tvr(cx, 1, &val);
  * but is is easy to accidentally write:
- *     JSAutoTempValueRooter(cx, 1, &val);
+ *     js::AutoValueRooter(cx, 1, &val);
  * which compiles just fine, but runs the destructor well before the
  * intended time.
  *
  * They work by adding (#ifdef DEBUG) an additional parameter to the
  * guard object's constructor, with a default value, so that users of
  * the guard object's API do not need to do anything.  The default value
  * of this parameter is a temporary object.  C++ (ISO/IEC 14882:1998),
  * section 12.2 [class.temporary], clauses 4 and 5 seem to assume a
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -354,17 +354,20 @@ class Vector : AllocPolicy
 
     const T &back() const {
         JS_ASSERT(!entered && !empty());
         return *(end() - 1);
     }
 
     /* mutators */
 
-    /* If reserve(N) succeeds, the N next appends are guaranteed to succeed. */
+    /*
+     * If reserve(N) succeeds, additions to this vector which increase its size
+     * up to and including N are guaranteed to succeed.
+     */
     bool reserve(size_t capacity);
 
     /* Destroy elements in the range [begin() + incr, end()). */
     void shrinkBy(size_t incr);
 
     /*
      * Grow the vector by incr elements.  If T is a POD (as judged by
      * tl::IsPodType), leave as uninitialized memory.  Otherwise, default
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -65,20 +65,24 @@
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsxml.h"
 #include "jsstaticcheck.h"
 #include "jsvector.h"
 
+#include "jscntxtinlines.h"
+
 #ifdef DEBUG
 #include <string.h>     /* for #ifdef DEBUG memset calls */
 #endif
 
+using namespace js;
+
 /*
  * NOTES
  * - in the js shell, you must use the -x command line option, or call
  *   options('xml') before compiling anything that uses XML literals
  *
  * TODO
  * - XXXbe patrol
  * - Fuse objects and their JSXML* private data into single GC-things
@@ -861,70 +865,20 @@ static JSBool
 attr_identity(const void *a, const void *b)
 {
     const JSXML *xmla = (const JSXML *) a;
     const JSXML *xmlb = (const JSXML *) b;
 
     return qname_identity(xmla->name, xmlb->name);
 }
 
-struct JSXMLArrayCursor
-{
-    JSXMLArray       *array;
-    uint32           index;
-    JSXMLArrayCursor *next;
-    JSXMLArrayCursor **prevp;
-    void             *root;
-
-    JSXMLArrayCursor(JSXMLArray *array)
-      : array(array), index(0), next(array->cursors), prevp(&array->cursors),
-        root(NULL)
-    {
-        if (next)
-            next->prevp = &next;
-        array->cursors = this;
-    }
-
-    ~JSXMLArrayCursor() { disconnect(); }
-
-    void disconnect() {
-        if (!array)
-            return;
-        if (next)
-            next->prevp = prevp;
-        *prevp = next;
-        array = NULL;
-    }
-
-    void *getNext() {
-        if (!array || index >= array->length)
-            return NULL;
-        return root = array->vector[index++];
-    }
-
-    void *getCurrent() {
-        if (!array || index >= array->length)
-            return NULL;
-        return root = array->vector[index];
-    }
-};
-
 static void
 XMLArrayCursorTrace(JSTracer *trc, JSXMLArrayCursor *cursor)
 {
-    void *root;
-#ifdef DEBUG
-    size_t index = 0;
-#endif
-
-    for (; cursor; cursor = cursor->next) {
-        root = cursor->root;
-        JS_SET_TRACING_INDEX(trc, "cursor_root", index++);
-        js_CallValueTracerIfGCThing(trc, (jsval)root);
-    }
+    cursor->trace(trc);
 }
 
 /* NB: called with null cx from the GC, via xml_trace => XMLArrayTrim. */
 static JSBool
 XMLArraySetCapacity(JSContext *cx, JSXMLArray *array, uint32 capacity)
 {
     void **vector;
 
@@ -3843,88 +3797,83 @@ GetNamedProperty(JSContext *cx, JSXML *x
 static JSBool
 GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
     JSXML *xml, *list, *kid;
     uint32 index;
     JSObject *kidobj, *listobj;
     JSObject *nameqn;
     jsid funid;
-    jsval roots[2];
-    JSTempValueRooter tvr;
 
     xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
     if (!xml)
-        return JS_TRUE;
+        return true;
 
     if (js_IdIsIndex(id, &index)) {
         if (xml->xml_class != JSXML_CLASS_LIST) {
             *vp = (index == 0) ? OBJECT_TO_JSVAL(obj) : JSVAL_VOID;
         } else {
             /*
              * ECMA-357 9.2.1.1 starts here.
              *
              * Erratum: 9.2 is not completely clear that indexed properties
              * correspond to kids, but that's what it seems to say, and it's
              * what any sane user would want.
              */
             if (index < xml->xml_kids.length) {
                 kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML);
                 if (!kid) {
                     *vp = JSVAL_VOID;
-                    return JS_TRUE;
+                    return true;
                 }
                 kidobj = js_GetXMLObject(cx, kid);
                 if (!kidobj)
-                    return JS_FALSE;
+                    return false;
 
                 *vp = OBJECT_TO_JSVAL(kidobj);
             } else {
                 *vp = JSVAL_VOID;
             }
         }
-        return JS_TRUE;
+        return true;
     }
 
     /*
      * ECMA-357 9.2.1.1/9.1.1.1 qname case.
      */
     nameqn = ToXMLName(cx, id, &funid);
     if (!nameqn)
-        return JS_FALSE;
+        return false;
     if (funid)
         return GetXMLFunction(cx, obj, funid, vp);
 
-    roots[0] = OBJECT_TO_JSVAL(nameqn);
-    JS_PUSH_TEMP_ROOT(cx, 1, roots, &tvr);
+    jsval roots[2] = { OBJECT_TO_JSVAL(nameqn), JSVAL_NULL };
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
 
     listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
-    if (listobj) {
-        roots[1] = OBJECT_TO_JSVAL(listobj);
-        tvr.count++;
-
-        list = (JSXML *) listobj->getPrivate();
-        if (!GetNamedProperty(cx, xml, nameqn, list)) {
-            listobj = NULL;
-        } else {
-            /*
-             * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the
-             * given list's [[TargetProperty]] to the property that is being
-             * appended. This means that any use of the internal [[Get]]
-             * property returns a list which, when used by e.g. [[Insert]]
-             * duplicates the last element matched by id. See bug 336921.
-             */
-            list->xml_target = xml;
-            list->xml_targetprop = nameqn;
-            *vp = OBJECT_TO_JSVAL(listobj);
-        }
-    }
-
-    JS_POP_TEMP_ROOT(cx, &tvr);
-    return listobj != NULL;
+    if (!listobj)
+        return false;
+
+    roots[1] = OBJECT_TO_JSVAL(listobj);
+
+    list = (JSXML *) listobj->getPrivate();
+    if (!GetNamedProperty(cx, xml, nameqn, list))
+        return false;
+
+    /*
+     * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the
+     * given list's [[TargetProperty]] to the property that is being
+     * appended. This means that any use of the internal [[Get]]
+     * property returns a list which, when used by e.g. [[Insert]]
+     * duplicates the last element matched by id. See bug 336921.
+     */
+    list->xml_target = xml;
+    list->xml_targetprop = nameqn;
+    *vp = OBJECT_TO_JSVAL(listobj);
+    return true;
 }
 
 static JSXML *
 CopyOnWrite(JSContext *cx, JSXML *xml, JSObject *obj)
 {
     JS_ASSERT(xml->object != obj);
 
     xml = DeepCopy(cx, xml, obj, 0);
@@ -3958,18 +3907,16 @@ static JSBool
 ResolveValue(JSContext *cx, JSXML *list, JSXML **result);
 
 /* ECMA-357 9.1.1.2 XML [[Put]] and 9.2.1.2 XMLList [[Put]]. */
 static JSBool
 PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
     JSBool ok, primitiveAssign;
     enum { OBJ_ROOT, ID_ROOT, VAL_ROOT };
-    jsval roots[3];
-    JSTempValueRooter tvr;
     JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match;
     JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj;
     JSObject *targetprop, *nameqn, *attrqn;
     uint32 index, i, j, k, n, q, matchIndex;
     jsval attrval, nsval;
     jsid funid;
     JSString *left, *right, *space, *uri;
     JSObject *ns;
@@ -3988,21 +3935,23 @@ PutProperty(JSContext *cx, JSObject *obj
         vobj = JSVAL_TO_OBJECT(*vp);
         if (OBJECT_IS_XML(cx, vobj))
             vxml = (JSXML *) vobj->getPrivate();
     }
 
     ok = js_EnterLocalRootScope(cx);
     if (!ok)
         return JS_FALSE;
+
     MUST_FLOW_THROUGH("out");
+    jsval roots[3];
     roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj);
     roots[ID_ROOT] = id;
     roots[VAL_ROOT] = *vp;
-    JS_PUSH_TEMP_ROOT(cx, 3, roots, &tvr);
+    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
 
     if (js_IdIsIndex(id, &index)) {
         if (xml->xml_class != JSXML_CLASS_LIST) {
             /* See NOTE in spec: this variation is reserved for future use. */
             ReportBadXMLName(cx, id);
             goto bad;
         }
 
@@ -4579,17 +4528,16 @@ PutProperty(JSContext *cx, JSObject *obj
             }
         } else {
             /* 15(a). */
             ok = Replace(cx, xml, matchIndex, *vp);
         }
     }
 
 out:
-    JS_POP_TEMP_ROOT(cx, &tvr);
     js_LeaveLocalRootScope(cx);
     return ok;
 
 type_error:
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_BAD_XMLLIST_PUT,
                          js_ValueToPrintableString(cx, id));
 bad:
@@ -4711,48 +4659,44 @@ static JSBool
 HasSimpleContent(JSXML *xml);
 
 static JSBool
 HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found)
 {
     JSObject *pobj;
     JSProperty *prop;
     JSXML *xml;
-    JSTempValueRooter tvr;
-    JSBool ok;
 
     JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_XMLClass);
 
     if (!js_LookupProperty(cx, obj, funid, &pobj, &prop))
-        return JS_FALSE;
+        return false;
     if (prop) {
         pobj->dropProperty(cx, prop);
     } else {
         xml = (JSXML *) obj->getPrivate();
         if (HasSimpleContent(xml)) {
+            AutoObjectRooter tvr(cx);
+
             /*
              * Search in String.prototype to set found whenever
              * GetXMLFunction returns existing function.
              */
-            JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr);
-            ok = js_GetClassPrototype(cx, NULL, JSProto_String,
-                                      &tvr.u.object);
-            JS_ASSERT(tvr.u.object);
-            if (ok) {
-                ok = js_LookupProperty(cx, tvr.u.object, funid, &pobj, &prop);
-                if (ok && prop)
-                    pobj->dropProperty(cx, prop);
-            }
-            JS_POP_TEMP_ROOT(cx, &tvr);
-            if (!ok)
-                return JS_FALSE;
+            if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr()))
+                return false;
+
+            JS_ASSERT(tvr.object());
+            if (!js_LookupProperty(cx, tvr.object(), funid, &pobj, &prop))
+                return false;
+            if (prop)
+                pobj->dropProperty(cx, prop);
         }
     }
     *found = (prop != NULL);
-    return JS_TRUE;
+    return true;
 }
 
 /* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */
 static JSBool
 HasProperty(JSContext *cx, JSObject *obj, jsval id, JSBool *found)
 {
     JSXML *xml;
     uint32 i;
@@ -5009,40 +4953,46 @@ xml_enumerate(JSContext *cx, JSObject *o
     JSXMLArrayCursor *cursor;
 
     xml = (JSXML *)obj->getPrivate();
     length = JSXML_LENGTH(xml);
 
     switch (enum_op) {
       case JSENUMERATE_INIT:
         if (length == 0) {
-            cursor = NULL;
+            *statep = JSVAL_ZERO;
         } else {
             cursor = cx->create<JSXMLArrayCursor>(&xml->xml_kids);
             if (!cursor)
                 return JS_FALSE;
-        }
-        *statep = PRIVATE_TO_JSVAL(cursor);
+            *statep = PRIVATE_TO_JSVAL(cursor);
+        }
         if (idp)
             *idp = INT_TO_JSID(length);
         break;
 
       case JSENUMERATE_NEXT:
+        if (*statep == JSVAL_ZERO) {
+            *statep = JSVAL_NULL;
+            break;
+        }
         cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep);
         if (cursor && cursor->array && (index = cursor->index) < length) {
             *idp = INT_TO_JSID(index);
             cursor->index = index + 1;
             break;
         }
         /* FALL THROUGH */
 
       case JSENUMERATE_DESTROY:
-        cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep);
-        if (cursor)
-            cx->destroy(cursor);
+        if (*statep != JSVAL_ZERO) {
+            cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep);
+            if (cursor)
+                cx->destroy(cursor);
+        }
         *statep = JSVAL_NULL;
         break;
     }
     return JS_TRUE;
 }
 
 static JSType
 xml_typeOf(JSContext *cx, JSObject *obj)
@@ -5121,17 +5071,17 @@ js_GetXMLMethod(JSContext *cx, JSObject 
         if (funid != 0)
             id = funid;
     }
 
     /*
      * As our callers have a bad habit of passing a pointer to an unrooted
      * local value as vp, we use a proper root here.
      */
-    JSAutoTempValueRooter tvr(cx);
+    AutoValueRooter tvr(cx);
     JSBool ok = GetXMLFunction(cx, obj, id, tvr.addr());
     *vp = tvr.value();
     return ok;
 }
 
 JSBool
 js_EnumerateXMLValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                       jsval *statep, jsid *idp, jsval *vp)
@@ -5144,30 +5094,32 @@ js_EnumerateXMLValues(JSContext *cx, JSO
     JS_ASSERT(JS_InstanceOf(cx, obj, &js_XMLClass, NULL));
     xml = (JSXML *) obj->getPrivate();
     length = JSXML_LENGTH(xml);
     JS_ASSERT(INT_FITS_IN_JSVAL(length));
 
     switch (enum_op) {
       case JSENUMERATE_INIT:
         if (length == 0) {
-            cursor = NULL;
+            *statep = JSVAL_ZERO;
         } else {
             cursor = cx->create<JSXMLArrayCursor>(&xml->xml_kids);
             if (!cursor)
                 return JS_FALSE;
-        }
-        *statep = PRIVATE_TO_JSVAL(cursor);
-        if (idp)
-            *idp = INT_TO_JSID(length);
-        if (vp)
-            *vp = JSVAL_VOID;
+            *statep = PRIVATE_TO_JSVAL(cursor);
+        }
+        JS_ASSERT(!idp);
+        JS_ASSERT(!vp);
         break;
 
       case JSENUMERATE_NEXT:
+        if (*statep == JSVAL_ZERO) {
+            *statep = JSVAL_NULL;
+            break;
+        }
         cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep);
         if (cursor && cursor->array && (index = cursor->index) < length) {
             while (!(kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML))) {
                 if (++index == length)
                     goto destroy;
             }
             kidobj = js_GetXMLObject(cx, kid);
             if (!kidobj)
@@ -5176,20 +5128,22 @@ js_EnumerateXMLValues(JSContext *cx, JSO
             *idp = INT_TO_JSID(index);
             *vp = OBJECT_TO_JSVAL(kidobj);
             cursor->index = index + 1;
             break;
         }
         /* FALL THROUGH */
 
       case JSENUMERATE_DESTROY:
-        cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep);
-        if (cursor) {
-      destroy:
-            cx->destroy(cursor);
+        if (*statep != JSVAL_ZERO) {
+            cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep);
+            if (cursor) {
+          destroy:
+                cx->destroy(cursor);
+            }
         }
         *statep = JSVAL_NULL;
         break;
     }
     return JS_TRUE;
 }
 
 JSBool
@@ -5472,17 +5426,17 @@ static JSBool
 xml_attributes(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval name = ATOM_KEY(cx->runtime->atomState.starAtom);
     JSObject *qn = ToAttributeName(cx, name);
     if (!qn)
         return JS_FALSE;
     name = OBJECT_TO_JSVAL(qn);
 
-    JSAutoTempValueRooter tvr(cx, name);
+    AutoValueRooter tvr(cx, name);
     return GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp);
 }
 
 static JSXML *
 xml_list_helper(JSContext *cx, JSXML *xml, jsval *rval)
 {
     JSObject *listobj;
     JSXML *list;
@@ -5878,91 +5832,16 @@ again:
 static JSBool
 xml_hasSimpleContent(JSContext *cx, uintN argc, jsval *vp)
 {
     XML_METHOD_PROLOG;
     *vp = BOOLEAN_TO_JSVAL(HasSimpleContent(xml));
     return JS_TRUE;
 }
 
-typedef struct JSTempRootedNSArray {
-    JSTempValueRooter   tvr;
-    JSXMLArray          array;
-    jsval               value;  /* extra root for temporaries */
-} JSTempRootedNSArray;
-
-static void
-TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len)
-{
-    uint32 i;
-    JSObject *obj;
-
-    for (i = 0; i < len; i++) {
-        obj = vec[i];
-        if (obj) {
-            JS_SET_TRACING_INDEX(trc, "vector", i);
-            js_CallGCMarker(trc, obj, JSTRACE_OBJECT);
-        }
-    }
-}
-
-static void
-trace_temp_ns_array(JSTracer *trc, JSTempValueRooter *tvr)
-{
-    JSTempRootedNSArray *tmp = (JSTempRootedNSArray *)tvr;
-
-    TraceObjectVector(trc,
-                      (JSObject **) tmp->array.vector,
-                      tmp->array.length);
-    XMLArrayCursorTrace(trc, tmp->array.cursors);
-    JS_CALL_VALUE_TRACER(trc, tmp->value, "temp_ns_array_value");
-}
-
-static void
-InitTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp)
-{
-    XMLArrayInit(cx, &tmp->array, 0);
-    tmp->value = JSVAL_NULL;
-    JS_PUSH_TEMP_ROOT_TRACE(cx, trace_temp_ns_array, &tmp->tvr);
-}
-
-static void
-FinishTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp)
-{
-    JS_ASSERT(tmp->tvr.u.trace == trace_temp_ns_array);
-    JS_POP_TEMP_ROOT(cx, &tmp->tvr);
-    XMLArrayFinish(cx, &tmp->array);
-}
-
-/*
- * Populate a new JS array with elements of JSTempRootedNSArray.array and
- * place the result into rval.  rval must point to a rooted location.
- */
-static JSBool
-TempNSArrayToJSArray(JSContext *cx, JSTempRootedNSArray *tmp, jsval *rval)
-{
-    JSObject *arrayobj;
-    uint32 i, n;
-    JSObject *ns;
-
-    arrayobj = js_NewArrayObject(cx, 0, NULL);
-    if (!arrayobj)
-        return JS_FALSE;
-    *rval = OBJECT_TO_JSVAL(arrayobj);
-    for (i = 0, n = tmp->array.length; i < n; i++) {
-        ns = XMLARRAY_MEMBER(&tmp->array, i, JSObject);
-        if (!ns)
-            continue;
-        tmp->value = OBJECT_TO_JSVAL(ns);
-        if (!arrayobj->setProperty(cx, INT_TO_JSID(i), &tmp->value))
-            return JS_FALSE;
-    }
-    return JS_TRUE;
-}
-
 static JSBool
 FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray)
 {
     uint32 length, i, j, n;
     JSObject *ns, *ns2;
     JSString *prefix, *prefix2;
 
     length = nsarray->length;
@@ -5994,29 +5873,58 @@ FindInScopeNamespaces(JSContext *cx, JSX
             }
         }
     } while ((xml = xml->parent) != NULL);
     JS_ASSERT(length == nsarray->length);
 
     return JS_TRUE;
 }
 
+class AutoNamespaceArray : public js::AutoNamespaces {
+  public:
+    AutoNamespaceArray(JSContext *cx)
+      : js::AutoNamespaces(cx)
+    {
+        XMLArrayInit(cx, &array, 0);
+    }
+
+    ~AutoNamespaceArray() {
+        XMLArrayFinish(context, &array);
+    }
+
+    /*
+     * Populate a new JS array with elements of array and place the result into
+     * rval.  rval must point to a rooted location.
+     */
+    bool toJSArray(jsval *rval) {
+        JSObject *arrayobj = js_NewArrayObject(context, 0, NULL);
+        if (!arrayobj)
+            return JS_FALSE;
+        *rval = OBJECT_TO_JSVAL(arrayobj);
+
+        AutoValueRooter tvr(context);
+        for (uint32 i = 0, n = array.length; i < n; i++) {
+            JSObject *ns = XMLARRAY_MEMBER(&array, i, JSObject);
+            if (!ns)
+                continue;
+            *tvr.addr() = OBJECT_TO_JSVAL(ns);
+            if (!arrayobj->setProperty(context, INT_TO_JSID(i), tvr.addr()))
+                return JS_FALSE;
+        }
+        return JS_TRUE;
+    }
+};
+
 static JSBool
 xml_inScopeNamespaces(JSContext *cx, uintN argc, jsval *vp)
 {
-    JSTempRootedNSArray namespaces;
-    JSBool ok;
-
     NON_LIST_XML_METHOD_PROLOG;
 
-    InitTempNSArray(cx, &namespaces);
-    ok = FindInScopeNamespaces(cx, xml, &namespaces.array) &&
-         TempNSArrayToJSArray(cx, &namespaces, vp);
-    FinishTempNSArray(cx, &namespaces);
-    return ok;
+    AutoNamespaceArray namespaces(cx);
+    return FindInScopeNamespaces(cx, xml, &namespaces.array) && namespaces.toJSArray(vp);
 }
 
 static JSBool
 xml_insertChildAfter(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval arg;
     JSXML *kid;
     uint32 i;
@@ -6106,120 +6014,94 @@ xml_name(JSContext *cx, uintN argc, jsva
     *vp = OBJECT_TO_JSVAL(xml->name);
     return JS_TRUE;
 }
 
 static JSBool
 xml_namespace(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *prefix, *nsprefix;
-    JSTempRootedNSArray inScopeNSes;
-    JSBool ok;
     jsuint i, length;
     JSObject *ns;
 
     NON_LIST_XML_METHOD_PROLOG;
     if (argc == 0 && !JSXML_HAS_NAME(xml)) {
         *vp = JSVAL_NULL;
-        return JS_TRUE;
+        return true;
     }
 
     if (argc == 0) {
         prefix = NULL;
     } else {
         prefix = js_ValueToString(cx, vp[2]);
         if (!prefix)
-            return JS_FALSE;
+            return false;
         vp[2] = STRING_TO_JSVAL(prefix);      /* local root */
     }
 
-    InitTempNSArray(cx, &inScopeNSes);
-    MUST_FLOW_THROUGH("out");
-    ok = FindInScopeNamespaces(cx, xml, &inScopeNSes.array);
-    if (!ok)
-        goto out;
+    AutoNamespaceArray inScopeNSes(cx);
+    if (!FindInScopeNamespaces(cx, xml, &inScopeNSes.array))
+        return false;
 
     if (!prefix) {
         ns = GetNamespace(cx, xml->name, &inScopeNSes.array);
-        if (!ns) {
-            ok = JS_FALSE;
-            goto out;
-        }
+        if (!ns)
+            return false;
     } else {
         ns = NULL;
         for (i = 0, length = inScopeNSes.array.length; i < length; i++) {
             ns = XMLARRAY_MEMBER(&inScopeNSes.array, i, JSObject);
             if (ns) {
                 nsprefix = GetPrefix(ns);
                 if (nsprefix && js_EqualStrings(nsprefix, prefix))
                     break;
                 ns = NULL;
             }
         }
     }
 
     *vp = (!ns) ? JSVAL_VOID : OBJECT_TO_JSVAL(ns);
-
-  out:
-    FinishTempNSArray(cx, &inScopeNSes);
-    return JS_TRUE;
+    return true;
 }
 
 static JSBool
 xml_namespaceDeclarations(JSContext *cx, uintN argc, jsval *vp)
 {
-    JSBool ok;
-    JSTempRootedNSArray ancestors, declared;
-    JSXML *yml;
-    uint32 i, n;
-    JSObject *ns;
-
     NON_LIST_XML_METHOD_PROLOG;
     if (JSXML_HAS_VALUE(xml))
-        return JS_TRUE;
-
-    /* From here, control flow must goto out to finish these arrays. */
-    ok = JS_TRUE;
-    InitTempNSArray(cx, &ancestors);
-    InitTempNSArray(cx, &declared);
-    yml = xml;
-
+        return true;
+
+    AutoNamespaceArray ancestors(cx);
+    AutoNamespaceArray declared(cx);
+
+    JSXML *yml = xml;
     while ((yml = yml->parent) != NULL) {
         JS_ASSERT(yml->xml_class == JSXML_CLASS_ELEMENT);
-        for (i = 0, n = yml->xml_namespaces.length; i < n; i++) {
-            ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject);
-            if (ns &&
-                !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) {
-                ok = XMLARRAY_APPEND(cx, &ancestors.array, ns);
-                if (!ok)
-                    goto out;
+        for (uint32 i = 0, n = yml->xml_namespaces.length; i < n; i++) {
+            JSObject *ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject);
+            if (ns && !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) {
+                if (!XMLARRAY_APPEND(cx, &ancestors.array, ns))
+                    return false;
             }
         }
     }
 
-    for (i = 0, n = xml->xml_namespaces.length; i < n; i++) {
-        ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject);
+    for (uint32 i = 0, n = xml->xml_namespaces.length; i < n; i++) {
+        JSObject *ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject);
         if (!ns)
             continue;
         if (!IsDeclared(ns))
             continue;
         if (!XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) {
-            ok = XMLARRAY_APPEND(cx, &declared.array, ns);
-            if (!ok)
-                goto out;
-        }
-    }
-
-    ok = TempNSArrayToJSArray(cx, &declared, vp);
-
-out:
-    /* Finishing must be in reverse order of initialization to follow LIFO. */
-    FinishTempNSArray(cx, &declared);
-    FinishTempNSArray(cx, &ancestors);
-    return ok;
+            if (!XMLARRAY_APPEND(cx, &declared.array, ns))
+                return false;
+        }
+    }
+
+    return declared.toJSArray(vp);
 }
 
 static const char js_attribute_str[] = "attribute";
 static const char js_text_str[]      = "text";
 
 /* Exported to jsgc.c #ifdef DEBUG. */
 const char *js_xml_class_str[] = {
     "list",
@@ -7242,19 +7124,19 @@ js_TraceXML(JSTracer *trc, JSXML *xml)
         XMLArrayTrim(&xml->xml_kids);
 
     if (xml->xml_class == JSXML_CLASS_LIST) {
         if (xml->xml_target)
             JS_CALL_TRACER(trc, xml->xml_target, JSTRACE_XML, "target");
         if (xml->xml_targetprop)
             JS_CALL_OBJECT_TRACER(trc, xml->xml_targetprop, "targetprop");
     } else {
-        TraceObjectVector(trc,
-                          (JSObject **) xml->xml_namespaces.vector,
-                          xml->xml_namespaces.length);
+        js::TraceObjectVector(trc,
+                              (JSObject **) xml->xml_namespaces.vector,
+                              xml->xml_namespaces.length);
         XMLArrayCursorTrace(trc, xml->xml_namespaces.cursors);
         if (IS_GC_MARKING_TRACER(trc))
             XMLArrayTrim(&xml->xml_namespaces);
 
         xml_trace_vector(trc,
                          (JSXML **) xml->xml_attrs.vector,
                          xml->xml_attrs.length);
         XMLArrayCursorTrace(trc, xml->xml_attrs.cursors);
@@ -7277,27 +7159,22 @@ js_FinalizeXML(JSContext *cx, JSXML *xml
 #ifdef DEBUG_notme
     JS_REMOVE_LINK(&xml->links);
 #endif
 }
 
 JSObject *
 js_NewXMLObject(JSContext *cx, JSXMLClass xml_class)
 {
-    JSXML *xml;
-    JSObject *obj;
-    JSTempValueRooter tvr;
-
-    xml = js_NewXML(cx, xml_class);
+    JSXML *xml = js_NewXML(cx, xml_class);
     if (!xml)
         return NULL;
-    JS_PUSH_TEMP_ROOT_XML(cx, xml, &tvr);
-    obj = js_GetXMLObject(cx, xml);
-    JS_POP_TEMP_ROOT(cx, &tvr);
-    return obj;
+
+    AutoXMLRooter root(cx, xml);
+    return js_GetXMLObject(cx, xml);
 }
 
 static JSObject *
 NewXMLObject(JSContext *cx, JSXML *xml)
 {
     JSObject *obj;
 
     obj = js_NewObject(cx, &js_XMLClass, NULL, NULL);
@@ -7804,58 +7681,45 @@ js_FindXMLProperty(JSContext *cx, jsval 
                                      JSMSG_UNDEFINED_XML_NAME, printable);
     }
     return JS_FALSE;
 }
 
 static JSBool
 GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
-    JSObject *target;
-    JSXML *xml;
-    JSTempValueRooter tvr;
-    JSBool ok;
-
     JS_ASSERT(OBJECT_IS_XML(cx, obj));
 
-    MUST_FLOW_THROUGH("out");
-    JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr);
-
     /*
      * See comments before xml_lookupProperty about the need for the proto
      * chain lookup.
      */
-    target = obj;
+    JSObject *target = obj;
+    AutoObjectRooter tvr(cx);
     for (;;) {
-        ok = js_GetProperty(cx, target, id, vp);
-        if (!ok)
-            goto out;
-        if (VALUE_IS_FUNCTION(cx, *vp)) {
-            ok = JS_TRUE;
-            goto out;
-        }
+        if (!js_GetProperty(cx, target, id, vp))
+            return false;
+        if (VALUE_IS_FUNCTION(cx, *vp))
+            return true;
         target = target->getProto();
         if (target == NULL)
             break;
-        tvr.u.object = target;
-    }
-
-    xml = (JSXML *) obj->getPrivate();
-    if (HasSimpleContent(xml)) {
-        /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */
-        ok = js_GetClassPrototype(cx, NULL, JSProto_String, &tvr.u.object);
-        if (!ok)
-            goto out;
-        JS_ASSERT(tvr.u.object);
-        ok = tvr.u.object->getProperty(cx, id, vp);
-    }
-
-  out:
-    JS_POP_TEMP_ROOT(cx, &tvr);
-    return ok;
+        tvr.setObject(target);
+    }
+
+    JSXML *xml = (JSXML *) obj->getPrivate();
+    if (!HasSimpleContent(xml))
+        return true;
+
+    /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */
+    if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr()))
+        return false;
+
+    JS_ASSERT(tvr.object());
+    return tvr.object()->getProperty(cx, id, vp);
 }
 
 static JSXML *
 GetPrivate(JSContext *cx, JSObject *obj, const char *method)
 {
     JSXML *xml;
 
     xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
--- a/js/src/jsxml.h
+++ b/js/src/jsxml.h
@@ -34,17 +34,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsxml_h___
 #define jsxml_h___
 
-#include "jspubtd.h"
+#include "jsarray.h"
 
 JS_BEGIN_EXTERN_C
 
 extern const char js_AnyName_str[];
 extern const char js_AttributeName_str[];
 extern const char js_isXMLName_str[];
 extern const char js_XMLList_str[];
 
@@ -58,16 +58,68 @@ typedef JSBool
 
 struct JSXMLArray {
     uint32              length;
     uint32              capacity;
     void                **vector;
     JSXMLArrayCursor    *cursors;
 };
 
+struct JSXMLArrayCursor
+{
+    JSXMLArray       *array;
+    uint32           index;
+    JSXMLArrayCursor *next;
+    JSXMLArrayCursor **prevp;
+    void             *root;
+
+    JSXMLArrayCursor(JSXMLArray *array)
+      : array(array), index(0), next(array->cursors), prevp(&array->cursors),
+        root(NULL)
+    {
+        if (next)
+            next->prevp = &next;
+        array->cursors = this;
+    }
+
+    ~JSXMLArrayCursor() { disconnect(); }
+
+    void disconnect() {
+        if (!array)
+            return;
+        if (next)
+            next->prevp = prevp;
+        *prevp = next;
+        array = NULL;
+    }
+
+    void *getNext() {
+        if (!array || index >= array->length)
+            return NULL;
+        return root = array->vector[index++];
+    }
+
+    void *getCurrent() {
+        if (!array || index >= array->length)
+            return NULL;
+        return root = array->vector[index];
+    }
+
+    void trace(JSTracer *trc) {
+#ifdef DEBUG
+        size_t index = 0;
+#endif
+        for (JSXMLArrayCursor *cursor = this; cursor; cursor = cursor->next) {
+            void *root = cursor->root;
+            JS_SET_TRACING_INDEX(trc, "cursor_root", index++);
+            js_CallValueTracerIfGCThing(trc, jsval(root));
+        }
+    }
+};
+
 #define JSXML_PRESET_CAPACITY   JS_BIT(31)
 #define JSXML_CAPACITY_MASK     JS_BITMASK(31)
 #define JSXML_CAPACITY(array)   ((array)->capacity & JSXML_CAPACITY_MASK)
 
 /*
  * NB: don't reorder this enum without changing all array initializers that
  * depend on it in jsxml.c.
  */
--- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
@@ -35,17 +35,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "xpcprivate.h"
 #include "nsDOMError.h"
 #include "jsdbgapi.h"
-#include "jscntxt.h"  // For JSAutoTempValueRooter.
+#include "jscntxt.h"  // For js::AutoValueRooter.
 #include "jsobj.h"
 #include "XPCNativeWrapper.h"
 #include "XPCWrapper.h"
 
 // This file implements a wrapper around trusted objects that allows them to
 // be safely injected into untrusted code.
 
 namespace {
@@ -278,27 +278,26 @@ WrapObject(JSContext *cx, JSObject *pare
   JSObject *wrapperObj =
     JS_NewObjectWithGivenProto(cx, &COWClass.base, NULL, parent);
   if (!wrapperObj) {
     return JS_FALSE;
   }
 
   *vp = OBJECT_TO_JSVAL(wrapperObj);
 
-  jsval exposedProps = JSVAL_VOID;
-  JSAutoTempValueRooter tvr(cx, 1, &exposedProps);
+  js::AutoValueRooter exposedProps(cx, JSVAL_VOID);
 
-  if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), &exposedProps)) {
+  if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), exposedProps.addr())) {
     return JS_FALSE;
   }
 
   if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) ||
-      !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot,
-                          JSVAL_ZERO) ||
-      !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, exposedProps)) {
+      !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO) ||
+      !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot,
+                          exposedProps.value())) {
     return JS_FALSE;
   }
 
   return JS_TRUE;
 }
 
 } // namespace ChromeObjectWrapper
 
@@ -773,17 +772,17 @@ XPC_COW_Iterator(JSContext *cx, JSObject
   }
 
   JSObject *wrapperIter = JS_NewObject(cx, &COWClass.base, nsnull,
                                        JS_GetGlobalForObject(cx, obj));
   if (!wrapperIter) {
     return nsnull;
   }
 
-  JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
+  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
 
   // Initialize our COW.
   jsval v = OBJECT_TO_JSVAL(wrappedObj);
   if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, v) ||
       !JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot,
                           JSVAL_ZERO)) {
     return nsnull;
   }
--- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
+++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
@@ -35,17 +35,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "xpcprivate.h"
 #include "nsDOMError.h"
 #include "jsdbgapi.h"
-#include "jscntxt.h"  // For JSAutoTempValueRooter.
+#include "jscntxt.h"  // For js::AutoValueRooter.
 #include "XPCWrapper.h"
 #include "nsIDOMWindow.h"
 #include "nsIDOMWindowCollection.h"
 
 // This file implements a wrapper around objects that allows them to be
 // accessed safely from across origins.
 
 static JSBool
@@ -825,17 +825,17 @@ GetUXPCObject(JSContext *cx, JSObject *o
   }
 
   JSObject *uxpco =
     JS_NewObjectWithGivenProto(cx, &XOWClass.base, nsnull, obj->getParent());
   if (!uxpco) {
     return nsnull;
   }
 
-  JSAutoTempValueRooter tvr(cx, uxpco);
+  js::AutoValueRooter tvr(cx, uxpco);
 
   jsval wrappedObj, parentScope;
   if (!JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &wrappedObj) ||
       !JS_GetReservedSlot(cx, obj, XPC_XOW_ScopeSlot, &parentScope)) {
     return nsnull;
   }
 
   if (!JS_SetReservedSlot(cx, uxpco, sWrappedObjSlot, wrappedObj) ||
@@ -1201,17 +1201,17 @@ XPC_XOW_Iterator(JSContext *cx, JSObject
   }
 
   JSObject *wrapperIter = JS_NewObject(cx, &XOWClass.base, nsnull,
                                        JS_GetGlobalForObject(cx, obj));
   if (!wrapperIter) {
     return nsnull;
   }
 
-  JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
+  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
 
   // Initialize our XOW.
   jsval v = OBJECT_TO_JSVAL(wrappedObj);
   if (!JS_SetReservedSlot(cx, wrapperIter, sWrappedObjSlot, v) ||
       !JS_SetReservedSlot(cx, wrapperIter, sFlagsSlot, JSVAL_ZERO) ||
       !JS_SetReservedSlot(cx, wrapperIter, XPC_XOW_ScopeSlot,
                           PRIVATE_TO_JSVAL(nsnull))) {
     return nsnull;
--- a/js/src/xpconnect/src/XPCNativeWrapper.cpp
+++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp
@@ -1113,17 +1113,17 @@ XPC_NW_Iterator(JSContext *cx, JSObject 
 
   JSObject *wrapperIter =
     JS_NewObjectWithGivenProto(cx, XPCNativeWrapper::GetJSClass(), nsnull,
                                obj->getParent());
   if (!wrapperIter) {
     return nsnull;
   }
 
-  JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
+  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
 
   // Initialize our native wrapper.
   XPCWrappedNative *wn = static_cast<XPCWrappedNative *>(JS_GetPrivate(cx, obj));
   JS_SetPrivate(cx, wrapperIter, wn);
   if (!JS_SetReservedSlot(cx, wrapperIter, 0,
                           INT_TO_JSVAL(FLAG_DEEP | FLAG_EXPLICIT))) {
     return nsnull;
   }
--- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
@@ -473,17 +473,17 @@ XPC_SJOW_DelProperty(JSContext *cx, JSOb
   }
 
   return XPCWrapper::DelProperty(cx, unsafeObj, id, vp);
 }
 
 NS_STACK_CLASS class SafeCallGuard {
 public:
   SafeCallGuard(JSContext *cx, nsIPrincipal *principal)
-    : cx(cx) {
+    : cx(cx), tvr(cx) {
     nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
     if (ssm) {
       // Note: We pass null as the target frame pointer because we know that
       // we're about to set aside the frame chain.
       nsresult rv = ssm->PushContextPrincipal(cx, nsnull, principal);
       if (NS_FAILED(rv)) {
         NS_WARNING("Not allowing call because we're out of memory");
         JS_ReportOutOfMemory(cx);
@@ -512,17 +512,17 @@ public:
         ssm->PopContextPrincipal(cx);
       }
     }
   }
 
 private:
   JSContext *cx;
   JSRegExpStatics statics;
-  JSTempValueRooter tvr;
+  js::AutoValueRooter tvr;
   uint32 options;
   JSStackFrame *fp;
 };
 
 static JSBool
 XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
                           JSBool aIsSet)
 {
@@ -952,17 +952,17 @@ XPC_SJOW_Iterator(JSContext *cx, JSObjec
 
   if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot,
                           OBJECT_TO_JSVAL(unsafeObj)) ||
       !JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot,
                           JSVAL_ZERO)) {
     return nsnull;
   }
 
-  JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
+  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
 
   // Initialize the wrapper.
   return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, unsafeObj,
                                        keysonly);
 }
 
 static JSObject *
 XPC_SJOW_WrappedObject(JSContext *cx, JSObject *obj)
--- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
@@ -35,17 +35,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "xpcprivate.h"
 #include "nsDOMError.h"
 #include "jsdbgapi.h"
-#include "jscntxt.h"  // For JSAutoTempValueRooter.
+#include "jscntxt.h"  // For js::AutoValueRooter.
 #include "XPCNativeWrapper.h"
 #include "XPCWrapper.h"
 
 // This file implements a wrapper around trusted objects that allows them to
 // be safely injected into untrusted code.
 
 static JSBool
 XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
@@ -132,17 +132,17 @@ WrapObject(JSContext *cx, JSObject *pare
 
   JSObject *wrapperObj =
     JS_NewObjectWithGivenProto(cx, &SOWClass.base, NULL, parent);
   if (!wrapperObj) {
     return JS_FALSE;
   }
 
   *vp = OBJECT_TO_JSVAL(wrapperObj);
-  JSAutoTempValueRooter tvr(cx, *vp);
+  js::AutoValueRooter tvr(cx, *vp);
 
   if (!JS_SetReservedSlot(cx, wrapperObj, sWrappedObjSlot, v) ||
       !JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, JSVAL_ZERO)) {
     return JS_FALSE;
   }
 
   return JS_TRUE;
 }
@@ -432,17 +432,17 @@ XPC_SOW_GetOrSetProperty(JSContext *cx, 
   if (!obj) {
     return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
   }
 
   if (!AllowedToAct(cx, id)) {
     return JS_FALSE;
   }
 
-  JSAutoTempValueRooter tvr(cx, 1, vp);
+  js::AutoArrayRooter tvr(cx, 1, vp);
 
   JSObject *wrappedObj = GetWrappedObject(cx, obj);
   if (!wrappedObj) {
     return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
   }
 
   if (isSet && id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_PROTO)) {
     // No setting __proto__ on my object.
@@ -644,17 +644,17 @@ XPC_SOW_Iterator(JSContext *cx, JSObject
   }
 
   JSObject *wrapperIter = JS_NewObject(cx, &SOWClass.base, nsnull,
                                        JS_GetGlobalForObject(cx, obj));
   if (!wrapperIter) {
     return nsnull;
   }
 
-  JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
+  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
 
   // Initialize our SOW.
   jsval v = OBJECT_TO_JSVAL(wrappedObj);
   if (!JS_SetReservedSlot(cx, wrapperIter, sWrappedObjSlot, v) ||
       !JS_SetReservedSlot(cx, wrapperIter, sFlagsSlot, JSVAL_ZERO)) {
     return nsnull;
   }
 
--- a/js/src/xpconnect/src/XPCWrapper.cpp
+++ b/js/src/xpconnect/src/XPCWrapper.cpp
@@ -148,17 +148,17 @@ IteratorNext(JSContext *cx, uintN argc, 
     jsval name;
     JSString *str;
     if (!JS_IdToValue(cx, id, &name) ||
         !(str = JS_ValueToString(cx, name))) {
       return JS_FALSE;
     }
 
     jsval vec[2] = { STRING_TO_JSVAL(str), v };
-    JSAutoTempValueRooter tvr(cx, 2, vec);
+    js::AutoArrayRooter tvr(cx, 2, vec);
     JSObject *array = JS_NewArrayObject(cx, 2, vec);
     if (!array) {
       return JS_FALSE;
     }
 
     *vp = OBJECT_TO_JSVAL(array);
   }
 
@@ -187,17 +187,17 @@ CreateIteratorObj(JSContext *cx, JSObjec
   // identifiers with a next method, so we create an object that
   // delegates (via the __proto__ link) to the wrapper.
 
   JSObject *iterObj = JS_NewObject(cx, &IteratorClass, tempWrapper, wrapperObj);
   if (!iterObj) {
     return nsnull;
   }
 
-  JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(iterObj));
+  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(iterObj));
 
   // Do this sooner rather than later to avoid complications in
   // IteratorFinalize.
   if (!JS_SetReservedSlot(cx, iterObj, 0, PRIVATE_TO_JSVAL(nsnull))) {
     return nsnull;
   }
 
   // Initialize iterObj.
@@ -208,17 +208,17 @@ CreateIteratorObj(JSContext *cx, JSObjec
 
   if (XPCNativeWrapper::IsNativeWrapper(wrapperObj)) {
     // For native wrappers, expandos on the wrapper itself aren't propagated
     // to the wrapped object, so we have to actually iterate the wrapper here.
     // In order to do so, we set the prototype of the iter to the wrapper,
     // call enumerate, and then re-set the prototype. As we do this, we have
     // to protec the temporary wrapper from garbage collection.
 
-    JSAutoTempValueRooter tvr(cx, tempWrapper);
+    js::AutoValueRooter tvr(cx, tempWrapper);
     if (!JS_SetPrototype(cx, iterObj, wrapperObj) ||
         !XPCWrapper::Enumerate(cx, iterObj, wrapperObj) ||
         !JS_SetPrototype(cx, iterObj, tempWrapper)) {
       return nsnull;
     }
   }
 
   // Start enumerating over all of our properties.
--- a/js/src/xpconnect/src/qsgen.py
+++ b/js/src/xpconnect/src/qsgen.py
@@ -828,17 +828,17 @@ def writeQuickStub(f, customMethodCalls,
         # which is vp[1]; and it's ok to overwrite it.
         f.write("    if (!xpc_qsUnwrapThisFromCcx(ccx, &self, &selfref.ptr, "
                 "&vp[1]))\n")
         f.write("        return JS_FALSE;\n")
     else:
         if isGetter:
             pthisval = 'vp'
         elif isSetter:
-            f.write("    JSAutoTempValueRooter tvr(cx);\n")
+            f.write("    js::AutoValueRooter tvr(cx);\n")
             pthisval = 'tvr.addr()'
         else:
             pthisval = '&vp[1]' # as above, ok to overwrite vp[1]
 
         if not isSetter and isInterfaceType(member.realtype):
             f.write("    XPCLazyCallContext lccx(JS_CALLER, cx, obj);\n")
             f.write("    if (!xpc_qsUnwrapThis(cx, obj, callee, &self, "
                     "&selfref.ptr, %s, &lccx))\n" % pthisval)
--- a/js/src/xpconnect/src/xpcconvert.cpp
+++ b/js/src/xpconnect/src/xpcconvert.cpp
@@ -1577,33 +1577,33 @@ XPCConvert::ConstructException(nsresult 
 
     if(sz)
         JS_smprintf_free(sz);
     return res;
 }
 
 /********************************/
 
-class AutoExceptionRestorer : public JSAutoTempValueRooter
+class AutoExceptionRestorer
 {
 public:
     AutoExceptionRestorer(JSContext *cx, jsval v)
-        : JSAutoTempValueRooter(cx, v),
-          mVal(v)
+        : mContext(cx), tvr(cx, v)
     {
         JS_ClearPendingException(mContext);
     }
 
     ~AutoExceptionRestorer()
     {
-        JS_SetPendingException(mContext, mVal);
+        JS_SetPendingException(mContext, tvr.value());
     }
 
 private:
-    jsval mVal;
+    JSContext * const mContext;
+    js::AutoValueRooter tvr;
 };
 
 // static
 nsresult
 XPCConvert::JSValToXPCException(XPCCallContext& ccx,
                                 jsval s,
                                 const char* ifaceName,
                                 const char* methodName,
--- a/js/src/xpconnect/src/xpcquickstubs.cpp
+++ b/js/src/xpconnect/src/xpcquickstubs.cpp
@@ -168,17 +168,17 @@ GeneratePropertyOp(JSContext *cx, JSObje
     JSFunction *fun =
         JS_NewFunction(cx, reinterpret_cast<JSNative>(PropertyOpForwarder),
                        argc, JSFUN_FAST_NATIVE, obj, name);
     if(!fun)
         return JS_FALSE;
 
     JSObject *funobj = JS_GetFunctionObject(fun);
 
-    JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(funobj));
+    js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(funobj));
 
     // Unfortunately, we cannot guarantee that JSPropertyOp is aligned. Use a
     // second object to work around this.
     JSObject *ptrobj = JS_NewObject(cx, &PointerHolderClass, nsnull, funobj);
     if(!ptrobj)
         return JS_FALSE;
     JSPropertyOp *popp = new JSPropertyOp;
     if(!popp)
@@ -193,17 +193,17 @@ GeneratePropertyOp(JSContext *cx, JSObje
 
 static JSBool
 ReifyPropertyOps(JSContext *cx, JSObject *obj, jsval idval, jsid interned_id,
                  const char *name, JSPropertyOp getter, JSPropertyOp setter,
                  JSObject **getterobjp, JSObject **setterobjp)
 {
     // Generate both getter and setter and stash them in the prototype.
     jsval roots[2] = { JSVAL_NULL, JSVAL_NULL };
-    JSAutoTempValueRooter tvr(cx, 2, roots);
+    js::AutoArrayRooter tvr(cx, 2, roots);
 
     uintN attrs = JSPROP_SHARED;
     JSObject *getterobj;
     if(getter)
     {
         getterobj = GeneratePropertyOp(cx, obj, idval, 0, name, getter);
         if(!getterobj)
             return JS_FALSE;
--- a/js/src/xpconnect/src/xpcquickstubs.h
+++ b/js/src/xpconnect/src/xpcquickstubs.h
@@ -316,17 +316,17 @@ struct xpc_qsSelfRef
 template<size_t N>
 struct xpc_qsArgValArray
 {
     xpc_qsArgValArray(JSContext *cx) : tvr(cx, N, array)
     {
         memset(array, 0, N * sizeof(jsval));
     }
 
-    JSAutoTempValueRooter tvr;
+    js::AutoArrayRooter tvr;
     jsval array[N];
 };
 
 /**
  * Convert a jsval to char*, returning JS_TRUE on success.
  *
  * @param cx
  *      A context.
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp
@@ -1512,43 +1512,42 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
     {
         XPCThrower::Throw(NS_ERROR_FAILURE, cx);
         return nsnull;
     }
 
     JSStackFrame *fp;
     nsIPrincipal *principal = secMan->GetCxSubjectPrincipalAndFrame(cx, &fp);
 
-    jsval retval = OBJECT_TO_JSVAL(obj);
-    JSAutoTempValueRooter atvr(cx, 1, &retval);
+    js::AutoValueRooter retval(cx, obj);
 
     if(principal && fp)
     {
         JSScript* script = JS_GetFrameScript(cx, fp);
 
         PRUint32 flags = script ? JS_GetScriptFilenameFlags(script) : 0;
         NS_ASSERTION(flags != JSFILENAME_NULL, "Null filename!");
 
         nsXPConnect *xpc = nsXPConnect::GetXPConnect();
         if(!xpc)
         {
             XPCThrower::Throw(NS_ERROR_FAILURE, cx);
             return nsnull;
         }
 
         nsresult rv = xpc->GetWrapperForObject(cx, obj, scope, principal, flags,
-                                               &retval);
+                                               retval.addr());
         if(NS_FAILED(rv))
         {
             XPCThrower::Throw(rv, cx);
             return nsnull;
         }
     }
 
-    return JSVAL_TO_OBJECT(retval);
+    return JSVAL_TO_OBJECT(retval.value());
 }
 
 JSObjectOps *
 XPC_WN_GetObjectOpsNoCall(JSContext *cx, JSClass *clazz)
 {
     return &XPC_WN_NoCall_JSOps;
 }
 
--- a/js/src/xpconnect/tests/TestXPC.cpp
+++ b/js/src/xpconnect/tests/TestXPC.cpp
@@ -557,17 +557,17 @@ TestArgFormatter(JSContext* jscontext, J
         return;
     }
 
     do {
         JSAutoRequest ar(jscontext);
 
         // Prepare an array of arguments for JS_ConvertArguments
         jsval argv[5];
-        JSAutoTempValueRooter tvr(jscontext, 5, argv);
+        js::AutoArrayRooter tvr(jscontext, JS_ARRAY_LENGTH(argv), argv);
 
         if (!PushArguments(jscontext, 5, argv,
                            "s %ip %iv %is s",
                            a_in,
                            &NS_GET_IID(nsITestXPCFoo2), b_in.get(),
                            c_in.get(),
                            static_cast<const nsAString*>(&d_in),
                            e_in))
--- a/modules/plugin/base/src/nsJSNPRuntime.cpp
+++ b/modules/plugin/base/src/nsJSNPRuntime.cpp
@@ -668,46 +668,46 @@ doInvoke(NPObject *npobj, NPIdentifier m
     jsargs = (jsval *)PR_Malloc(argCount * sizeof(jsval));
     if (!jsargs) {
       ::JS_ReportOutOfMemory(cx);
 
       return PR_FALSE;
     }
   }
 
-  JSTempValueRooter tvr;
-  JS_PUSH_TEMP_ROOT(cx, 0, jsargs, &tvr);
-
-  // Convert args
-  for (PRUint32 i = 0; i < argCount; ++i) {
-    jsargs[i] = NPVariantToJSVal(npp, cx, args + i);
-    ++tvr.count;
-  }
-
   jsval v;
   JSBool ok;
 
-  if (ctorCall) {
-    JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj);
-    JSObject *newObj =
-      ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj),
-                                        nsnull, global, argCount, jsargs);
-
-    if (newObj) {
-      v = OBJECT_TO_JSVAL(newObj);
-      ok = JS_TRUE;
+  {
+    js::AutoArrayRooter tvr(cx, 0, jsargs);
+
+    // Convert args
+    for (PRUint32 i = 0; i < argCount; ++i) {
+      jsargs[i] = NPVariantToJSVal(npp, cx, args + i);
+      tvr.changeLength(i + 1);
+    }
+
+    if (ctorCall) {
+      JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj);
+      JSObject *newObj =
+        ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj),
+                                          nsnull, global, argCount, jsargs);
+
+      if (newObj) {
+        v = OBJECT_TO_JSVAL(newObj);
+        ok = JS_TRUE;
+      } else {
+        ok = JS_FALSE;
+      }
     } else {
-      ok = JS_FALSE;
+      ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v);
     }
-  } else {
-    ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v);
+
   }
 
-  JS_POP_TEMP_ROOT(cx, &tvr);
-
   if (jsargs != jsargs_buf)
     PR_Free(jsargs);
 
   if (ok)
     ok = JSValToNPVariant(npp, cx, v, result);
 
   // return ok == JS_TRUE to quiet down compiler warning, even if
   // return ok is what we really want.
@@ -832,17 +832,17 @@ nsJSObjWrapper::NP_SetProperty(NPObject 
   jsval id = (jsval)identifier;
   JSBool ok = JS_FALSE;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
 
   jsval v = NPVariantToJSVal(npp, cx, value);
-  JSAutoTempValueRooter tvr(cx, v);
+  js::AutoValueRooter tvr(cx, v);
 
   if (JSVAL_IS_STRING(id)) {
     JSString *str = JSVAL_TO_STRING(id);
 
     ok = ::JS_SetUCProperty(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
                             ::JS_GetStringLength(str), &v);
   } else {
     NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
--- a/modules/plugin/base/src/nsNPAPIPlugin.cpp
+++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp
@@ -1688,17 +1688,17 @@ bool NP_CALLBACK
     nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj);
 
   if (!obj) {
     return false;
   }
 
   // Root obj and the rval (below).
   jsval vec[] = { OBJECT_TO_JSVAL(obj), JSVAL_NULL };
-  JSAutoTempValueRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec);
+  js::AutoArrayRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec);
   jsval *rval = &vec[1];
 
   if (result) {
     // Initialize the out param to void
     VOID_TO_NPVARIANT(*result);
   }
 
   if (!script || !script->UTF8Length || !script->UTF8Characters) {
--- a/xpinstall/src/nsXPITriggerInfo.cpp
+++ b/xpinstall/src/nsXPITriggerInfo.cpp
@@ -242,17 +242,17 @@ XPITriggerEvent::Run()
     JSObject* innerGlobal = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(cbval));
     jsval components;
     if (!JS_LookupProperty(cx, innerGlobal, "Components", &components) ||
         !JSVAL_IS_OBJECT(components))
         return 0;
 
     // Build arguments into rooted jsval array
     jsval args[2] = { JSVAL_NULL, JSVAL_NULL };
-    JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(args), args);
+    js::AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(args), args);
 
     // args[0] is the URL
     JSString *str = JS_NewUCStringCopyZ(cx, URL.get());
     if (!str)
         return 0;
     args[0] = STRING_TO_JSVAL(str);
 
     // args[1] is the status