Merge.
authorJeff Walden <jwalden@mit.edu>
Fri, 26 Mar 2010 21:53:40 -0700
changeset 40379 ade01a37624aaaa9704580e0ae80c9d90aca9b61
parent 40376 4a32bcd70c494120045b4c7fd1f4ba64a96245aa (current diff)
parent 40378 81494bc56f63ce7f68ffc6c0fded8423713b31aa (diff)
child 40380 7fa301b622eb781ca2515275c19904c1a963e199
push idunknown
push userunknown
push dateunknown
milestone1.9.3a3pre
Merge.
dom/base/nsJSEnvironment.cpp
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/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/json.cpp
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/xpconnect/src/XPCNativeWrapper.cpp
js/src/xpconnect/src/qsgen.py
js/src/xpconnect/src/xpcconvert.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;
-    js::AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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;
-    js::AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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;
-    js::AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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;
-    js::AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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;
-    js::AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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]);
 
-    js::AutoValueRooter obj_tvr(cx);
+    JSAutoTempValueRooter 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;
-    js::AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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]);
 
-    js::AutoValueRooter obj_tvr(cx);
+    JSAutoTempValueRooter 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;
-    js::AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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]);
 
-    js::AutoValueRooter obj_tvr(cx);
+    JSAutoTempValueRooter 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;
-    js::AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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]);
 
-    js::AutoValueRooter obj_tvr(cx);
+    JSAutoTempValueRooter 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;
     }
 
-    js::AutoValueRooter obj_tvr(cx);
+    JSAutoTempValueRooter 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;
     }
 
-    js::AutoValueRooter obj_tvr(cx);
+    JSAutoTempValueRooter 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;
     }
 
-    js::AutoValueRooter obj_tvr(cx);
+    JSAutoTempValueRooter 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
@@ -2103,23 +2103,24 @@ nsJSContext::CallEventHandler(nsISupport
                               nsIArray *aargv, nsIVariant **arv)
 {
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   if (!mScriptsEnabled) {
     return NS_OK;
   }
 
-  js::AutoValueRooter targetVal(mContext, JSVAL_VOID);
+  jsval targetVal = JSVAL_VOID;
+  JSAutoTempValueRooter tvr(mContext, 1, &targetVal);
 
   JSObject* target = nsnull;
   nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  targetVal.setObject(target);
+  targetVal = OBJECT_TO_JSVAL(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.
 
@@ -2134,17 +2135,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<js::AutoArrayRooter> tvr;
+    js::LazilyConstructed<JSAutoTempValueRooter> 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);
@@ -2648,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<js::AutoArrayRooter> tvr;
+  js::LazilyConstructed<JSAutoTempValueRooter> tvr;
 
   nsresult rv;
   rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc,
                                &argv, poolRelease, tvr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   jsval vargs;
 
@@ -2683,17 +2684,17 @@ nsJSContext::SetProperty(void *aTarget, 
 }
 
 nsresult
 nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
                                      void *aScope,
                                      PRUint32 *aArgc,
                                      jsval **aArgv,
                                      js::LazilyConstructed<nsAutoPoolRelease> &aPoolRelease,
-                                     js::LazilyConstructed<js::AutoArrayRooter> &aRooter)
+                                     js::LazilyConstructed<JSAutoTempValueRooter> &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,21 +44,18 @@
 #include "nsIObserver.h"
 #include "nsIXPCScriptNotify.h"
 #include "prtime.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsScriptNameSpaceManager.h"
 
 class nsIXPConnectJSObjectHolder;
 class nsAutoPoolRelease;
-namespace js {
-class AutoValueRooter;
-class AutoArrayRooter;
-template <class> class LazilyConstructed;
-}
+class JSAutoTempValueRooter;
+namespace js { template <class> class LazilyConstructed; }
 
 class nsJSContext : public nsIScriptContext,
                     public nsIXPCScriptNotify
 {
 public:
   nsJSContext(JSRuntime *aRuntime);
   virtual ~nsJSContext();
 
@@ -213,17 +210,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<js::AutoArrayRooter> &aRooter);
+                                   js::LazilyConstructed<JSAutoTempValueRooter> &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
@@ -288,17 +288,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);
-  js::AutoValueRooter fnRoot(aContext, fnObj);
+  JSAutoTempValueRooter fnRoot(aContext, fnObj);
 
   // stash a pointer to self, which Function::Call will need at call time
   if (!JS_SetReservedSlot(aContext, fnObj, SLOT_FUNCTION, PRIVATE_TO_JSVAL(self.get())))
     return NULL;
 
   // make a strong reference to the library for GC-safety
   if (!JS_SetReservedSlot(aContext, fnObj, SLOT_LIBRARYOBJ, 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);
 
-    AutoValueRooter tvr(cx, v);
+    JSAutoTempValueRooter 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);
 
-    AutoValueRooter tvr(cx, v);
+    JSAutoTempValueRooter 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);
 
-    AutoValueRooter tvr(cx, v);
+    JSAutoTempValueRooter 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);
 
-    AutoValueRooter tvr(cx, v);
+    JSAutoTempValueRooter 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);
 
-    AutoValueRooter tvr(cx, v);
+    JSAutoTempValueRooter 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);
@@ -3078,17 +3078,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()) {
-            AutoScopePropertyRooter root(cx, sprop);
+            JSAutoTempValueRooter 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)
@@ -3836,28 +3836,29 @@ 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;
-    AutoEnumStateRooter iterState(cx, obj);
+    iter_state = JSVAL_NULL;
+    JSAutoEnumStateRooter tvr(cx, obj, &iter_state);
 
     /* Get the number of properties to enumerate. */
-    jsval num_properties;
-    if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties))
+    if (!obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &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);
@@ -3867,34 +3868,36 @@ 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, iterState.addr(), &id))
+        if (!obj->enumerate(cx, JSENUMERATE_NEXT, &iter_state, &id))
             goto error;
 
         /* No more jsid's to enumerate ? */
-        if (iterState.state() == JSVAL_NULL)
+        if (iter_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...
@@ -3968,17 +3971,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.
          */
-        AutoValueRooter tvr(cx, iterobj);
+        JSAutoTempValueRooter tvr(cx, iterobj);
         ida = JS_Enumerate(cx, obj);
         if (!ida)
             return NULL;
         pdata = ida;
         index = ida->length;
     }
 
     /* iterobj cannot escape to other threads here. */
@@ -4619,37 +4622,35 @@ 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);
 
-    {
-        AutoScriptRooter root(cx, script);
-
-        obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
-        if (obj) {
-            obj->setPrivate(script);
-            script->u.object = obj;
+    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;
 #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;
 }
@@ -4717,16 +4718,17 @@ 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);
@@ -4734,58 +4736,57 @@ JS_CompileUCFunctionForPrincipals(JSCont
             fun = NULL;
             goto out2;
         }
     }
     fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
     if (!fun)
         goto out2;
 
-    {
-        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;
-            }
+    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;
         }
-
-        if (!JSCompiler::compileFunctionBody(cx, fun, principals,
-                                             chars, length, filename, lineno)) {
+        if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) {
             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 (!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;
+    }
 
 #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;
-    }
+  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,
@@ -4963,17 +4964,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);
 
-    AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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;
     }
 
-    AutoValueRooter tvr(cx, JSVAL_NULL);
+    JSAutoTempValueRooter 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)
 {
-    AutoValueRooter dval(cx);
+    JSAutoTempValueRooter 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;
     }
 
-    AutoIdRooter idr(cx);
+    JSAutoTempIdRooter 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;
     }
 
-    AutoIdRooter idr(cx);
+    JSAutoTempIdRooter 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;
     }
 
-    AutoIdRooter idr(cx);
+    JSAutoTempIdRooter 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);
-    AutoValueRooter tvr(cx, JSVAL_NULL);
+    JSAutoTempValueRooter 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,16 +621,18 @@ 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;
+    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);
@@ -668,29 +670,34 @@ array_length_setter(JSContext *cx, JSObj
          * correspond to indexes in the half-open range [newlen, oldlen).  See
          * bug 322135.
          */
         JSObject *iter = JS_NewPropertyIterator(cx, obj);
         if (!iter)
             return false;
 
         /* Protect iter against GC under JSObject::deleteProperty. */
-        AutoValueRooter tvr(cx, iter);
-
+        JS_PUSH_TEMP_ROOT_OBJECT(cx, iter, &tvr);
         gap = oldlen - newlen;
         for (;;) {
-            if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &id))
-                return false;
+            ok = (JS_CHECK_OPERATION_LIMIT(cx) &&
+                  JS_NextProperty(cx, iter, &id));
+            if (!ok)
+                break;
             if (JSVAL_IS_VOID(id))
                 break;
-            if (js_IdIsIndex(id, &index) && index - newlen < gap &&
-                !obj->deleteProperty(cx, id, &junk)) {
-                return false;
+            if (js_IdIsIndex(id, &index) && index - newlen < gap) {
+                ok = obj->deleteProperty(cx, id, &junk);
+                if (!ok)
+                    break;
             }
         }
+        JS_POP_TEMP_ROOT(cx, &tvr);
+        if (!ok)
+            return false;
     }
 
     obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
     return true;
 }
 
 /*
  * We have only indexed properties up to capacity (excepting holes), plus the
@@ -1503,17 +1510,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;
     }
 
-    AutoValueRooter tvr(cx, obj);
+    JSAutoTempValueRooter 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;
@@ -1637,17 +1644,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. */
-            AutoIdRooter idr(cx);
+            JSAutoTempIdRooter idr(cx, JSVAL_ZERO);
             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;
@@ -1703,22 +1710,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};
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp);
+    JSAutoTempValueRooter 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);
-    AutoIdRooter idr(cx);
+    JSAutoTempIdRooter 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);
@@ -1754,28 +1761,28 @@ InitArrayObject(JSContext *cx, JSObject 
     }
     return JS_TRUE;
 }
 
 #ifdef JS_TRACER
 static JSString* FASTCALL
 Array_p_join(JSContext* cx, JSObject* obj, JSString *str)
 {
-    AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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)
 {
-    AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter tvr(cx);
     if (!array_toString_sub(cx, obj, JS_FALSE, NULL, tvr.addr())) {
         SetBuiltinError(cx);
         return NULL;
     }
     return JSVAL_TO_STRING(tvr.value());
 }
 #endif
 
@@ -1837,17 +1844,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;
     }
 
-    AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
     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;
@@ -2087,254 +2094,277 @@ 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 fval;
+    jsval *argv, fval, *vec, *mergesort_tmp, v;
+    JSObject *obj;
+    CompareArgs ca;
     jsuint len, newlen, i, undefs;
+    JSTempValueRooter tvr;
+    JSBool hole;
+    JSBool ok;
     size_t elemsize;
     JSString *str;
 
-    jsval *argv = JS_ARGV(cx, vp);
+    /*
+     * 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);
     if (argc > 0) {
         if (JSVAL_IS_PRIMITIVE(argv[0])) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG);
-            return false;
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                 JSMSG_BAD_SORT_ARG);
+            return JS_FALSE;
         }
         fval = argv[0];     /* non-default compare function */
     } else {
         fval = JSVAL_NULL;
     }
 
-    JSObject *obj = JS_THIS_OBJECT(cx, vp);
+    obj = JS_THIS_OBJECT(cx, vp);
     if (!obj || !js_GetLengthProperty(cx, obj, &len))
-        return false;
+        return JS_FALSE;
     if (len == 0) {
         *vp = OBJECT_TO_JSVAL(obj);
-        return true;
+        return JS_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(-1) / (2 * sizeof(jsval))) {
+    if ((size_t)len > ~(size_t)0 / (2 * sizeof(jsval))) {
         js_ReportAllocationOverflow(cx);
-        return false;
+        return JS_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 the rooted amount of vec when we know that the
-     * property at the corresponding index exists and its value must be rooted.
+     * one while increasing tvr.count 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.
      */
-    {
-        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);
-
+    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;
+        }
+
+        /* 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) {
         /*
-         * 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.
+         * Sort using the default comparator converting all elements to
+         * strings.
          */
-        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;
-        }
-
-        if (newlen == 0)
-            return true; /* The array has only holes and undefs. */
-
-        /*
-         * 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.
-         */
-        jsval *mergesort_tmp = vec + newlen;
-        PodZero(mergesort_tmp, newlen);
-        tvr.changeLength(newlen * 2);
-
-        /* Here len == 2 * (newlen + undefs + number_of_holes). */
-        if (fval == JSVAL_NULL) {
+        if (all_strings) {
+            elemsize = sizeof(jsval);
+        } else {
             /*
-             * Sort using the default comparator converting all elements to
-             * strings.
+             * 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 (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(-1) / (4 * sizeof(jsval))) {
-                    js_ReportAllocationOverflow(cx);
-                    return false;
-                }
+            if ((size_t)newlen > ~(size_t)0 / (4 * sizeof(jsval))) {
+                js_ReportAllocationOverflow(cx);
+                ok = JS_FALSE;
+                goto out;
+            }
 #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;
-                    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;
+            /*
+             * 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;
                 }
-                mergesort_tmp = vec + 2 * newlen;
-                PodZero(mergesort_tmp, newlen * 2);
-                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;
+                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;
             }
-            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;
+            tvr.u.array = vec;
+            mergesort_tmp = vec + 2 * newlen;
+            PodZero(mergesort_tmp, newlen * 2);
+            tvr.count = newlen * 4;
+            elemsize = 2 * sizeof(jsval);
+        }
+        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 false;
+        if (!JS_CHECK_OPERATION_LIMIT(cx) ||
+            !SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) {
+            return JS_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 true;
+    return JS_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)
 {
@@ -2398,17 +2428,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)
 {
-    AutoValueRooter tvr(cx, v);
+    JSAutoTempValueRooter 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;
 }
@@ -2470,17 +2500,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)
 {
-    AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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;
 }
@@ -2534,17 +2564,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. */
-            AutoValueRooter tvr(cx);
+            JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
             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;
                 }
             }
 
@@ -2579,17 +2609,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;
-                AutoValueRooter tvr(cx);
+                JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
                 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);
@@ -2669,17 +2699,17 @@ array_splice(JSContext *cx, uintN argc, 
         else if (d > delta)
             d = delta;
         count = (jsuint)d;
         end = begin + count;
         argc--;
         argv++;
     }
 
-    AutoValueRooter tvr(cx, JSVAL_NULL);
+    JSAutoTempValueRooter 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] !=
@@ -2808,17 +2838,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;
     }
 
-    AutoValueRooter tvr(cx, JSVAL_NULL);
+    JSAutoTempValueRooter 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;
@@ -2922,17 +2952,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);
 
-    AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
     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;
     }
@@ -3443,17 +3473,17 @@ js_NewArrayObject(JSContext *cx, jsuint 
 
     /*
      * If this fails, the global object was not initialized and its class does
      * not have JSCLASS_IS_GLOBAL.
      */
     JS_ASSERT(obj->getProto());
 
     {
-        AutoValueRooter tvr(cx, obj);
+        JSAutoTempValueRooter 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;
 }
@@ -3562,17 +3592,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;
 
-    AutoValueRooter tvr(cx, obj);
+    JSAutoTempValueRooter 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
@@ -1159,16 +1159,106 @@ typedef struct JSResolvingEntry {
     JSResolvingKey      key;
     uint32              flags;
 } JSResolvingEntry;
 
 #define JSRESFLAG_LOOKUP        0x1     /* resolving id from lookup */
 #define JSRESFLAG_WATCH         0x2     /* resolving id from watch */
 #define JSRESOLVE_INFER         0xffff  /* infer bits from current bytecode */
 
+/*
+ * 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)
+
 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;
@@ -1381,16 +1471,19 @@ 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;
@@ -1658,27 +1751,27 @@ class AutoGCRooter {
      * memory corruption.
      */
     ptrdiff_t tag;
 
     JSContext * const context;
 
     enum {
         JSVAL =        -1, /* js::AutoValueRooter */
-        SPROP =        -2, /* js::AutoScopePropertyRooter */
-        WEAKROOTS =    -3, /* js::AutoSaveWeakRoots */
+        SPROP =        -2, /* JSAutoScopePropertyTreeRooter */
+        WEAKROOTS =    -3, /* AutoSaveWeakRoots */
         COMPILER =     -4, /* JSCompiler */
-        SCRIPT =       -5, /* js::AutoScriptRooter */
-        ENUMERATOR =   -6, /* js::AutoEnumStateRooter */
-        IDARRAY =      -7, /* js::AutoIdArray */
-        DESCRIPTORS =  -8, /* js::AutoDescriptorArray */
-        NAMESPACES =   -9, /* js::AutoNamespaces */
-        XML =         -10, /* js::AutoXMLRooter */
-        OBJECT =      -11, /* js::AutoObjectRooter */
-        ID =          -12  /* js::AutoIdRooter */
+        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:
     explicit AutoSaveWeakRoots(JSContext *cx
                                JS_GUARD_OBJECT_NOTIFIER_PARAM)
@@ -1957,17 +2050,156 @@ class AutoXMLRooter : private AutoGCRoot
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 
   private:
     JSXML * const xml;
 };
 #endif /* JS_HAS_XML_SUPPORT */
 
-}
+} /* namespace js */
+
+/* FIXME(bug 332648): Move this into a public header. */
+class JSAutoTempValueRooter
+{
+  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) {
+        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);
+    }
+
+    jsval value() { return mTvr.u.value; }
+    jsval *addr() { return &mTvr.u.value; }
+
+  protected:
+    JSContext *mContext;
+
+  private:
+    JSTempValueRooter mTvr;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+class JSAutoTempIdRooter
+{
+  public:
+    explicit JSAutoTempIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0)
+                                JS_GUARD_OBJECT_NOTIFIER_PARAM)
+        : mContext(cx) {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+        JS_PUSH_SINGLE_TEMP_ROOT(mContext, ID_TO_VALUE(id), &mTvr);
+    }
+
+    ~JSAutoTempIdRooter() {
+        JS_POP_TEMP_ROOT(mContext, &mTvr);
+    }
+
+    jsid id() { return (jsid) mTvr.u.value; }
+    jsid * addr() { return (jsid *) &mTvr.u.value; }
+
+  private:
+    JSContext *mContext;
+    JSTempValueRooter mTvr;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+class JSAutoIdArray {
+  public:
+    JSAutoIdArray(JSContext *cx, JSIdArray *ida
+                  JS_GUARD_OBJECT_NOTIFIER_PARAM)
+        : cx(cx), idArray(ida) {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+        if (ida)
+            JS_PUSH_TEMP_ROOT(cx, ida->length, ida->vector, &tvr);
+    }
+    ~JSAutoIdArray() {
+        if (idArray) {
+            JS_POP_TEMP_ROOT(cx, &tvr);
+            JS_DestroyIdArray(cx, 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;
+    }
+  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 &);
+};
+
+/* The auto-root for enumeration object and its state. */
+class JSAutoEnumStateRooter : public JSTempValueRooter
+{
+  public:
+    JSAutoEnumStateRooter(JSContext *cx, JSObject *obj, jsval *statep
+                          JS_GUARD_OBJECT_NOTIFIER_PARAM)
+        : mContext(cx), mStatep(statep)
+    {
+        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);
+    }
+
+    void mark(JSTracer *trc) {
+        JS_CALL_OBJECT_TRACER(trc, u.object, "enumerator_obj");
+        js_MarkEnumeratorState(trc, u.object, *mStatep);
+    }
+
+  private:
+    JSContext   *mContext;
+    jsval       *mStatep;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
 
 class JSAutoResolveFlags
 {
   public:
     JSAutoResolveFlags(JSContext *cx, uintN flags
                        JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : mContext(cx), mSaved(cx->resolveFlags)
     {
deleted file mode 100644
--- a/js/src/jscntxtinlines.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* -*- 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);
 
-    bool wasThrowing = cx->throwing;
-    AutoValueRooter lastException(cx, cx->exception);
+    JSBool wasThrowing = cx->throwing;
+    JSAutoTempValueRooter 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
@@ -833,44 +833,52 @@ exn_toSource(JSContext *cx, uintN argc, 
     obj = JS_THIS_OBJECT(cx, vp);
     if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp))
         return false;
     name = js_ValueToString(cx, *vp);
     if (!name)
         return false;
     *vp = STRING_TO_JSVAL(name);
 
+    JSTempValueRooter tvr;
     {
-        AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroots), localroots);
+        JSBool ok;
+
+        MUST_FLOW_THROUGH("out");
+        JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr);
 
 #ifdef __GNUC__
         message = filename = NULL;
 #endif
-        if (!JS_GetProperty(cx, obj, js_message_str, &localroots[0]) ||
-            !(message = js_ValueToSource(cx, localroots[0]))) {
-            return false;
-        }
+        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_fileName_str, &localroots[1]) ||
-            !(filename = js_ValueToSource(cx, localroots[1]))) {
-            return false;
-        }
+        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;
+        ok = JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]);
+        if (!ok)
+            goto out;
         lineno = js_ValueToECMAUint32 (cx, &localroots[2]);
-        if (JSVAL_IS_NULL(localroots[2]))
-            return false;
+        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;
+            if (!lineno_as_str) {
+                ok = JS_FALSE;
+                goto out;
+            }
             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();
@@ -891,18 +899,20 @@ exn_toSource(JSContext *cx, uintN argc, 
                  * 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)
-            return false;
+        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;
@@ -929,21 +939,26 @@ exn_toSource(JSContext *cx, uintN argc, 
             cp += lineno_length;
         }
 
         *cp++ = ')'; *cp++ = ')'; *cp = 0;
 
         result = js_NewString(cx, chars, length);
         if (!result) {
             cx->free(chars);
-            return false;
+            ok = JS_FALSE;
+            goto out;
         }
         *vp = STRING_TO_JSVAL(result);
-        return true;
+        ok = JS_TRUE;
     }
+
+  out:
+    JS_POP_TEMP_ROOT(cx, &tvr);
+    return JS_FALSE;
 }
 #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),
@@ -984,17 +999,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;
 
     PodArrayZero(roots);
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
+    JSAutoTempValueRooter 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;
@@ -1142,17 +1157,19 @@ 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. */
     PodArrayZero(tv);
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tv), tv);
+
+    JSTempValueRooter tvr;
+    JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr);
 
     /*
      * 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)
@@ -1186,16 +1203,17 @@ 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;
@@ -1207,17 +1225,20 @@ js_ReportUncaughtException(JSContext *cx
 
     if (!JS_IsExceptionPending(cx))
         return true;
 
     if (!JS_GetPendingException(cx, &exn))
         return false;
 
     PodArrayZero(roots);
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
+    JSBool ok = JS_TRUE;
+    JSTempValueRooter tvr;
+    JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr);
+    MUST_FLOW_THROUGH("out");
 
     /*
      * 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)) {
@@ -1232,46 +1253,59 @@ 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)
-            return false;
+        if (!bytes) {
+            ok = JS_FALSE;
+            goto out;
+        }
     }
 
-    if (!reportp && exnObject && OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) {
+    if (!reportp && exnObject && exnObject->getClass() == &js_ErrorClass) {
         const char *filename;
         uint32 lineno;
 
-        if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2]))
-            return false;
+        if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2])) {
+            ok = JS_FALSE;
+            goto out;
+        }
         if (JSVAL_IS_STRING(roots[2])) {
             bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2]));
-            if (!bytes)
-                return false;
+            if (!bytes) {
+                ok = JS_FALSE;
+                goto out;
+            }
         }
 
-        if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]))
-            return false;
+        ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]);
+        if (!ok)
+            goto out;
         str = js_ValueToString(cx, roots[3]);
-        if (!str)
-            return false;
+        if (!str) {
+            ok = JS_FALSE;
+            goto out;
+        }
         filename = StringToFilename(cx, str);
-        if (!filename)
-            return false;
+        if (!filename) {
+            ok = JS_FALSE;
+            goto out;
+        }
 
-        if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]))
-            return false;
+        ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]);
+        if (!ok)
+            goto out;
         lineno = js_ValueToECMAUint32 (cx, &roots[4]);
-        if (JSVAL_IS_NULL(roots[4]))
-            return false;
+        ok = !JSVAL_IS_NULL(roots[4]);
+        if (!ok)
+            goto out;
 
         reportp = &report;
         PodZero(&report);
         report.filename = filename;
         report.lineno = (uintN) lineno;
     }
 
     if (!reportp) {
@@ -1282,10 +1316,12 @@ js_ReportUncaughtException(JSContext *cx
         reportp->flags |= JSREPORT_EXCEPTION;
 
         /* Pass the exception object. */
         JS_SetPendingException(cx, exn);
         js_ReportErrorAgain(cx, bytes, reportp);
         JS_ClearPendingException(cx);
     }
 
-    return true;
+  out:
+    JS_POP_TEMP_ROOT(cx, &tvr);
+    return ok;
 }
--- 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;
-    AutoValueRooter tvr(cx, wfunobj);
+    JSAutoTempValueRooter 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;
 
-    AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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,59 +1579,64 @@ 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 false;
+            return JS_FALSE;
         }
         if (fun->u.i.wrapper) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_XDR_CLOSURE_WRAPPER,
                                  JS_GetFunctionName(fun));
-            return false;
+            return JS_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 false;
+            return JS_FALSE;
         FUN_OBJECT(fun)->clearParent();
         FUN_OBJECT(fun)->clearProto();
 #ifdef __GNUC__
         nvars = nargs = nupvars = 0;    /* quell GCC uninitialized warning */
 #endif
     }
 
-    AutoValueRooter tvr(cx, FUN_OBJECT(fun));
+    /* 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;
 
     if (!JS_XDRUint32(xdr, &firstword))
-        return false;
+        goto bad;
     if ((firstword & 1U) && !js_XDRStringAtom(xdr, &fun->atom))
-        return false;
+        goto bad;
     if (!JS_XDRUint32(xdr, &localsword) ||
         !JS_XDRUint32(xdr, &flagsword)) {
-        return false;
+        goto bad;
     }
 
     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);
@@ -1645,17 +1650,16 @@ 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
@@ -1664,23 +1668,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 = false;
+            ok = JS_FALSE;
             goto release_mark;
         }
         if (xdr->mode == JSXDR_ENCODE) {
             names = js_GetLocalNameArray(xdr->cx, fun, &xdr->cx->tempPool);
             if (!names) {
-                ok = false;
+                ok = JS_FALSE;
                 goto release_mark;
             }
             PodZero(bitmap, bitmapLength);
             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] |=
@@ -1725,40 +1729,47 @@ 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)
-            return false;
+            goto out;
 
         if (xdr->mode == JSXDR_DECODE)
             js_FreezeLocalNames(cx, fun);
     }
 
     if (!js_XDRScript(xdr, &fun->u.i.script, false, NULL))
-        return false;
+        goto bad;
 
     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);
         }
     }
 
-    return true;
+out:
+    JS_POP_TEMP_ROOT(cx, &tvr);
+    return ok;
+
+bad:
+    ok = JS_FALSE;
+    goto out;
 }
 
 #else  /* !JS_HAS_XDR */
 
 #define js_XDRFunctionObject NULL
 
 #endif /* !JS_HAS_XDR */
 
@@ -2673,51 +2684,54 @@ 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;
-
-    AutoValueRooter tvr(cx);
+    JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr);
     if (flags & JSV2F_ITERATOR) {
         error = JSMSG_BAD_ITERATOR;
         name = js_iterator_str;
         JSString *src = js_ValueToSource(cx, *vp);
         if (!src)
-            return;
-        tvr.setString(src);
+            goto out;
+        tvr.u.value = STRING_TO_JSVAL(src);
         JSString *qsrc = js_QuoteString(cx, src, 0);
         if (!qsrc)
-            return;
-        tvr.setString(qsrc);
+            goto out;
+        tvr.u.value = STRING_TO_JSVAL(qsrc);
         source = js_GetStringBytes(cx, qsrc);
         if (!source)
-            return;
+            goto out;
     } 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,17 +82,16 @@
 #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
@@ -106,16 +105,24 @@
 #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);
 
@@ -2257,30 +2264,29 @@ 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;
 }
 
-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);
-        }
-    }
-}
-
-}
+#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
 
 void
 js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
 {
     uintN nslots, minargs, skip;
 
     if (fp->callobj)
         JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call");
@@ -2296,17 +2302,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;
             }
-            js::TraceValues(trc, nslots, fp->slots, "slot");
+            TRACE_JSVALS(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");
@@ -2321,17 +2327,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;
         }
-        js::TraceValues(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand");
+        TRACE_JSVALS(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
@@ -2376,16 +2382,17 @@ 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.
      */
@@ -2425,32 +2432,59 @@ 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);
-        js::TraceValues(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack");
+        TRACE_JSVALS(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack");
     }
 
-    for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down)
-        gcr->trace(trc);
+    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");
+        }
+    }
 
     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)
-            js::TraceValues(trc, state->nativeVpLen, state->nativeVp, "nativeVp");
+            TRACE_JSVALS(trc, state->nativeVpLen, state->nativeVp, "nativeVp");
         state = state->prev;
     }
 #endif
 }
 
 JS_REQUIRES_STACK void
 js_TraceRuntime(JSTracer *trc, JSBool allAtoms)
 {
@@ -3392,40 +3426,43 @@ 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)) {
-        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 {
+        JSWeakRoots savedWeakRoots;
+        JSTempValueRooter tvr;
+
+        if (gckind & GC_KEEP_ATOMS) {
             /*
              * 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.
              */
-            AutoSaveWeakRoots save(cx);
-
+            savedWeakRoots = cx->weakRoots;
+            JS_PUSH_TEMP_ROOT_WEAK_COPY(cx, &savedWeakRoots, &tvr);
             JS_KEEP_ATOMS(rt);
             JS_UNLOCK_GC(rt);
-
-            (void) callback(cx, JSGC_END);
-
+        }
+
+        (void) callback(cx, JSGC_END);
+
+        if (gckind & GC_KEEP_ATOMS) {
             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;
         }
     }
     TIMESTAMP(gcTimer.end);
 
 #ifdef MOZ_GCTIMER
     if (gcTimer.startMark > 0)
         dumpGCTimer(&gcTimer, firstEnter, gckind == GC_LAST_CONTEXT);
     newChunkCount = 0;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -450,28 +450,9 @@ 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
@@ -309,17 +309,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;
-    AutoValueRooter tvr(cx, innermostNewChild);
+    JSAutoTempValueRooter 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);
@@ -514,17 +514,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);
-    AutoValueRooter tvr(cx, JSVAL_NULL);
+    JSAutoTempValueRooter 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,21 +210,28 @@ 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] = { ID_TO_VALUE(key), val };
-    AutoArrayRooter tvr(cx, 2, vec);
+    jsval vec[2];
+    JSTempValueRooter tvr;
+    JSObject *aobj;
 
-    JSObject *aobj = js_NewArrayObject(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);
     *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;
@@ -335,99 +342,109 @@ 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 false;
+                return JS_FALSE;
             if (!obj)
                 goto default_iter;
         } else {
             obj = js_ValueToNonNullObject(cx, *vp);
             if (!obj)
-                return false;
+                return JS_FALSE;
         }
     }
 
-    tvr.setObject(obj);
+    JS_ASSERT(obj);
+    JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
 
     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)
-            return false;
+            goto bad;
         *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))
-            return false;
+            goto bad;
         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)
-                return false;
+                goto bad;
 
             /* Store in *vp to protect it from GC (callers must root vp). */
             *vp = OBJECT_TO_JSVAL(iterobj);
 
             if (!InitNativeIterator(cx, iterobj, obj, flags))
-                return false;
+                goto bad;
         } else {
             LeaveTrace(cx);
             arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0);
             if (!js_InternalInvoke(cx, obj, *vp, JSINVOKE_ITERATOR, 1, &arg,
                                    vp)) {
-                return false;
+                goto bad;
             }
             if (JSVAL_IS_PRIMITIVE(*vp)) {
                 js_ReportValueError(cx, JSMSG_BAD_ITERATOR_RETURN,
                                     JSDVG_SEARCH_STACK, *vp, NULL);
-                return false;
+                goto bad;
             }
         }
     }
 
-    return true;
+    ok = JS_TRUE;
+  out:
+    if (obj)
+        JS_POP_TEMP_ROOT(cx, &tvr);
+    return ok;
+  bad:
+    ok = JS_FALSE;
+    goto out;
 }
 
 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
@@ -989,21 +989,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.
          */
-        AutoValueRooter gcr(cx, v);
-        if (!obj->defaultValue(cx, JSTYPE_NUMBER, gcr.addr()))
+        JSAutoTempValueRooter tvr(cx, v);
+        if (!obj->defaultValue(cx, JSTYPE_NUMBER, tvr.addr()))
             obj = NULL;
         else
-            v = *vp = gcr.value();
+            v = *vp = tvr.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
@@ -628,17 +628,19 @@ obj_toSource(JSContext *cx, uintN argc, 
     jsval *val;
     jsval localroot[4] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
     JSString *gsopold[2];
     JSString *gsop[2];
     JSString *idstr, *valstr, *str;
 
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroot), localroot);
+    JSTempValueRooter tvr;
+    MUST_FLOW_THROUGH("out");
+    JS_PUSH_TEMP_ROOT(cx, 4, localroot, &tvr);
 
     /* 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;
     }
@@ -993,16 +995,17 @@ 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;
 }
@@ -1677,17 +1680,17 @@ js_HasOwnProperty(JSContext *cx, JSLooku
              * It's not really a hack, of course: a permanent property can't
              * be deleted, and JSPROP_SHARED means "don't allocate a slot in
              * any instance, prototype or delegating".  Without a slot, and
              * without the ability to remove and recreate (with differences)
              * the property, there is no way to tell whether it is directly
              * owned, or indirectly delegated.
              */
             JSScopeProperty *sprop = reinterpret_cast<JSScopeProperty *>(*propp);
-            if (sprop->isSharedPermanent())
+            if (!sprop->isSharedPermanent())
                 return true;
         }
 
         (*objp)->dropProperty(cx, *propp);
         *propp = NULL;
     }
     return true;
 }
@@ -2016,33 +2019,33 @@ js_GetOwnPropertyDescriptor(JSContext *c
 static JSBool
 obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp)
 {
     if (argc == 0 || JSVAL_IS_PRIMITIVE(vp[2])) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
         return false;
     }
     JSObject *obj = JSVAL_TO_OBJECT(vp[2]);
-    AutoIdRooter nameidr(cx);
+    JSAutoTempIdRooter nameidr(cx);
     if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr()))
         return JS_FALSE;
     return js_GetOwnPropertyDescriptor(cx, obj, nameidr.id(), vp);
 }
 
 static JSBool
 obj_keys(JSContext *cx, uintN argc, jsval *vp)
 {
     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);
-    AutoIdArray ida(cx, JS_Enumerate(cx, obj));
+    JSAutoIdArray 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);
 
@@ -2197,16 +2200,60 @@ 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,
@@ -2566,17 +2613,16 @@ DefineProperty(JSContext *cx, JSObject *
     return DefinePropertyObject(cx, obj, desc, throwError, rval);
 }
 
 JSBool
 js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
 {
     AutoDescriptorArray descs(cx);
     PropertyDescriptor *desc = descs.append();
-
     if (!desc || !desc->initialize(cx, id, descriptor))
         return false;
 
     bool rval;
     if (!DefineProperty(cx, obj, *desc, true, &rval))
         return false;
     *bp = !!rval;
     return true;
@@ -2625,17 +2671,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);
 
-    AutoIdArray ida(cx, JS_Enumerate(cx, props));
+    JSAutoIdArray 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();
@@ -2689,17 +2735,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]);
-        AutoIdArray ida(cx, JS_Enumerate(cx, props));
+        JSAutoIdArray 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();
@@ -2887,17 +2933,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)) {
-        AutoValueRooter tvr(cx, obj);
+        JSAutoTempValueRooter 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:
@@ -3563,17 +3609,17 @@ js_XDRBlockObject(JSXDRState *xdr, JSObj
          */
         if (parentId == NO_PARENT_INDEX)
             parent = NULL;
         else
             parent = xdr->script->getObject(parentId);
         obj->setParent(parent);
     }
 
-    AutoValueRooter tvr(cx, obj);
+    JSAutoTempValueRooter 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));
@@ -3690,18 +3736,20 @@ js_InitClass(JSContext *cx, JSObject *ob
         return NULL;
     }
 
     /* 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. */
-    AutoValueRooter tvr(cx, proto);
+    /* After this point, control must exit via label out or out. */
+    JSTempValueRooter tvr;
+    JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr);
+    MUST_FLOW_THROUGH("out");
 
     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.
          */
@@ -3781,16 +3829,17 @@ 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;
 }
@@ -4088,29 +4137,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;
 
-    AutoArrayRooter argtvr(cx, argc, argv);
+    JSAutoTempValueRooter 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. */
-    AutoValueRooter tvr(cx, cval);
+    JSAutoTempValueRooter 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();
@@ -4916,18 +4965,18 @@ 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);
     {
-        AutoScopePropertyRooter tvr(cx, sprop);
-        AutoValueRooter tvr2(cx, pobj);
+        JSAutoTempValueRooter tvr(cx, sprop);
+        JSAutoTempValueRooter 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))) {
@@ -4978,17 +5027,17 @@ js_NativeSet(JSContext *cx, JSObject *ob
          */
         if (!sprop->hasGetterValue() && sprop->hasDefaultSetter())
             return js_ReportGetterOnlyAssignment(cx);
     }
 
     sample = cx->runtime->propertyRemovals;
     JS_UNLOCK_SCOPE(cx, scope);
     {
-        AutoScopePropertyRooter tvr(cx, sprop);
+        JSAutoTempValueRooter 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))) {
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -47,24 +47,22 @@
  * 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 js::AutoDescriptorArray;
+  friend class 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,39 +78,9 @@ 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
@@ -103,48 +103,51 @@ JSClass js_JSONClass = {
     JSCLASS_NO_OPTIONAL_MEMBERS
 };
 
 JSBool
 js_json_parse(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *s = NULL;
     jsval *argv = vp + 2;
-    AutoValueRooter reviver(cx, JSVAL_NULL);
+    jsval reviver = JSVAL_NULL;
+    JSAutoTempValueRooter tvr(cx, 1, &reviver);
 
-    if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, reviver.addr()))
+    if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, &reviver))
         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.value());
+        ok &= js_FinishJSONParse(cx, jp, reviver);
     }
 
     return ok;
 }
 
 JSBool
 js_json_stringify(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval *argv = vp + 2;
-    AutoValueRooter space(cx, JSVAL_NULL);
-    AutoObjectRooter replacer(cx);
+    JSObject *replacer = NULL;
+    jsval space = JSVAL_NULL;
+    JSAutoTempValueRooter tvr(cx, replacer);
+    JSAutoTempValueRooter tvr2(cx, 1, &space);
 
     // Must throw an Error if there isn't a first arg
-    if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, replacer.addr(), space.addr()))
+    if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, &replacer, &space))
         return JS_FALSE;
 
     JSCharBuffer cb(cx);
 
-    if (!js_Stringify(cx, vp, replacer.object(), space.value(), cb))
+    if (!js_Stringify(cx, vp, replacer, space, 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)
@@ -252,17 +255,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};
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec);
+    JSAutoTempValueRooter tvr(cx, 3, 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
@@ -301,17 +304,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;
         }
-        AutoValueRooter keyStringRoot(cx, ks);
+        JSAutoTempValueRooter 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)) {
@@ -387,30 +390,31 @@ JA(JSContext *cx, jsval *vp, StringifyCo
 
     if (!scx->cb.append('['))
         return JS_FALSE;
 
     jsuint length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
-    AutoValueRooter outputValue(cx, JSVAL_NULL);
+    jsval outputValue = JSVAL_NULL;
+    JSAutoTempValueRooter tvr(cx, 1, &outputValue);
 
     jsid id;
     jsuint i;
     for (i = 0; i < length; i++) {
         id = INT_TO_JSID(i);
 
-        if (!obj->getProperty(cx, id, outputValue.addr()))
+        if (!obj->getProperty(cx, id, &outputValue))
             return JS_FALSE;
 
-        if (!Str(cx, id, obj, scx, outputValue.addr()))
+        if (!Str(cx, id, obj, scx, &outputValue))
             return JS_FALSE;
 
-        if (outputValue.value() == JSVAL_VOID) {
+        if (outputValue == 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))
@@ -564,94 +568,105 @@ 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 bool
+static JSBool
+DestroyIdArrayOnError(JSContext *cx, JSIdArray *ida) {
+    JS_DestroyIdArray(cx, ida);
+    return JS_FALSE;
+}
+
+static JSBool
 Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp)
 {
-    JS_CHECK_RECURSION(cx, return false);
+    JS_CHECK_RECURSION(cx, return JS_FALSE);
 
     if (!holder->getProperty(cx, id, vp))
-        return false;
+        return JS_FALSE;
 
     JSObject *obj;
 
     if (!JSVAL_IS_PRIMITIVE(*vp) && !(obj = JSVAL_TO_OBJECT(*vp))->isCallable()) {
-        AutoValueRooter propValue(cx, JSVAL_NULL);
+        jsval propValue = JSVAL_NULL;
+        JSAutoTempValueRooter tvr(cx, 1, &propValue);
 
         if(obj->isArray()) {
             jsuint length = 0;
             if (!js_GetLengthProperty(cx, obj, &length))
-                return false;
+                return JS_FALSE;
 
             for (jsuint i = 0; i < length; i++) {
                 jsid index;
                 if (!js_IndexToId(cx, i, &index))
-                    return false;
+                    return JS_FALSE;
 
-                if (!Walk(cx, index, obj, reviver, propValue.addr()))
-                    return false;
+                if (!Walk(cx, index, obj, reviver, &propValue))
+                    return JS_FALSE;
 
-                if (!obj->defineProperty(cx, index, propValue.value(), NULL, NULL, JSPROP_ENUMERATE))
-                    return false;
+                if (!obj->defineProperty(cx, index, propValue, NULL, NULL, JSPROP_ENUMERATE))
+                    return JS_FALSE;
             }
         } else {
-            AutoIdArray ida(cx, JS_Enumerate(cx, obj));
+            JSIdArray *ida = JS_Enumerate(cx, obj);
             if (!ida)
-                return false;
+                return JS_FALSE;
+
+            JSAutoTempValueRooter idaroot(cx, JS_ARRAY_LENGTH(ida), (jsval*)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;
+            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);
                 } else {
-                    if (!obj->defineProperty(cx, idName, propValue.value(), NULL, NULL,
-                                             JSPROP_ENUMERATE)) {
-                        return false;
-                    }
+                    if (!obj->defineProperty(cx, idName, propValue, NULL, NULL, JSPROP_ENUMERATE))
+                        return DestroyIdArrayOnError(cx, ida);
                 }
             }
+
+            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 false;
+        return JS_FALSE;
 
     jsval vec[2] = {STRING_TO_JSVAL(key), value};
     jsval reviverResult;
     if (!JS_CallFunctionValue(cx, holder, reviver, 2, vec, &reviverResult))
-        return false;
+        return JS_FALSE;
 
     *vp = reviverResult;
-    return true;
+
+    return JS_TRUE;
 }
 
-static bool
+static JSBool
 Revive(JSContext *cx, jsval reviver, jsval *vp)
 {
 
     JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
     if (!obj)
-        return false;
+        return JS_FALSE;
 
-    AutoValueRooter tvr(cx, obj);
+    jsval v = OBJECT_TO_JSVAL(obj);
+    JSAutoTempValueRooter tvr(cx, 1, &v);
     if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom),
                              *vp, NULL, NULL, JSPROP_ENUMERATE)) {
-        return false;
+        return JS_FALSE;
     }
 
     return Walk(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), obj, reviver, vp);
 }
 
 JSONParser *
 js_BeginJSONParse(JSContext *cx, jsval *rootVal)
 {
@@ -676,21 +691,21 @@ js_BeginJSONParse(JSContext *cx, jsval *
 
     return jp;
 
 bad:
     js_FinishJSONParse(cx, jp, JSVAL_NULL);
     return NULL;
 }
 
-bool
+JSBool
 js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
 {
     if (!jp)
-        return true;
+        return JS_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);
@@ -701,30 +716,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);
 
-    bool ok = *jp->statep == JSON_PARSE_STATE_FINISHED;
+    JSBool ok = *jp->statep == JSON_PARSE_STATE_FINISHED;
     jsval *vp = jp->rootVal;
 
     cx->destroy(jp);
 
     if (!early_ok)
-        return false;
+        return JS_FALSE;
 
     if (!ok) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE);
-        return false;
+        return JS_FALSE;
     }
 
-    if (!JSVAL_IS_PRIMITIVE(reviver) && JSVAL_TO_OBJECT(reviver)->isCallable())
+    if (!JSVAL_IS_PRIMITIVE(reviver) && js_IsCallable(reviver))
         ok = Revive(cx, reviver, vp);
 
     return ok;
 }
 
 static JSBool
 PushState(JSContext *cx, JSONParser *jp, JSONParserState state)
 {
@@ -792,17 +807,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);
-    AutoValueRooter tvr(cx, v);
+    JSAutoTempValueRooter 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;
@@ -865,17 +880,17 @@ static JSBool
 CloseArray(JSContext *cx, JSONParser *jp)
 {
     return CloseObject(cx, jp);
 }
 
 static JSBool
 PushPrimitive(JSContext *cx, JSONParser *jp, jsval value)
 {
-    AutoValueRooter tvr(cx, value);
+    JSAutoTempValueRooter tvr(cx, 1, &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 bool
+extern JSBool
 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
@@ -304,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) {
-            AutoValueRooter tvr(cx);
+            JSAutoTempValueRooter 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
@@ -167,25 +167,28 @@ JSCompiler::init(const jschar *base, siz
     tempPoolMark = JS_ARENA_MARK(&cx->tempPool);
     if (!tokenStream.init(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();
     JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
 }
 
 void
 JSCompiler::setPrincipals(JSPrincipals *prin)
 {
@@ -280,17 +283,20 @@ JSFunctionBox::shouldUnbrand(uintN metho
         }
     }
     return false;
 }
 
 void
 JSCompiler::trace(JSTracer *trc)
 {
-    JSObjectBox *objbox = traceListHead;
+    JSObjectBox *objbox;
+
+    JS_ASSERT(tempRoot.u.compiler == this);
+    objbox = traceListHead;
     while (objbox) {
         JS_CALL_OBJECT_TRACER(trc, objbox->object, "parser.object");
         objbox = objbox->traceLink;
     }
 }
 
 static void
 UnlinkFunctionBoxes(JSParseNode *pn, JSTreeContext *tc);
@@ -8704,16 +8710,17 @@ FoldBinaryNumeric(JSContext *cx, JSOp op
 
 static JSBool
 FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
 {
     TokenKind 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)
@@ -8794,22 +8801,21 @@ FoldXMLConstants(JSContext *cx, JSParseN
             }
             pnp = &pn2->pn_next;
             pn1 = *pnp;
             accum = NULL;
             continue;
         }
 
         if (accum) {
-            {
-                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);
-            }
+            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);
             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
@@ -907,46 +907,44 @@ struct JSFunctionBoxQueue {
 };
 
 #define NUM_TEMP_FREELISTS      6U      /* 32 to 2048 byte size classes (32 bit) */
 
 class JSTreeContext;
 
 typedef struct BindData BindData;
 
-struct JSCompiler : private js::AutoGCRooter {
-    JSContext           * const context; /* FIXME Bug 551291: use AutoGCRooter::context? */
+struct JSCompiler {
+    JSContext           * const context;
     JSAtomListElement   *aleFreeList;
     void                *tempFreeList[NUM_TEMP_FREELISTS];
     js::TokenStream     tokenStream;
     void                *tempPoolMark;  /* initial JSContext.tempPool mark */
     JSPrincipals        *principals;    /* principals associated with source */
     JSStackFrame *const callerFrame;    /* scripted caller frame for eval and dbgapi */
     JSObject     *const callerVarObj;   /* callerFrame's varObj */
     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 */
     JSTreeContext       *tc;            /* innermost tree context (stack-allocated) */
+    JSTempValueRooter   tempRoot;       /* root to trace traceListHead */
 
     JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL)
-      : js::AutoGCRooter(cx, COMPILER), context(cx),
+      : context(cx),
         aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp),
         callerVarObj(cfp ? cfp->varobj(cx->containingCallStack(cfp)) : NULL),
         nodeList(NULL), functionCount(0), traceListHead(NULL), tc(NULL)
     {
         js::PodArrayZero(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
@@ -280,16 +280,41 @@ 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
@@ -5221,36 +5221,37 @@ 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,
-                             AutoValueRooter *tvr)
+                             JSTempValueRooter *tvr)
 {
     *statics = cx->regExpStatics;
-    if (statics->input)
-        tvr->setString(statics->input);
+    JS_PUSH_TEMP_ROOT_STRING(cx, statics->input, tvr);
+
     /*
      * 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,
-                        AutoValueRooter *tvr)
+                        JSTempValueRooter *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)
@@ -5833,17 +5834,17 @@ js_NewRegExpObject(JSContext *cx, TokenS
 {
     JSString *str;
     JSObject *obj;
     JSRegExp *re;
 
     str = js_NewStringCopyN(cx, chars, length);
     if (!str)
         return NULL;
-    AutoValueRooter tvr(cx, str);
+    JSAutoTempValueRooter 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,25 +60,23 @@ 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,
-                             js::AutoValueRooter *tvr);
+                             JSTempValueRooter *tvr);
 
 extern JS_FRIEND_API(void)
 js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
-                        js::AutoValueRooter *tvr);
+                        JSTempValueRooter *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,16 +89,17 @@ 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;
@@ -206,32 +207,30 @@ 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;
-        tvr.setScript(script);
+        JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr);
     }
 
     /*
      * Control hereafter must goto error on failure, in order for the
      * DECODE case to destroy script.
      */
     oldscript = xdr->script;
     code = script->code;
@@ -364,20 +363,23 @@ 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
@@ -1631,17 +1631,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;
 
-    AutoValueRooter array(cx, JSVAL_NULL);
+    JSAutoTempValueRooter 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;
 }
@@ -3323,17 +3323,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;
-    AutoValueRooter tvr(cx, JSVAL_NULL);
+    JSAutoTempValueRooter 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
@@ -8839,22 +8839,23 @@ 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");
         }
     }
     {
-        AutoValueRooter tvr(cx);
-
-        *tvr.addr() = l;
-        lnum = js_ValueToNumber(cx, tvr.addr());
-        *tvr.addr() = r;
-        rnum = js_ValueToNumber(cx, tvr.addr());
+        jsval tmp = JSVAL_NULL;
+        JSAutoTempValueRooter tvr(cx, 1, &tmp);
+
+        tmp = l;
+        lnum = js_ValueToNumber(cx, &tmp);
+        tmp = r;
+        rnum = js_ValueToNumber(cx, &tmp);
     }
     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
@@ -11238,17 +11239,17 @@ TraceRecorder::nativeSet(JSObject* obj, 
     }
 
     return RECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 MethodWriteBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj)
 {
-    AutoValueRooter tvr(cx, funobj);
+    JSAutoTempValueRooter 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, PropertyCacheEntry* entry, JSScopeProperty* sprop,
@@ -11605,17 +11606,17 @@ TraceRecorder::getPropertyByName(LIns* o
     return RECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp)
 {
     LeaveTraceIfGlobalObject(cx, obj);
 
-    AutoIdRooter idr(cx);
+    JSAutoTempIdRooter 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)
@@ -11950,32 +11951,32 @@ TraceRecorder::initOrSetPropertyByName(L
     return RECORD_CONTINUE;
 }
 
 static JSBool FASTCALL
 SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp)
 {
     LeaveTraceIfGlobalObject(cx, obj);
 
-    AutoIdRooter idr(cx);
+    JSAutoTempIdRooter 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);
 
-    AutoIdRooter idr(cx);
+    JSAutoTempIdRooter 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,
@@ -12792,17 +12793,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)
 {
-    AutoValueRooter tvr(cx, funobj);
+    JSAutoTempValueRooter 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)
@@ -14924,17 +14925,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)
 {
-    AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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
@@ -1377,20 +1377,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)
 {
-    AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter tvr(cx);
     js_NewNumberInRootedValue(cx, jsdouble(nbytes), tvr.addr());
 
-    AutoValueRooter rval(cx);
+    JSAutoTempValueRooter rval(cx);
     if (!ArrayBuffer::class_constructor(cx, cx->globalObject,
                                         1, tvr.addr(), 
                                         rval.addr()))
         return NULL;
 
     return JSVAL_TO_OBJECT(rval.value());
 }
 
@@ -1432,34 +1432,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];
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
+    JSAutoTempValueRooter tvr(cx, 2, 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];
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
+    JSAutoTempValueRooter tvr(cx, 2, vals);
 
     vals[0] = OBJECT_TO_JSVAL(arrayArg);
 
     if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1]))
         return NULL;
 
     return JSVAL_TO_OBJECT(vals[1]);
 }
@@ -1469,17 +1469,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];
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals);
+    JSAutoTempValueRooter tvr(cx, 4, 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:
- *     js::AutoValueRooter tvr(cx, 1, &val);
+ *     JSAutoTempValueRooter tvr(cx, 1, &val);
  * but is is easy to accidentally write:
- *     js::AutoValueRooter(cx, 1, &val);
+ *     JSAutoTempValueRooter(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
@@ -369,20 +369,17 @@ class Vector : AllocPolicy
 
     const T &back() const {
         JS_ASSERT(!entered && !empty());
         return *(end() - 1);
     }
 
     /* mutators */
 
-    /*
-     * If reserve(N) succeeds, additions to this vector which increase its size
-     * up to and including N are guaranteed to succeed.
-     */
+    /* If reserve(N) succeeds, the N next appends 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,18 +65,16 @@
 #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
@@ -865,20 +863,70 @@ 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)
 {
-    cursor->trace(trc);
+    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);
+    }
 }
 
 /* NB: called with null cx from the GC, via xml_trace => XMLArrayTrim. */
 static JSBool
 XMLArraySetCapacity(JSContext *cx, JSXMLArray *array, uint32 capacity)
 {
     void **vector;
 
@@ -3792,83 +3840,88 @@ 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 true;
+        return JS_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 true;
+                    return JS_TRUE;
                 }
                 kidobj = js_GetXMLObject(cx, kid);
                 if (!kidobj)
-                    return false;
+                    return JS_FALSE;
 
                 *vp = OBJECT_TO_JSVAL(kidobj);
             } else {
                 *vp = JSVAL_VOID;
             }
         }
-        return true;
+        return JS_TRUE;
     }
 
     /*
      * ECMA-357 9.2.1.1/9.1.1.1 qname case.
      */
     nameqn = ToXMLName(cx, id, &funid);
     if (!nameqn)
-        return false;
+        return JS_FALSE;
     if (funid)
         return GetXMLFunction(cx, obj, funid, vp);
 
-    jsval roots[2] = { OBJECT_TO_JSVAL(nameqn), JSVAL_NULL };
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
+    roots[0] = OBJECT_TO_JSVAL(nameqn);
+    JS_PUSH_TEMP_ROOT(cx, 1, roots, &tvr);
 
     listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
-    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;
+    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;
 }
 
 static JSXML *
 CopyOnWrite(JSContext *cx, JSXML *xml, JSObject *obj)
 {
     JS_ASSERT(xml->object != obj);
 
     xml = DeepCopy(cx, xml, obj, 0);
@@ -3902,16 +3955,18 @@ 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;
@@ -3930,23 +3985,21 @@ 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;
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
+    JS_PUSH_TEMP_ROOT(cx, 3, roots, &tvr);
 
     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;
         }
 
@@ -4523,16 +4576,17 @@ 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:
@@ -4654,44 +4708,48 @@ 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 false;
+        return JS_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.
              */
-            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);
+            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;
         }
     }
     *found = (prop != NULL);
-    return true;
+    return JS_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;
@@ -4948,46 +5006,40 @@ 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) {
-            *statep = JSVAL_ZERO;
+            cursor = NULL;
         } 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:
-        if (*statep != JSVAL_ZERO) {
-            cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep);
-            if (cursor)
-                cx->destroy(cursor);
-        }
+        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)
@@ -5066,17 +5118,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.
      */
-    AutoValueRooter tvr(cx);
+    JSAutoTempValueRooter 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)
@@ -5089,32 +5141,30 @@ 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) {
-            *statep = JSVAL_ZERO;
+            cursor = NULL;
         } else {
             cursor = cx->create<JSXMLArrayCursor>(&xml->xml_kids);
             if (!cursor)
                 return JS_FALSE;
-            *statep = PRIVATE_TO_JSVAL(cursor);
-        }
-        JS_ASSERT(!idp);
-        JS_ASSERT(!vp);
+        }
+        *statep = PRIVATE_TO_JSVAL(cursor);
+        if (idp)
+            *idp = INT_TO_JSID(length);
+        if (vp)
+            *vp = JSVAL_VOID;
         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)
@@ -5123,22 +5173,20 @@ 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:
-        if (*statep != JSVAL_ZERO) {
-            cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep);
-            if (cursor) {
-          destroy:
-                cx->destroy(cursor);
-            }
+        cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep);
+        if (cursor) {
+      destroy:
+            cx->destroy(cursor);
         }
         *statep = JSVAL_NULL;
         break;
     }
     return JS_TRUE;
 }
 
 JSBool
@@ -5421,17 +5469,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);
 
-    AutoValueRooter tvr(cx, name);
+    JSAutoTempValueRooter 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;
@@ -5827,16 +5875,91 @@ 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;
@@ -5868,58 +5991,29 @@ 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;
 
-    AutoNamespaceArray namespaces(cx);
-    return FindInScopeNamespaces(cx, xml, &namespaces.array) && namespaces.toJSArray(vp);
+    InitTempNSArray(cx, &namespaces);
+    ok = FindInScopeNamespaces(cx, xml, &namespaces.array) &&
+         TempNSArrayToJSArray(cx, &namespaces, vp);
+    FinishTempNSArray(cx, &namespaces);
+    return ok;
 }
 
 static JSBool
 xml_insertChildAfter(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval arg;
     JSXML *kid;
     uint32 i;
@@ -6009,94 +6103,120 @@ 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 true;
+        return JS_TRUE;
     }
 
     if (argc == 0) {
         prefix = NULL;
     } else {
         prefix = js_ValueToString(cx, vp[2]);
         if (!prefix)
-            return false;
+            return JS_FALSE;
         vp[2] = STRING_TO_JSVAL(prefix);      /* local root */
     }
 
-    AutoNamespaceArray inScopeNSes(cx);
-    if (!FindInScopeNamespaces(cx, xml, &inScopeNSes.array))
-        return false;
+    InitTempNSArray(cx, &inScopeNSes);
+    MUST_FLOW_THROUGH("out");
+    ok = FindInScopeNamespaces(cx, xml, &inScopeNSes.array);
+    if (!ok)
+        goto out;
 
     if (!prefix) {
         ns = GetNamespace(cx, xml->name, &inScopeNSes.array);
-        if (!ns)
-            return false;
+        if (!ns) {
+            ok = JS_FALSE;
+            goto out;
+        }
     } 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);
-    return true;
+
+  out:
+    FinishTempNSArray(cx, &inScopeNSes);
+    return JS_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 true;
-
-    AutoNamespaceArray ancestors(cx);
-    AutoNamespaceArray declared(cx);
-
-    JSXML *yml = 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;
+
     while ((yml = yml->parent) != NULL) {
         JS_ASSERT(yml->xml_class == JSXML_CLASS_ELEMENT);
-        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 = 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 = xml->xml_namespaces.length; i < n; i++) {
-        JSObject *ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject);
+    for (i = 0, n = xml->xml_namespaces.length; i < n; i++) {
+        ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject);
         if (!ns)
             continue;
         if (!IsDeclared(ns))
             continue;
         if (!XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) {
-            if (!XMLARRAY_APPEND(cx, &declared.array, ns))
-                return false;
-        }
-    }
-
-    return declared.toJSArray(vp);
+            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;
 }
 
 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",
@@ -7119,19 +7239,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 {
-        js::TraceObjectVector(trc,
-                              (JSObject **) xml->xml_namespaces.vector,
-                              xml->xml_namespaces.length);
+        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);
@@ -7154,22 +7274,27 @@ 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 = js_NewXML(cx, xml_class);
+    JSXML *xml;
+    JSObject *obj;
+    JSTempValueRooter tvr;
+
+    xml = js_NewXML(cx, xml_class);
     if (!xml)
         return NULL;
-
-    AutoXMLRooter root(cx, xml);
-    return js_GetXMLObject(cx, xml);
+    JS_PUSH_TEMP_ROOT_XML(cx, xml, &tvr);
+    obj = js_GetXMLObject(cx, xml);
+    JS_POP_TEMP_ROOT(cx, &tvr);
+    return obj;
 }
 
 static JSObject *
 NewXMLObject(JSContext *cx, JSXML *xml)
 {
     JSObject *obj;
 
     obj = js_NewObject(cx, &js_XMLClass, NULL, NULL);
@@ -7676,45 +7801,58 @@ 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.
      */
-    JSObject *target = obj;
-    AutoObjectRooter tvr(cx);
+    target = obj;
     for (;;) {
-        if (!js_GetProperty(cx, target, id, vp))
-            return false;
-        if (VALUE_IS_FUNCTION(cx, *vp))
-            return true;
+        ok = js_GetProperty(cx, target, id, vp);
+        if (!ok)
+            goto out;
+        if (VALUE_IS_FUNCTION(cx, *vp)) {
+            ok = JS_TRUE;
+            goto out;
+        }
         target = target->getProto();
         if (target == NULL)
             break;
-        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);
+        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;
 }
 
 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 "jsarray.h"
+#include "jspubtd.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,68 +58,16 @@ 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 js::AutoValueRooter.
+#include "jscntxt.h"  // For JSAutoTempValueRooter.
 #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,26 +278,27 @@ WrapObject(JSContext *cx, JSObject *pare
   JSObject *wrapperObj =
     JS_NewObjectWithGivenProto(cx, &COWClass.base, NULL, parent);
   if (!wrapperObj) {
     return JS_FALSE;
   }
 
   *vp = OBJECT_TO_JSVAL(wrapperObj);
 
-  js::AutoValueRooter exposedProps(cx, JSVAL_VOID);
+  jsval exposedProps = JSVAL_VOID;
+  JSAutoTempValueRooter tvr(cx, 1, &exposedProps);
 
-  if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), exposedProps.addr())) {
+  if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), &exposedProps)) {
     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.value())) {
+      !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot,
+                          JSVAL_ZERO) ||
+      !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, exposedProps)) {
     return JS_FALSE;
   }
 
   return JS_TRUE;
 }
 
 } // namespace ChromeObjectWrapper
 
@@ -772,17 +773,17 @@ XPC_COW_Iterator(JSContext *cx, JSObject
   }
 
   JSObject *wrapperIter = JS_NewObject(cx, &COWClass.base, nsnull,
                                        JS_GetGlobalForObject(cx, obj));
   if (!wrapperIter) {
     return nsnull;
   }
 
-  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
+  JSAutoTempValueRooter 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 js::AutoValueRooter.
+#include "jscntxt.h"  // For JSAutoTempValueRooter.
 #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;
   }
 
-  js::AutoValueRooter tvr(cx, uxpco);
+  JSAutoTempValueRooter 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;
   }
 
-  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
+  JSAutoTempValueRooter 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
@@ -1139,17 +1139,17 @@ XPC_NW_Iterator(JSContext *cx, JSObject 
 
   JSObject *wrapperIter =
     JS_NewObjectWithGivenProto(cx, XPCNativeWrapper::GetJSClass(false), nsnull,
                                obj->getParent());
   if (!wrapperIter) {
     return nsnull;
   }
 
-  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
+  JSAutoTempValueRooter 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), tvr(cx) {
+    : cx(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;
-  js::AutoValueRooter tvr;
+  JSTempValueRooter 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;
   }
 
-  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
+  JSAutoTempValueRooter 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 js::AutoValueRooter.
+#include "jscntxt.h"  // For JSAutoTempValueRooter.
 #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);
-  js::AutoValueRooter tvr(cx, *vp);
+  JSAutoTempValueRooter 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;
   }
 
-  js::AutoArrayRooter tvr(cx, 1, vp);
+  JSAutoTempValueRooter 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;
   }
 
-  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
+  JSAutoTempValueRooter 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 };
-    js::AutoArrayRooter tvr(cx, 2, vec);
+    JSAutoTempValueRooter 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;
   }
 
-  js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(iterObj));
+  JSAutoTempValueRooter 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.
 
-    js::AutoValueRooter tvr(cx, tempWrapper);
+    JSAutoTempValueRooter 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
@@ -830,17 +830,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("    js::AutoValueRooter tvr(cx);\n")
+            f.write("    JSAutoTempValueRooter 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
+class AutoExceptionRestorer : public JSAutoTempValueRooter
 {
 public:
     AutoExceptionRestorer(JSContext *cx, jsval v)
-        : mContext(cx), tvr(cx, v)
+        : JSAutoTempValueRooter(cx, v),
+          mVal(v)
     {
         JS_ClearPendingException(mContext);
     }
 
     ~AutoExceptionRestorer()
     {
-        JS_SetPendingException(mContext, tvr.value());
+        JS_SetPendingException(mContext, mVal);
     }
 
 private:
-    JSContext * const mContext;
-    js::AutoValueRooter tvr;
+    jsval mVal;
 };
 
 // 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);
 
-    js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(funobj));
+    JSAutoTempValueRooter 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 };
-    js::AutoArrayRooter tvr(cx, 2, roots);
+    JSAutoTempValueRooter 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));
     }
 
-    js::AutoArrayRooter tvr;
+    JSAutoTempValueRooter 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,42 +1512,43 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
     {
         XPCThrower::Throw(NS_ERROR_FAILURE, cx);
         return nsnull;
     }
 
     JSStackFrame *fp;
     nsIPrincipal *principal = secMan->GetCxSubjectPrincipalAndFrame(cx, &fp);
 
-    js::AutoValueRooter retval(cx, obj);
+    jsval retval = OBJECT_TO_JSVAL(obj);
+    JSAutoTempValueRooter atvr(cx, 1, &retval);
 
     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.addr());
+                                               &retval);
         if(NS_FAILED(rv))
         {
             XPCThrower::Throw(rv, cx);
             return nsnull;
         }
     }
 
-    return JSVAL_TO_OBJECT(retval.value());
+    return JSVAL_TO_OBJECT(retval);
 }
 
 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];
-        js::AutoArrayRooter tvr(jscontext, JS_ARRAY_LENGTH(argv), argv);
+        JSAutoTempValueRooter tvr(jscontext, 5, 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;
 
-  {
-    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;
     }
-
-    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_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);
-  js::AutoValueRooter tvr(cx, v);
+  JSAutoTempValueRooter 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
@@ -1693,17 +1693,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 };
-  js::AutoArrayRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec);
+  JSAutoTempValueRooter 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 };
-    js::AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(args), args);
+    JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(args), args);
 
     // args[0] is the URL
     JSString *str = JS_NewUCStringCopyZ(cx, reinterpret_cast<const jschar*>(URL.get()));
     if (!str)
         return 0;
     args[0] = STRING_TO_JSVAL(str);
 
     // args[1] is the status