Bug 770759 - Add mutable handles (r=bhackett)
authorBill McCloskey <wmccloskey@mozilla.com>
Wed, 04 Jul 2012 11:12:16 -0700
changeset 98351 13897ce0f3a2a70e7b8a9d1cf6b1e939416fe6f8
parent 98350 9586208fceae9c8852d82a971e557873c8f51856
child 98352 2ecd5bbb52897c504f1a134966396a6cd62a1b4e
push id23046
push userwmccloskey@mozilla.com
push dateThu, 05 Jul 2012 01:18:01 +0000
treeherdermozilla-central@13897ce0f3a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs770759
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 770759 - Add mutable handles (r=bhackett)
content/xbl/src/nsXBLBinding.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/plugins/base/nsJSNPRuntime.cpp
dom/workers/RuntimeService.cpp
dom/workers/WorkerScope.cpp
dom/workers/Workers.h
gfx/skia/src/xml/SkJS.cpp
js/ipc/ObjectWrapperParent.cpp
js/ipc/ObjectWrapperParent.h
js/src/gc/Root.h
js/src/jsapi-tests/testLookup.cpp
js/src/jsapi-tests/testResolveRecursion.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsclass.h
js/src/jsclone.cpp
js/src/jscompartment.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsinfer.cpp
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jswrapper.cpp
js/src/jsxml.cpp
js/src/jsxml.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/ObjectImpl.cpp
js/src/vm/ScopeObject.cpp
js/xpconnect/shell/xpcshell.cpp
js/xpconnect/src/XPCRuntimeService.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -326,19 +326,19 @@ FieldSetter(JSContext *cx, unsigned argc
 
   JS::Rooted<JS::Value> v(cx,
                           argc > 0 ? JS_ARGV(cx, vp)[0] : JS::UndefinedValue());
   return JS_SetPropertyById(cx, thisObj, id, v.address());
 }
 
 static JSBool
 XBLResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
-           JSObject **objp)
+           JSMutableHandleObject objp)
 {
-  *objp = NULL;
+  objp.set(NULL);
 
   if (!JSID_IS_STRING(id)) {
     return true;
   }
 
   nsXBLPrototypeBinding* protoBinding =
     static_cast<nsXBLPrototypeBinding*>(::JS_GetReservedSlot(obj, 0).toPrivate());
   MOZ_ASSERT(protoBinding);
@@ -382,17 +382,17 @@ XBLResolve(JSContext *cx, JSHandleObject
                                JS_DATA_TO_FUNC_PTR(JSPropertyOp,
                                                    get.reference()),
                                JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp,
                                                    set.reference()),
                                field->AccessorAttributes())) {
     return false;
   }
 
-  *objp = obj;
+  objp.set(obj);
   return true;
 }
 
 static JSBool
 XBLEnumerate(JSContext *cx, JS::Handle<JSObject*> obj)
 {
   nsXBLPrototypeBinding* protoBinding =
     static_cast<nsXBLPrototypeBinding*>(::JS_GetReservedSlot(obj, 0).toPrivate());
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -5371,17 +5371,17 @@ GetDocument(JSObject *obj)
   return static_cast<nsHTMLDocument*>(
     static_cast<nsIHTMLDocument*>(::JS_GetPrivate(obj)));
 }
 
 // static
 JSBool
 nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSHandleObject obj,
                                           JSHandleId id, unsigned flags,
-                                          JSObject **objp)
+                                          JSMutableHandleObject objp)
 {
   if (flags & (JSRESOLVE_ASSIGNING | JSRESOLVE_QUALIFIED) ||
       !JSID_IS_STRING(id)) {
     // Nothing to do here if we're assigning, doing a qualified resolve, or
     // resolving a non-string property.
 
     return JS_TRUE;
   }
@@ -5425,17 +5425,17 @@ nsWindowSH::GlobalScopePolluterNewResolv
                              getter_AddRefs(holder));
     NS_ENSURE_SUCCESS(rv, JS_FALSE);
 
     if (!JS_WrapValue(cx, &v) ||
         !JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull, 0)) {
       return JS_FALSE;
     }
 
-    *objp = obj;
+    objp.set(obj);
   }
 
   return JS_TRUE;
 }
 
 // static
 void
 nsWindowSH::InvalidateGlobalScopePolluter(JSContext *cx, JSObject *obj)
@@ -7318,19 +7318,21 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
   // It is not worth calling GlobalResolve() if we are resolving
   // for assignment, since only read-write properties get dealt
   // with there.
   if (!(flags & JSRESOLVE_ASSIGNING)) {
     JSAutoRequest ar(cx);
 
     // Resolve special classes.
     for (PRUint32 i = 0; i < ArrayLength(sOtherResolveFuncs); i++) {
-      if (!sOtherResolveFuncs[i](cx, obj, id, flags, objp)) {
+      JS::RootedObject tmp(cx, *objp);
+      if (!sOtherResolveFuncs[i](cx, obj, id, flags, &tmp)) {
         return NS_ERROR_FAILURE;
       }
+      *objp = tmp;
       if (*objp) {
         return NS_OK;
       }
     }
 
     // Call GlobalResolve() after we call FindChildWithName() so
     // that named child frames will override external properties
     // which have been registered with the script namespace manager.
@@ -8960,32 +8962,32 @@ nsHTMLDocumentSH::DocumentAllGetProperty
     *vp = JSVAL_VOID;
   }
 
   return JS_TRUE;
 }
 
 JSBool
 nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id,
-                                        unsigned flags, JSObject **objp)
+                                        unsigned flags, JSMutableHandleObject objp)
 {
   if (flags & JSRESOLVE_ASSIGNING) {
     // Nothing to do here if we're assigning
 
     return JS_TRUE;
   }
 
   jsval v = JSVAL_VOID;
 
   if (sItem_id == id || sNamedItem_id == id) {
     // Define the item() or namedItem() method.
 
     JSFunction *fnc = ::JS_DefineFunctionById(cx, obj, id, CallToGetPropMapper,
                                               0, JSPROP_ENUMERATE);
-    *objp = obj;
+    objp.set(obj);
 
     return fnc != nsnull;
   }
 
   if (sLength_id == id) {
     // document.all.length. Any jsval other than undefined would do
     // here, all we need is to get into the code below that defines
     // this propery on obj, the rest happens in
@@ -9012,17 +9014,17 @@ nsHTMLDocumentSH::DocumentAllNewResolve(
       return JS_FALSE;
     }
   }
 
   JSBool ok = JS_TRUE;
 
   if (v != JSVAL_VOID) {
     ok = ::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull, 0);
-    *objp = obj;
+    objp.set(obj);
   }
 
   return ok;
 }
 
 // Finalize hook used by document related JS objects, but also by
 // sGlobalScopePolluterClass!
 
@@ -9159,40 +9161,40 @@ nsHTMLDocumentSH::DocumentAllHelperGetPr
   }
 
   return JS_TRUE;
 }
 
 JSBool
 nsHTMLDocumentSH::DocumentAllHelperNewResolve(JSContext *cx, JSHandleObject obj,
                                               JSHandleId id, unsigned flags,
-                                              JSObject **objp)
+                                              JSMutableHandleObject objp)
 {
   if (nsDOMClassInfo::sAll_id == id) {
     // document.all is resolved for the first time. Define it.
     JSObject *helper = GetDocumentAllHelper(obj);
 
     if (helper) {
       if (!::JS_DefineProperty(cx, helper, "all", JSVAL_VOID, nsnull, nsnull,
                                JSPROP_ENUMERATE)) {
         return JS_FALSE;
       }
 
-      *objp = helper;
+      objp.set(helper);
     }
   }
 
   return JS_TRUE;
 }
 
 
 JSBool
 nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSHandleObject obj,
                                             JSHandleId id, unsigned flags,
-                                            JSObject **objp)
+                                            JSMutableHandleObject objp)
 {
   if (JSID_IS_STRING(id)) {
     nsDocument *doc = GetDocument(obj);
 
     JSObject *proto = ::JS_GetPrototype(obj);
     if (NS_UNLIKELY(!proto)) {
       return JS_TRUE;
     }
@@ -9220,17 +9222,17 @@ nsHTMLDocumentSH::DocumentAllTagsNewReso
 
         return JS_FALSE;
       }
 
       if (!::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull, 0)) {
         return JS_FALSE;
       }
 
-      *objp = obj;
+      objp.set(obj);
     }
   }
 
   return JS_TRUE;
 }
 
 
 NS_IMETHODIMP
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -379,17 +379,17 @@ public:
                         JSObject **objp, bool *_retval);
   NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop,
                       JSObject *obj);
   NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
                          JSObject * obj, JSObject * *_retval);
 
   static JSBool GlobalScopePolluterNewResolve(JSContext *cx, JSHandleObject obj,
                                               JSHandleId id, unsigned flags,
-                                              JSObject **objp);
+                                              JSMutableHandleObject objp);
   static JSBool GlobalScopePolluterGetProperty(JSContext *cx, JSHandleObject obj,
                                                JSHandleId id, jsval *vp);
   static JSBool SecurityCheckOnAddDelProp(JSContext *cx, JSHandleObject obj, JSHandleId id,
                                           jsval *vp);
   static JSBool SecurityCheckOnSetProp(JSContext *cx, JSHandleObject obj, JSHandleId id,
                                        JSBool strict, jsval *vp);
   static void InvalidateGlobalScopePolluter(JSContext *cx, JSObject *obj);
   static nsresult InstallGlobalScopePolluter(JSContext *cx, JSObject *obj,
@@ -773,27 +773,27 @@ protected:
   static JSBool GetDocumentAllNodeList(JSContext *cx, JSObject *obj,
                                        nsDocument *doc,
                                        nsContentList **nodeList);
 
 public:
   static JSBool DocumentAllGetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id,
                                        jsval *vp);
   static JSBool DocumentAllNewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id,
-                                      unsigned flags, JSObject **objp);
+                                      unsigned flags, JSMutableHandleObject objp);
   static void ReleaseDocument(JSFreeOp *fop, JSObject *obj);
   static JSBool CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp);
   static JSBool DocumentAllHelperGetProperty(JSContext *cx, JSHandleObject obj,
                                              JSHandleId id, jsval *vp);
   static JSBool DocumentAllHelperNewResolve(JSContext *cx, JSHandleObject obj,
                                             JSHandleId id, unsigned flags,
-                                            JSObject **objp);
+                                            JSMutableHandleObject objp);
   static JSBool DocumentAllTagsNewResolve(JSContext *cx, JSHandleObject obj,
                                           JSHandleId id, unsigned flags,
-                                          JSObject **objp);
+                                          JSMutableHandleObject objp);
 
   NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj, jsid id, PRUint32 flags,
                         JSObject **objp, bool *_retval);
   NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                          JSObject *obj, jsid id, jsval *vp, bool *_retval);
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -122,17 +122,17 @@ static JSBool
 NPObjWrapper_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, jsval *vp);
 
 static JSBool
 NPObjWrapper_newEnumerate(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op,
                           jsval *statep, jsid *idp);
 
 static JSBool
 NPObjWrapper_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
-                        JSObject **objp);
+                        JSMutableHandleObject objp);
 
 static JSBool
 NPObjWrapper_Convert(JSContext *cx, JSHandleObject obj, JSType type, jsval *vp);
 
 static void
 NPObjWrapper_Finalize(JSFreeOp *fop, JSObject *obj);
 
 static JSBool
@@ -1591,17 +1591,17 @@ NPObjWrapper_newEnumerate(JSContext *cx,
     break;
   }
 
   return JS_TRUE;
 }
 
 static JSBool
 NPObjWrapper_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
-                        JSObject **objp)
+                        JSMutableHandleObject objp)
 {
   NPObject *npobj = GetNPObject(obj);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
       !npobj->_class->hasMethod) {
     ThrowJSException(cx, "Bad NPObject as private data!");
 
     return JS_FALSE;
@@ -1618,33 +1618,33 @@ NPObjWrapper_NewResolve(JSContext *cx, J
   if (hasProperty) {
     NS_ASSERTION(JSID_IS_STRING(id) || JSID_IS_INT(id),
                  "id must be either string or int!\n");
     if (!::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nsnull,
                                  nsnull, JSPROP_ENUMERATE)) {
         return JS_FALSE;
     }
 
-    *objp = obj;
+    objp.set(obj);
 
     return JS_TRUE;
   }
 
   bool hasMethod = npobj->_class->hasMethod(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return JS_FALSE;
 
   if (hasMethod) {
     NS_ASSERTION(JSID_IS_STRING(id) || JSID_IS_INT(id),
                  "id must be either string or int!\n");
 
     JSFunction *fnc = ::JS_DefineFunctionById(cx, obj, id, CallNPMethod, 0,
                                               JSPROP_ENUMERATE);
 
-    *objp = obj;
+    objp.set(obj);
 
     return fnc != nsnull;
   }
 
   // no property or method
   return JS_TRUE;
 }
 
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -363,23 +363,23 @@ public:
 
 } /* anonymous namespace */
 
 BEGIN_WORKERS_NAMESPACE
 
 // Entry point for the DOM.
 JSBool
 ResolveWorkerClasses(JSContext* aCx, JSHandleObject aObj, JSHandleId aId, unsigned aFlags,
-                     JSObject** aObjp)
+                     JSMutableHandleObject aObjp)
 {
   AssertIsOnMainThread();
 
   // Don't care about assignments, bail now.
   if (aFlags & JSRESOLVE_ASSIGNING) {
-    *aObjp = nsnull;
+    aObjp.set(nsnull);
     return true;
   }
 
   // Make sure our strings are interned.
   if (JSID_IS_VOID(gStringIDs[0])) {
     for (PRUint32 i = 0; i < ID_COUNT; i++) {
       JSString* str = JS_InternString(aCx, gStringChars[i]);
       if (!str) {
@@ -413,17 +413,17 @@ ResolveWorkerClasses(JSContext* aCx, JSH
       shouldResolve = gStringIDs[ID_ChromeWorker] == aId ? isChrome : true;
       break;
     }
   }
 
   if (shouldResolve) {
     // Don't do anything if workers are disabled.
     if (!isChrome && !Preferences::GetBool(PREF_WORKERS_ENABLED)) {
-      *aObjp = nsnull;
+      aObjp.set(nsnull);
       return true;
     }
 
     JSObject* eventTarget = EventTargetBinding_workers::GetProtoObject(aCx, aObj, aObj);
     if (!eventTarget) {
       return false;
     }
 
@@ -435,22 +435,22 @@ ResolveWorkerClasses(JSContext* aCx, JSH
     if (isChrome && !chromeworker::InitClass(aCx, aObj, worker, true)) {
       return false;
     }
 
     if (!events::InitClasses(aCx, aObj, true)) {
       return false;
     }
 
-    *aObjp = aObj;
+    aObjp.set(aObj);
     return true;
   }
 
   // Not resolved.
-  *aObjp = nsnull;
+  aObjp.set(nsnull);
   return true;
 }
 
 void
 CancelWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow)
 {
   AssertIsOnMainThread();
   RuntimeService* runtime = RuntimeService::GetService();
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -782,24 +782,24 @@ private:
   {
     JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
                          Class()->name);
     return false;
   }
 
   static JSBool
   Resolve(JSContext* aCx, JSHandleObject aObj, JSHandleId aId, unsigned aFlags,
-          JSObject** aObjp)
+          JSMutableHandleObject aObjp)
   {
     JSBool resolved;
     if (!JS_ResolveStandardClass(aCx, aObj, aId, &resolved)) {
       return false;
     }
 
-    *aObjp = resolved ? aObj.value() : NULL;
+    aObjp.set(resolved ? aObj.value() : NULL);
     return true;
   }
 
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
     DedicatedWorkerGlobalScope* scope =
--- a/dom/workers/Workers.h
+++ b/dom/workers/Workers.h
@@ -40,17 +40,17 @@ AssertIsOnMainThread();
 inline void
 AssertIsOnMainThread()
 { }
 #endif
 
 // All of these are implemented in RuntimeService.cpp
 JSBool
 ResolveWorkerClasses(JSContext* aCx, JSHandleObject aObj, JSHandleId aId, unsigned aFlags,
-                     JSObject** aObjp);
+                     JSMutableHandleObject aObjp);
 
 void
 CancelWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
 
 void
 SuspendWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
 
 void
--- a/gfx/skia/src/xml/SkJS.cpp
+++ b/gfx/skia/src/xml/SkJS.cpp
@@ -79,26 +79,27 @@ global_enumerate(JSContext *cx, JSHandle
 #ifdef LAZY_STANDARD_CLASSES
     return JS_EnumerateStandardClasses(cx, obj);
 #else
     return JS_TRUE;
 #endif
 }
 
 static JSBool
-global_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags, JSObject **objp)
+global_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
+	       MutableHandleObject objp)
 {
 #ifdef LAZY_STANDARD_CLASSES
     if ((flags & JSRESOLVE_ASSIGNING) == 0) {
         JSBool resolved;
 
         if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
             return JS_FALSE;
         if (resolved) {
-            *objp = obj;
+            objp.set(obj);
             return JS_TRUE;
         }
     }
 #endif
 
 #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
     if ((flags & (JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING)) == 0) {
         /*
@@ -133,17 +134,17 @@ global_resolve(JSContext *cx, JSHandleOb
             }
             found = (access(full, X_OK) == 0);
             if (*comp != '\0')
                 free(full);
             if (found) {
                 fun = JS_DefineFunction(cx, obj, name, Exec, 0, JSPROP_ENUMERATE);
                 ok = (fun != NULL);
                 if (ok)
-                    *objp = obj;
+                    objp.set(obj);
                 break;
             }
         }
         JS_free(cx, path);
         return ok;
     }
 #else
     return JS_TRUE;
--- a/js/ipc/ObjectWrapperParent.cpp
+++ b/js/ipc/ObjectWrapperParent.cpp
@@ -293,33 +293,33 @@ JSObject_to_PObjectWrapperParent(JSObjec
     *to = owp;
     return true;
 }
 
 /*static*/ bool
 ObjectWrapperParent::
 JSObject_from_PObjectWrapperParent(JSContext* cx,
                                    const PObjectWrapperParent* from,
-                                   JSObject** to)
+                                   JSMutableHandleObject to)
 {
     const ObjectWrapperParent* owp =
         static_cast<const ObjectWrapperParent*>(from);
-    *to = owp
-        ? owp->GetJSObject(cx)
-        : JSVAL_TO_OBJECT(JSVAL_NULL);
+    to.set(owp
+           ? owp->GetJSObject(cx)
+           : JSVAL_TO_OBJECT(JSVAL_NULL));
     return true;
 }
 
 /*static*/ bool
 ObjectWrapperParent::
 jsval_from_PObjectWrapperParent(JSContext* cx,
                                 const PObjectWrapperParent* from,
                                 jsval* to)
 {
-    JSObject* obj;
+    JS::RootedObject obj(cx);
     if (!JSObject_from_PObjectWrapperParent(cx, from, &obj))
         return false;
     *to = OBJECT_TO_JSVAL(obj);
     return true;
 }
     
 static bool
 jsid_from_int(JSContext* cx, int from, jsid* to)
@@ -539,17 +539,17 @@ ObjectWrapperParent::CPOW_NewEnumerate(J
     }
 
     NS_NOTREACHED("Unknown enum_op value in CPOW_NewEnumerate");
     return JS_FALSE;
 }
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id,
-                                     unsigned flags, JSObject **objp)
+                                     unsigned flags, JSMutableHandleObject objp)
 {
     CPOW_LOG(("Calling CPOW_NewResolve (%s)...",
               JSVAL_TO_CSTR(cx, id)));
 
     ObjectWrapperParent* self = Unwrap(obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_NewResolve");
 
@@ -564,19 +564,20 @@ ObjectWrapperParent::CPOW_NewResolve(JSC
 
     if (!self->Manager()->RequestRunToCompletion() ||
         !self->CallNewResolve(in_id, flags,
                               aco.StatusPtr(), &out_pobj) ||
         !aco.Ok() ||
         !JSObject_from_PObjectWrapperParent(cx, out_pobj, objp))
         return JS_FALSE;
 
-    if (*objp) {
-        AutoResolveFlag arf(*objp);
-        JS_DefinePropertyById(cx, *objp, id, JSVAL_VOID, NULL, NULL,
+    if (objp) {
+        AutoResolveFlag arf(objp);
+        JS::RootedObject obj2(cx, objp);
+        JS_DefinePropertyById(cx, obj2, id, JSVAL_VOID, NULL, NULL,
                               JSPROP_ENUMERATE);
     }
     return JS_TRUE;
 }
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_Convert(JSContext *cx, JSHandleObject obj, JSType type,
                                   jsval *vp)
--- a/js/ipc/ObjectWrapperParent.h
+++ b/js/ipc/ObjectWrapperParent.h
@@ -75,17 +75,17 @@ private:
     JSBool NewEnumerateNext(JSContext* cx, jsval* statep, jsid* idp);
     JSBool NewEnumerateDestroy(JSContext* cx, jsval state);
     static JSBool
     CPOW_NewEnumerate(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op,
                       jsval *statep, jsid *idp);
 
     static JSBool
     CPOW_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
-                    JSObject **objp);
+                    JSMutableHandleObject objp);
 
     static JSBool
     CPOW_Convert(JSContext *cx, JSHandleObject obj, JSType type, jsval *vp);
 
     static void
     CPOW_Finalize(js::FreeOp* fop, JSObject* obj);
 
     static JSBool
@@ -103,17 +103,17 @@ private:
     static bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to);
     static bool jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
                                      jsval* to);
     static bool
     JSObject_to_PObjectWrapperParent(JSObject* from, PObjectWrapperParent** to);
     static bool
     JSObject_from_PObjectWrapperParent(JSContext* cx,
                                        const PObjectWrapperParent* from,
-                                       JSObject** to);
+                                       JSMutableHandleObject to);
     static bool
     jsval_from_PObjectWrapperParent(JSContext* cx,
                                     const PObjectWrapperParent* from,
                                     jsval* to);
 };
 
 template <class StatusOwnerPolicy>
 class AutoCheckOperationBase
--- a/js/src/gc/Root.h
+++ b/js/src/gc/Root.h
@@ -119,16 +119,54 @@ class Handle
 
 typedef Handle<JSObject*>    HandleObject;
 typedef Handle<JSFunction*>  HandleFunction;
 typedef Handle<JSScript*>    HandleScript;
 typedef Handle<JSString*>    HandleString;
 typedef Handle<jsid>         HandleId;
 typedef Handle<Value>        HandleValue;
 
+/*
+ * Similar to a handle, but the underlying storage can be changed. This is
+ * useful for outparams.
+ */
+template <typename T>
+class MutableHandle
+{
+  public:
+    template <typename S>
+    MutableHandle(MutableHandle<S> handle,
+                  typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0)
+    {
+        this->ptr = reinterpret_cast<const T *>(handle.address());
+    }
+
+    template <typename S>
+    inline
+    MutableHandle(Rooted<S> *root,
+                  typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
+
+    void set(T v) { *ptr = v; }
+
+    const T *address() const { return ptr; }
+    T *address() { return ptr; }
+    T value() const { return *ptr; }
+
+    operator T () const { return value(); }
+    T operator ->() const { return value(); }
+
+  private:
+    MutableHandle() {}
+
+    T *ptr;
+};
+
+typedef MutableHandle<JSObject*>    MutableHandleObject;
+typedef MutableHandle<Value>        MutableHandleValue;
+
 template <typename T>
 struct RootMethods<T *>
 {
     static T *initial() { return NULL; }
     static ThingRootKind kind() { return T::rootKind(); }
     static bool poisoned(T *v) { return IsPoisonedPtr(v); }
 };
 
@@ -204,16 +242,24 @@ class Rooted
 template<typename T> template <typename S>
 inline
 Handle<T>::Handle(Rooted<S> &root,
                   typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy)
 {
     ptr = reinterpret_cast<const T *>(root.address());
 }
 
+template<typename T> template <typename S>
+inline
+MutableHandle<T>::MutableHandle(Rooted<S> *root,
+                                typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy)
+{
+    ptr = root->address();
+}
+
 typedef Rooted<JSObject*>    RootedObject;
 typedef Rooted<JSFunction*>  RootedFunction;
 typedef Rooted<JSScript*>    RootedScript;
 typedef Rooted<JSString*>    RootedString;
 typedef Rooted<jsid>         RootedId;
 typedef Rooted<Value>        RootedValue;
 
 /*
--- a/js/src/jsapi-tests/testLookup.cpp
+++ b/js/src/jsapi-tests/testLookup.cpp
@@ -33,34 +33,35 @@ BEGIN_TEST(testLookup_bug522590)
     CHECK(funobj->isFunction());
     CHECK(!js::IsInternalFunctionObject(funobj));
 
     return true;
 }
 END_TEST(testLookup_bug522590)
 
 JSBool
-document_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags, JSObject **objp)
+document_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
+                 JSMutableHandleObject objp)
 {
     // If id is "all", and we're not detecting, resolve document.all=true.
     jsvalRoot v(cx);
     if (!JS_IdToValue(cx, id, v.addr()))
         return false;
     if (JSVAL_IS_STRING(v.value())) {
         JSString *str = JSVAL_TO_STRING(v.value());
         JSFlatString *flatStr = JS_FlattenString(cx, str);
         if (!flatStr)
             return false;
         if (JS_FlatStringEqualsAscii(flatStr, "all") && !(flags & JSRESOLVE_DETECTING)) {
             JSBool ok = JS_DefinePropertyById(cx, obj, id, JSVAL_TRUE, NULL, NULL, 0);
-            *objp = ok ? obj.value() : NULL;
+            objp.set(ok ? obj.value() : NULL);
             return ok;
         }
     }
-    *objp = NULL;
+    objp.set(NULL);
     return true;
 }
 
 static JSClass document_class = {
     "document", JSCLASS_NEW_RESOLVE,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, (JSResolveOp) document_resolve, JS_ConvertStub
 };
--- a/js/src/jsapi-tests/testResolveRecursion.cpp
+++ b/js/src/jsapi-tests/testResolveRecursion.cpp
@@ -64,17 +64,17 @@ struct AutoIncrCounters {
     ~AutoIncrCounters() {
         t->resolveExitCount++;
     }
 
     cls_testResolveRecursion *t;
 };
 
 bool
-doResolve(JSObject *obj, jsid id, unsigned flags, JSObject **objp)
+doResolve(JSObject *obj, jsid id, unsigned flags, JSMutableHandleObject objp)
 {
     CHECK_EQUAL(resolveExitCount, 0);
     AutoIncrCounters incr(this);
     CHECK_EQUAL(obj, obj1 || obj == obj2);
 
     CHECK(JSID_IS_STRING(id));
 
     JSFlatString *str = JS_FlattenString(cx, JSID_TO_STRING(id));
@@ -82,55 +82,56 @@ doResolve(JSObject *obj, jsid id, unsign
     jsval v;
     if (JS_FlatStringEqualsAscii(str, "x")) {
         if (obj == obj1) {
             /* First resolve hook invocation. */
             CHECK_EQUAL(resolveEntryCount, 1);
             EVAL("obj2.y = true", &v);
             CHECK_SAME(v, JSVAL_TRUE);
             CHECK(JS_DefinePropertyById(cx, obj, id, JSVAL_FALSE, NULL, NULL, 0));
-            *objp = obj;
+            objp.set(obj);
             return true;
         }
         if (obj == obj2) {
             CHECK_EQUAL(resolveEntryCount, 4);
-            *objp = NULL;
+            objp.set(NULL);
             return true;
         }
     } else if (JS_FlatStringEqualsAscii(str, "y")) {
         if (obj == obj2) {
             CHECK_EQUAL(resolveEntryCount, 2);
             CHECK(JS_DefinePropertyById(cx, obj, id, JSVAL_NULL, NULL, NULL, 0));
             EVAL("obj1.x", &v);
             CHECK(JSVAL_IS_VOID(v));
             EVAL("obj1.y", &v);
             CHECK_SAME(v, JSVAL_ZERO);
-            *objp = obj;
+            objp.set(obj);
             return true;
         }
         if (obj == obj1) {
             CHECK_EQUAL(resolveEntryCount, 3);
             EVAL("obj1.x", &v);
             CHECK(JSVAL_IS_VOID(v));
             EVAL("obj1.y", &v);
             CHECK(JSVAL_IS_VOID(v));
             EVAL("obj2.y", &v);
             CHECK(JSVAL_IS_NULL(v));
             EVAL("obj2.x", &v);
             CHECK(JSVAL_IS_VOID(v));
             EVAL("obj1.y = 0", &v);
             CHECK_SAME(v, JSVAL_ZERO);
-            *objp = obj;
+            objp.set(obj);
             return true;
         }
     }
     CHECK(false);
     return false;
 }
 
 static JSBool
-my_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags, JSObject **objp)
+my_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
+           JSMutableHandleObject objp)
 {
     return static_cast<cls_testResolveRecursion *>(JS_GetPrivate(obj))->
            doResolve(obj, id, flags, objp);
 }
 
 END_TEST(testResolveRecursion)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2125,22 +2125,26 @@ JS_EnumerateResolvedStandardClasses(JSCo
 }
 
 #undef CLASP
 #undef EAGER_ATOM
 #undef EAGER_CLASS_ATOM
 #undef EAGER_ATOM_CLASP
 
 JS_PUBLIC_API(JSBool)
-JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
-{
-    AssertNoGC(cx);
-    CHECK_REQUEST(cx);
+JS_GetClassObject(JSContext *cx, JSObject *obj_, JSProtoKey key, JSObject **objp_)
+{
+    AssertNoGC(cx);
+    CHECK_REQUEST(cx);
+    RootedObject obj(cx, obj_);
+    RootedObject objp(cx);
     assertSameCompartment(cx, obj);
-    return js_GetClassObject(cx, obj, key, objp);
+    bool result = js_GetClassObject(cx, obj, key, &objp);
+    *objp_ = objp;
+    return result;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetObjectPrototype(JSContext *cx, JSObject *forObj)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, forObj);
     return forObj->global().getOrCreateObjectPrototype(cx);
@@ -3387,17 +3391,17 @@ JS_DeepFreezeObject(JSContext *cx, JSObj
             return false;
     }
 
     return true;
 }
 
 static JSBool
 LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                   JSObject **objp, JSProperty **propp)
+                   MutableHandleObject objp, JSProperty **propp)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
 
     JSAutoResolveFlags rf(cx, flags);
     return obj->lookupGeneric(cx, id, objp, propp);
 }
@@ -3444,17 +3448,17 @@ LookupResult(JSContext *cx, HandleObject
 JS_PUBLIC_API(JSBool)
 JS_LookupPropertyById(JSContext *cx, JSObject *obj_, jsid id_, jsval *vp)
 {
     RootedId id(cx, id_);
     RootedObject obj(cx, obj_);
     RootedObject obj2(cx);
     JSProperty* prop;
 
-    return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, obj2.address(), &prop) &&
+    return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
            LookupResult(cx, obj, obj2, id, prop, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_LookupElement(JSContext *cx, JSObject *obj, uint32_t index, jsval *vp)
 {
     CHECK_REQUEST(cx);
     jsid id;
@@ -3486,18 +3490,18 @@ JS_LookupPropertyWithFlagsById(JSContext
     RootedObject objp(cx, *objp_);
     RootedId id(cx, id_);
     JSProperty* prop;
 
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     if (!(obj->isNative()
-          ? LookupPropertyWithFlags(cx, obj, id, flags, objp.address(), &prop)
-          : obj->lookupGeneric(cx, id, objp.address(), &prop)))
+          ? LookupPropertyWithFlags(cx, obj, id, flags, &objp, &prop)
+          : obj->lookupGeneric(cx, id, &objp, &prop)))
         return false;
 
     if (!LookupResult(cx, obj, objp, id, prop, vp))
         return false;
 
     *objp_ = objp;
     return true;
 }
@@ -3513,17 +3517,17 @@ JS_LookupPropertyWithFlags(JSContext *cx
 JS_PUBLIC_API(JSBool)
 JS_HasPropertyById(JSContext *cx, JSObject *obj_, jsid id_, JSBool *foundp)
 {
     RootedObject obj(cx, obj_);
     RootedId id(cx, id_);
     RootedObject obj2(cx);
     JSProperty* prop;
     JSBool ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
-                                   obj2.address(), &prop);
+                                   &obj2, &prop);
     *foundp = (prop != NULL);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_HasElement(JSContext *cx, JSObject *obj, uint32_t index, JSBool *foundp)
 {
     AssertNoGC(cx);
@@ -3555,17 +3559,17 @@ JS_AlreadyHasOwnPropertyById(JSContext *
     RootedId id(cx, id_);
     RootedObject obj(cx, obj_);
 
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
 
     if (!obj->isNative()) {
-        JSObject *obj2;
+        RootedObject obj2(cx);
         JSProperty *prop;
 
         if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
                                 &obj2, &prop)) {
             return JS_FALSE;
         }
         *foundp = (obj == obj2);
         return JS_TRUE;
@@ -3830,17 +3834,17 @@ JS_DefineProperties(JSContext *cx, JSObj
 
 static JSBool
 GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
                           JSBool own, PropertyDescriptor *desc)
 {
     RootedObject obj2(cx);
     JSProperty *prop;
 
-    if (!LookupPropertyById(cx, obj, id, flags, obj2.address(), &prop))
+    if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop))
         return JS_FALSE;
 
     if (!prop || (own && obj != obj2)) {
         desc->obj = NULL;
         desc->attrs = 0;
         desc->getter = NULL;
         desc->setter = NULL;
         desc->value.setUndefined();
@@ -3955,17 +3959,17 @@ JS_GetOwnPropertyDescriptor(JSContext *c
 }
 
 static JSBool
 SetPropertyAttributesById(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, JSBool *foundp)
 {
     RootedObject obj2(cx);
     JSProperty *prop;
 
-    if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, obj2.address(), &prop))
+    if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
         return false;
     if (!prop || obj != obj2) {
         *foundp = false;
         return true;
     }
     Shape *shape = (Shape *) prop;
     JSBool ok = obj->isNative()
                 ? obj->changePropertyAttributes(cx, shape, attrs)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1384,30 +1384,35 @@ JS_STATIC_ASSERT(sizeof(JSLayoutAlignmen
 JS_STATIC_ASSERT(sizeof(jsval_layout) == sizeof(jsval));
 
 /************************************************************************/
 
 #ifdef __cplusplus
 
 typedef JS::Handle<JSObject*> JSHandleObject;
 typedef JS::Handle<jsid> JSHandleId;
+typedef JS::MutableHandle<JSObject*> JSMutableHandleObject;
 
 #else
 
 /*
  * Handle support for C API users. Handles must be destroyed in the reverse
  * order that they were created (as in a stack).
  */
 
 typedef struct { JSObject **_; } JSHandleObject;
+typedef struct { JSObject **_; } JSMutableHandleObject;
 typedef struct { jsid *_; } JSHandleId;
 
 JSBool JS_CreateHandleObject(JSContext *cx, JSObject *obj, JSHandleObject *phandle);
 void JS_DestroyHandleObject(JSContext *cx, JSHandleObject handle);
 
+JSBool JS_CreateMutableHandleObject(JSContext *cx, JSObject *obj, JSMutableHandleObject *phandle);
+void JS_DestroyMutableHandleObject(JSContext *cx, JSMutableHandleObject handle);
+
 JSBool JS_CreateHandleId(JSContext *cx, jsid id, JSHandleId *phandle);
 void JS_DestroyHandleId(JSContext *cx, JSHandleId handle);
 
 #endif
 
 /* JSClass operation signatures. */
 
 /*
@@ -1499,17 +1504,17 @@ typedef JSBool
  * was not resolved; and non-null, referring to obj or one of its prototypes,
  * if id was resolved.  The hook may assume *objp is null on entry.
  *
  * This hook instead of JSResolveOp is called via the JSClass.resolve member
  * if JSCLASS_NEW_RESOLVE is set in JSClass.flags.
  */
 typedef JSBool
 (* JSNewResolveOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
-                   JSObject **objp);
+                   JSMutableHandleObject objp);
 
 /*
  * Convert obj to the given type, returning true with the resulting value in
  * *vp on success, and returning false on error or exception.
  */
 typedef JSBool
 (* JSConvertOp)(JSContext *cx, JSHandleObject obj, JSType type, jsval *vp);
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -341,17 +341,17 @@ DoGetElement(JSContext *cx, JSObject *ob
     *hole = JS_FALSE;
     if (!IndexToId(cx, obj, index, hole, id.address()))
         return JS_FALSE;
     if (*hole) {
         vp->setUndefined();
         return JS_TRUE;
     }
 
-    JSObject *obj2;
+    RootedObject obj2(cx);
     JSProperty *prop;
     if (!obj->lookupGeneric(cx, id, &obj2, &prop))
         return JS_FALSE;
     if (!prop) {
         vp->setUndefined();
         *hole = JS_TRUE;
     } else {
         if (!obj->getGeneric(cx, id, vp))
@@ -687,68 +687,68 @@ IsDenseArrayId(JSContext *cx, JSObject *
     JS_ASSERT(obj->isDenseArray());
 
     uint32_t i;
     return JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
            (js_IdIsIndex(id, &i) && IsDenseArrayIndex(obj, i));
 }
 
 static JSBool
-array_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp,
+array_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
                     JSProperty **propp)
 {
     if (!obj->isDenseArray())
         return baseops::LookupProperty(cx, obj, id, objp, propp);
 
     if (IsDenseArrayId(cx, obj, id)) {
         *propp = (JSProperty *) 1;  /* non-null to indicate found */
-        *objp = obj;
+        objp.set(obj);
         return JS_TRUE;
     }
 
     JSObject *proto = obj->getProto();
     if (!proto) {
-        *objp = NULL;
+        objp.set(NULL);
         *propp = NULL;
         return JS_TRUE;
     }
     return proto->lookupGeneric(cx, id, objp, propp);
 }
 
 static JSBool
-array_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSObject **objp,
-                     JSProperty **propp)
+array_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                     MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return array_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
-array_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, JSObject **objp,
+array_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp,
                     JSProperty **propp)
 {
     if (!obj->isDenseArray())
         return baseops::LookupElement(cx, obj, index, objp, propp);
 
     if (IsDenseArrayIndex(obj, index)) {
         *propp = (JSProperty *) 1;  /* non-null to indicate found */
-        *objp = obj;
+        objp.set(obj);
         return true;
     }
 
     if (JSObject *proto = obj->getProto())
         return proto->lookupElement(cx, index, objp, propp);
 
-    *objp = NULL;
+    objp.set(NULL);
     *propp = NULL;
     return true;
 }
 
 static JSBool
-array_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSObject **objp,
+array_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, MutableHandleObject objp,
                     JSProperty **propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return array_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id, Value *vp)
@@ -3768,21 +3768,21 @@ NewArray(JSContext *cx, uint32_t length,
         obj->setFixedElements();
         obj->setArrayLength(cx, length);
         if (allocateCapacity && !EnsureNewArrayElements(cx, obj, length))
             return NULL;
         return obj;
     }
 
     Rooted<GlobalObject*> parent(cx, parent_);
-
-    if (!proto_ && !FindProto(cx, &ArrayClass, parent, &proto_))
+    RootedObject proto(cx, proto_);
+
+    if (!proto && !FindProto(cx, &ArrayClass, parent, &proto))
         return NULL;
 
-    RootedObject proto(cx, proto_);
     RootedTypeObject type(cx);
 
     type = proto->getNewType(cx);
     if (!type)
         return NULL;
 
     /*
      * Get a shape with zero fixed slots, regardless of the size class.
--- a/js/src/jsclass.h
+++ b/js/src/jsclass.h
@@ -144,26 +144,26 @@ JSID_TO_SPECIALID(jsid id)
     return SpecialId::defaultXMLNamespace();
 }
 
 typedef JS::Handle<SpecialId> HandleSpecialId;
 
 /* js::Class operation signatures. */
 
 typedef JSBool
-(* LookupGenericOp)(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp,
+(* LookupGenericOp)(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
                     JSProperty **propp);
 typedef JSBool
-(* LookupPropOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, JSObject **objp,
+(* LookupPropOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleObject objp,
                  JSProperty **propp);
 typedef JSBool
-(* LookupElementOp)(JSContext *cx, HandleObject obj, uint32_t index, JSObject **objp,
+(* LookupElementOp)(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp,
                     JSProperty **propp);
 typedef JSBool
-(* LookupSpecialOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSObject **objp,
+(* LookupSpecialOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid, MutableHandleObject objp,
                     JSProperty **propp);
 typedef JSBool
 (* DefineGenericOp)(JSContext *cx, HandleObject obj, HandleId id, const Value *value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
 typedef JSBool
 (* DefinePropOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, const Value *value,
                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
 typedef JSBool
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -553,17 +553,17 @@ JSStructuredCloneWriter::write(const Val
             ids.popBack();
             checkStack();
             if (JSID_IS_STRING(id) || JSID_IS_INT(id)) {
                 /*
                  * If obj still has an own property named id, write it out.
                  * The cost of re-checking could be avoided by using
                  * NativeIterators.
                  */
-                JSObject *obj2;
+                RootedObject obj2(context());
                 JSProperty *prop;
                 if (!js_HasOwnProperty(context(), obj->getOps()->lookupGeneric, obj, id,
                                        &obj2, &prop)) {
                     return false;
                 }
 
                 if (prop) {
                     Value val;
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -170,18 +170,23 @@ JSCompartment::wrap(JSContext *cx, Value
     /* Unwrap incoming objects. */
     if (vp->isObject()) {
         Rooted<JSObject*> obj(cx, &vp->toObject());
 
         if (obj->compartment() == this)
             return WrapForSameCompartment(cx, obj, vp);
 
         /* Translate StopIteration singleton. */
-        if (obj->isStopIteration())
-            return js_FindClassObject(cx, NULL, JSProto_StopIteration, vp);
+        if (obj->isStopIteration()) {
+            RootedObject null(cx);
+            RootedValue vvp(cx, *vp);
+            bool result = js_FindClassObject(cx, null, JSProto_StopIteration, &vvp);
+            *vp = vvp;
+            return result;
+        }
 
         /* Unwrap the object, but don't unwrap outer windows. */
         obj = UnwrapObject(&vp->toObject(), /* stopAtOuter = */ true, &flags);
 
         if (obj->compartment() == this)
             return WrapForSameCompartment(cx, obj, vp);
 
         if (cx->runtime->preWrapObjectCallback) {
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -52,17 +52,17 @@ Exception(JSContext *cx, unsigned argc, 
 static void
 exn_trace(JSTracer *trc, JSObject *obj);
 
 static void
 exn_finalize(FreeOp *fop, JSObject *obj);
 
 static JSBool
 exn_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-            JSObject **objp);
+            MutableHandleObject objp);
 
 Class js::ErrorClass = {
     js_Error_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Error),
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
@@ -387,27 +387,27 @@ exn_finalize(FreeOp *fop, JSObject *obj)
             fop->free_(report);
         }
         fop->free_(priv);
     }
 }
 
 static JSBool
 exn_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-            JSObject **objp)
+            MutableHandleObject objp)
 {
     JSExnPrivate *priv;
     JSString *str;
     JSAtom *atom;
     JSString *stack;
     const char *prop;
     jsval v;
     unsigned attrs;
 
-    *objp = NULL;
+    objp.set(NULL);
     priv = GetExnPrivate(obj);
     if (priv && JSID_IS_ATOM(id)) {
         str = JSID_TO_STRING(id);
 
         atom = cx->runtime->atomState.messageAtom;
         if (str == atom) {
             prop = js_message_str;
 
@@ -452,17 +452,17 @@ exn_resolve(JSContext *cx, HandleObject 
             goto define;
         }
     }
     return true;
 
   define:
     if (!JS_DefineProperty(cx, obj, prop, v, NULL, NULL, attrs))
         return false;
-    *objp = obj;
+    objp.set(obj);
     return true;
 }
 
 JSErrorReport *
 js_ErrorFromException(JSContext *cx, jsval exn)
 {
     JSObject *obj;
     JSExnPrivate *priv;
@@ -913,17 +913,16 @@ struct AutoSetGeneratingError
 JSBool
 js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
                     JSErrorCallback callback, void *userRef)
 {
     JSErrNum errorNumber;
     const JSErrorFormatString *errorString;
     JSExnType exn;
     jsval tv[4];
-    JSObject *errProto;
 
     /*
      * Tell our caller to report immediately if this report is just a warning.
      */
     JS_ASSERT(reportp);
     if (JSREPORT_IS_WARNING(reportp->flags))
         return false;
 
@@ -959,17 +958,19 @@ js_ErrorToException(JSContext *cx, const
     PodArrayZero(tv);
     AutoArrayRooter tvr(cx, ArrayLength(tv), tv);
 
     /*
      * Try to get an appropriate prototype by looking up the corresponding
      * exception constructor name in the scope chain of the current context's
      * top stack frame, or in the global object if no frame is active.
      */
-    if (!js_GetClassPrototype(cx, NULL, GetExceptionProtoKey(exn), &errProto))
+    RootedObject null(cx);
+    RootedObject errProto(cx);
+    if (!js_GetClassPrototype(cx, null, GetExceptionProtoKey(exn), &errProto))
         return false;
     tv[0] = OBJECT_TO_JSVAL(errProto);
 
     RootedObject errObject(cx, NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL));
     if (!errObject)
         return false;
     tv[1] = OBJECT_TO_JSVAL(errObject);
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -251,17 +251,17 @@ ResolveInterpretedFunctionPrototype(JSCo
        return NULL;
     }
 
     return proto;
 }
 
 static JSBool
 fun_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-            JSObject **objp)
+            MutableHandleObject objp)
 {
     if (!JSID_IS_ATOM(id))
         return true;
 
     RootedFunction fun(cx);
     fun = obj->toFunction();
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.classPrototypeAtom)) {
@@ -277,17 +277,17 @@ fun_resolve(JSContext *cx, HandleObject 
          * isNative() test covers this case because bound functions are native
          * functions by definition/construction.
          */
         if (fun->isNative() || fun->isFunctionPrototype())
             return true;
 
         if (!ResolveInterpretedFunctionPrototype(cx, fun))
             return false;
-        *objp = fun;
+        objp.set(fun);
         return true;
     }
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
         JSID_IS_ATOM(id, cx->runtime->atomState.nameAtom)) {
         JS_ASSERT(!IsInternalFunctionObject(obj));
 
         Value v;
@@ -295,17 +295,17 @@ fun_resolve(JSContext *cx, HandleObject 
             v.setInt32(fun->nargs - fun->hasRest());
         else
             v.setString(fun->atom ? fun->atom : cx->runtime->emptyString);
 
         if (!DefineNativeProperty(cx, fun, id, v, JS_PropertyStub, JS_StrictPropertyStub,
                                   JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
             return false;
         }
-        *objp = fun;
+        objp.set(fun);
         return true;
     }
 
     for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
         const uint16_t offset = poisonPillProps[i];
 
         if (JSID_IS_ATOM(id, OFFSET_TO_NAME(cx->runtime, offset))) {
             JS_ASSERT(!IsInternalFunctionObject(fun));
@@ -323,17 +323,17 @@ fun_resolve(JSContext *cx, HandleObject 
                 getter = fun_getProperty;
                 setter = JS_StrictPropertyStub;
             }
 
             if (!DefineNativeProperty(cx, fun, id, UndefinedValue(), getter, setter,
                                       attrs, 0, 0)) {
                 return false;
             }
-            *objp = fun;
+            objp.set(fun);
             return true;
         }
     }
 
     return true;
 }
 
 template<XDRMode mode>
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1857,18 +1857,19 @@ TypeCompartment::newAllocationSiteTypeOb
             cx->compartment->types.setPendingNukeTypes(cx);
             return NULL;
         }
     }
 
     AllocationSiteTable::AddPtr p = allocationSiteTable->lookupForAdd(key);
     JS_ASSERT(!p);
 
-    JSObject *proto;
-    if (!js_GetClassPrototype(cx, key.script->global(), key.kind, &proto, NULL))
+    RootedObject proto(cx);
+    RootedObject global(cx, key.script->global());
+    if (!js_GetClassPrototype(cx, global, key.kind, &proto, NULL))
         return NULL;
 
     RootedScript keyScript(cx, key.script);
     TypeObject *res = newTypeObject(cx, key.script, key.kind, proto);
     if (!res) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return NULL;
     }
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -259,18 +259,19 @@ struct AutoEnterCompilation
 
 /*
  * Get the default 'new' object for a given standard class, per the currently
  * active global.
  */
 inline TypeObject *
 GetTypeNewObject(JSContext *cx, JSProtoKey key)
 {
-    JSObject *proto;
-    if (!js_GetClassPrototype(cx, NULL, key, &proto, NULL))
+    RootedObject proto(cx);
+    RootedObject null(cx);
+    if (!js_GetClassPrototype(cx, null, key, &proto))
         return NULL;
     return proto->getNewType(cx);
 }
 
 /* Get a type object for the immediate allocation site within a native. */
 inline TypeObject *
 GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
 {
@@ -497,18 +498,19 @@ TypeScript::SlotTypes(JSScript *script, 
 {
     JS_ASSERT(slot < js::analyze::TotalSlots(script));
     return script->types->typeArray() + script->nTypeSets + slot;
 }
 
 /* static */ inline TypeObject *
 TypeScript::StandardType(JSContext *cx, JSScript *script, JSProtoKey key)
 {
-    JSObject *proto;
-    if (!js_GetClassPrototype(cx, script->global(), key, &proto, NULL))
+    RootedObject proto(cx);
+    RootedObject global(cx, script->global());
+    if (!js_GetClassPrototype(cx, global, key, &proto, NULL))
         return NULL;
     return proto->getNewType(cx);
 }
 
 struct AllocationSiteKey {
     JSScript *script;
 
     uint32_t offset : 24;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -945,17 +945,18 @@ js::AssertValidPropertyCacheHit(JSContex
     JSScript *script = cx->stack.currentScript(&pc);
 
     uint64_t sample = cx->runtime->gcNumber;
     PropertyCacheEntry savedEntry = *entry;
 
     RootedPropertyName name(cx, GetNameFromBytecode(cx, script, pc, JSOp(*pc)));
     RootedObject start(cx, start_);
 
-    JSObject *obj, *pobj;
+    RootedObject obj(cx);
+    RootedObject pobj(cx);
     JSProperty *prop;
     JSBool ok;
 
     if (JOF_OPMODE(*pc) == JOF_NAME)
         ok = FindProperty(cx, name, start, &obj, &pobj, &prop);
     else
         ok = baseops::LookupProperty(cx, start, name.reference(), &pobj, &prop);
     JS_ASSERT(ok);
@@ -1268,17 +1269,17 @@ js::Interpret(JSContext *cx, StackFrame 
      * Pool of rooters for use in this interpreter frame. References to these
      * are used for local variables within interpreter cases. This avoids
      * creating new rooters each time an interpreter case is entered, and also
      * correctness pitfalls due to incorrect compilation of destructor calls
      * around computed gotos.
      */
     RootedValue rootValue0(cx), rootValue1(cx);
     RootedString rootString0(cx), rootString1(cx);
-    RootedObject rootObject0(cx), rootObject1(cx);
+    RootedObject rootObject0(cx), rootObject1(cx), rootObject2(cx);
     RootedFunction rootFunction0(cx);
     RootedTypeObject rootType0(cx);
     RootedPropertyName rootName0(cx);
     RootedId rootId0(cx);
 
     if (rt->profilingScripts)
         ENABLE_INTERRUPTS();
 
@@ -1737,17 +1738,17 @@ BEGIN_CASE(JSOP_IN)
     if (!rref.isObject()) {
         js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
         goto error;
     }
     RootedObject &obj = rootObject0;
     obj = &rref.toObject();
     RootedId &id = rootId0;
     FETCH_ELEMENT_ID(obj, -2, id);
-    JSObject *obj2;
+    RootedObject &obj2 = rootObject1;
     JSProperty *prop;
     if (!obj->lookupGeneric(cx, id, &obj2, &prop))
         goto error;
     bool cond = prop != NULL;
     TRY_BRANCH_AFTER_COND(cond, 2);
     regs.sp--;
     regs.sp[-1].setBoolean(cond);
 }
@@ -2196,17 +2197,18 @@ END_CASE(JSOP_POS)
 BEGIN_CASE(JSOP_DELNAME)
 {
     RootedPropertyName &name = rootName0;
     LOAD_NAME(0, name);
 
     RootedObject &scopeObj = rootObject0;
     scopeObj = cx->stack.currentScriptedScopeChain();
 
-    JSObject *obj, *obj2;
+    RootedObject &obj = rootObject1;
+    RootedObject &obj2 = rootObject2;
     JSProperty *prop;
     if (!FindProperty(cx, name, scopeObj, &obj, &obj2, &prop))
         goto error;
 
     /* Strict mode code should never contain JSOP_DELNAME opcodes. */
     JS_ASSERT(!script->strictModeCode);
 
     /* ECMA says to return true if name is undefined or inherited. */
@@ -2542,17 +2544,18 @@ END_CASE(JSOP_SETCALL)
 BEGIN_CASE(JSOP_IMPLICITTHIS)
 {
     RootedPropertyName &name = rootName0;
     LOAD_NAME(0, name);
 
     RootedObject &scopeObj = rootObject0;
     scopeObj = cx->stack.currentScriptedScopeChain();
 
-    JSObject *obj, *obj2;
+    RootedObject &obj = rootObject1;
+    RootedObject &obj2 = rootObject2;
     JSProperty *prop;
     if (!FindPropertyHelper(cx, name, false, scopeObj, &obj, &obj2, &prop))
         goto error;
 
     Value v;
     if (!ComputeImplicitThis(cx, obj, &v))
         goto error;
     PUSH_COPY(v);
@@ -2911,17 +2914,17 @@ BEGIN_CASE(JSOP_DEFFUN)
      */
     RootedObject &parent = rootObject0;
     parent = &regs.fp()->varObj();
 
     /* ES5 10.5 (NB: with subsequent errata). */
     RootedPropertyName &name = rootName0;
     name = fun->atom->asPropertyName();
     JSProperty *prop = NULL;
-    JSObject *pobj;
+    RootedObject &pobj = rootObject1;
     if (!parent->lookupProperty(cx, name, &pobj, &prop))
         goto error;
 
     RootedValue &rval = rootValue0;
     rval = ObjectValue(*fun);
 
     do {
         /* Steps 5d, 5f. */
@@ -3473,17 +3476,17 @@ BEGIN_CASE(JSOP_ADDATTRVAL)
 END_CASE(JSOP_ADDATTRNAME)
 
 BEGIN_CASE(JSOP_BINDXMLNAME)
 {
     JS_ASSERT(!script->strictModeCode);
 
     Value lval;
     lval = regs.sp[-1];
-    JSObject *obj;
+    RootedObject &obj = rootObject0;
     jsid id;
     if (!js_FindXMLProperty(cx, lval, &obj, &id))
         goto error;
     regs.sp[-1].setObjectOrNull(obj);
     PUSH_COPY(IdToValue(id));
 }
 END_CASE(JSOP_BINDXMLNAME)
 
@@ -3504,17 +3507,17 @@ BEGIN_CASE(JSOP_SETXMLNAME)
 END_CASE(JSOP_SETXMLNAME)
 
 BEGIN_CASE(JSOP_CALLXMLNAME)
 BEGIN_CASE(JSOP_XMLNAME)
 {
     JS_ASSERT(!script->strictModeCode);
 
     Value lval = regs.sp[-1];
-    JSObject *obj;
+    RootedObject &obj = rootObject0;
     RootedId &id = rootId0;
     if (!js_FindXMLProperty(cx, lval, &obj, id.address()))
         goto error;
     Value rval;
     if (!obj->getGeneric(cx, id, &rval))
         goto error;
     regs.sp[-1] = rval;
     if (op == JSOP_CALLXMLNAME) {
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -381,17 +381,17 @@ NameOperation(JSContext *cx, JSScript *s
     if (!name) {
         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
         if (!NativeGet(cx, obj, obj2, entry->prop, 0, vp))
             return false;
         return true;
     }
 
     JSProperty *prop;
-    if (!FindPropertyHelper(cx, name, true, obj, obj.address(), obj2.address(), &prop))
+    if (!FindPropertyHelper(cx, name, true, obj, &obj, &obj2, &prop))
         return false;
     if (!prop) {
         /* Kludge to allow (typeof foo == "undefined") tests. */
         JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
         if (op2 == JSOP_TYPEOF) {
             vp->setUndefined();
             return true;
         }
@@ -420,17 +420,17 @@ NameOperation(JSContext *cx, JSScript *s
 
 inline bool
 DefVarOrConstOperation(JSContext *cx, HandleObject varobj, PropertyName *dn, unsigned attrs)
 {
     JS_ASSERT(varobj->isVarObj());
     JS_ASSERT(!varobj->getOps()->defineProperty || varobj->isDebugScope());
 
     JSProperty *prop;
-    JSObject *obj2;
+    RootedObject obj2(cx);
     if (!varobj->lookupProperty(cx, dn, &obj2, &prop))
         return false;
 
     /* Steps 8c, 8d. */
     if (!prop || (obj2 != varobj && varobj->isGlobal())) {
         if (!varobj->defineProperty(cx, dn, UndefinedValue(), JS_PropertyStub,
                                     JS_StrictPropertyStub, attrs)) {
             return false;
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -810,20 +810,20 @@ Iterator(JSContext *cx, unsigned argc, V
         return false;
     args.rval() = args[0];
     return true;
 }
 
 JSBool
 js_ThrowStopIteration(JSContext *cx)
 {
-    Value v;
-
     JS_ASSERT(!JS_IsExceptionPending(cx));
-    if (js_FindClassObject(cx, NULL, JSProto_StopIteration, &v))
+    RootedValue v(cx);
+    RootedObject null(cx);
+    if (js_FindClassObject(cx, null, JSProto_StopIteration, &v))
         cx->setPendingException(v);
     return JS_FALSE;
 }
 
 static JSBool
 iterator_next(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -987,17 +987,17 @@ SuppressDeletedPropertyHelper(JSContext 
             for (HeapPtr<JSFlatString> *idp = props_cursor; idp < props_end; ++idp) {
                 if (predicate(*idp)) {
                     /*
                      * Check whether another property along the prototype chain
                      * became visible as a result of this deletion.
                      */
                     if (obj->getProto()) {
                         JSObject *proto = obj->getProto();
-                        JSObject *obj2;
+                        RootedObject obj2(cx);
                         JSProperty *prop;
                         RootedId id(cx);
                         if (!ValueToId(cx, StringValue(*idp), id.address()))
                             return false;
                         if (!proto->lookupGeneric(cx, id, &obj2, &prop))
                             return false;
                         if (prop) {
                             unsigned attrs;
@@ -1765,17 +1765,17 @@ js_InitIteratorClasses(JSContext *cx, JS
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
 
     /*
      * Bail if Iterator has already been initialized.  We test for Iterator
      * rather than for StopIteration because if js_InitIteratorClasses recurs,
      * as happens when the StopIteration object is frozen, initializing the
      * Iterator class a second time will assert.
      */
-    JSObject *iter;
+    RootedObject iter(cx);
     if (!js_GetClassObject(cx, global, JSProto_Iterator, &iter))
         return NULL;
     if (iter)
         return iter;
 
     if (!InitIteratorClass(cx, global) || !GlobalObject::initGeneratorClass(cx, global))
         return NULL;
     return InitStopIterationClass(cx, global);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -173,17 +173,17 @@ MarkSharpObjects(JSContext *cx, HandleOb
         ida = JS_Enumerate(cx, obj);
         if (!ida)
             return false;
 
         bool ok = true;
         RootedId id(cx);
         for (int i = 0, length = ida->length; i < length; i++) {
             id = ida->vector[i];
-            JSObject *obj2;
+            RootedObject obj2(cx);
             JSProperty *prop;
             ok = obj->lookupGeneric(cx, id, &obj2, &prop);
             if (!ok)
                 break;
             if (!prop)
                 continue;
             bool hasGetter, hasSetter;
             RootedValue valueRoot(cx), setterRoot(cx);
@@ -454,17 +454,17 @@ obj_toSource(JSContext *cx, unsigned arg
     val = localroot + 2;
 
     RootedId id(cx);
     for (int i = 0; i < ida->length; i++) {
         /* Get strings for id and value and GC-root them via vp. */
         id = ida->vector[i];
         JSLinearString *idstr;
 
-        JSObject *obj2;
+        RootedObject obj2(cx);
         JSProperty *prop;
         if (!obj->lookupGeneric(cx, id, &obj2, &prop))
             return false;
 
         /*
          * Convert id to a value and then to a string.  Decide early whether we
          * prefer get/set or old getter/setter syntax.
          */
@@ -1254,58 +1254,58 @@ js_HasOwnPropertyHelper(JSContext *cx, L
 {
     RootedId id(cx);
     if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), id.address()))
         return JS_FALSE;
 
     RootedObject obj(cx, ToObject(cx, &vp[1]));
     if (!obj)
         return false;
-    JSObject *obj2;
+    RootedObject obj2(cx);
     JSProperty *prop;
     if (obj->isProxy()) {
         bool has;
         if (!Proxy::hasOwn(cx, obj, id, &has))
             return false;
         vp->setBoolean(has);
         return true;
     }
     if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop))
         return JS_FALSE;
     vp->setBoolean(!!prop);
     return JS_TRUE;
 }
 
 JSBool
 js_HasOwnProperty(JSContext *cx, LookupGenericOp lookup, HandleObject obj, HandleId id,
-                  JSObject **objp, JSProperty **propp)
+                  MutableHandleObject objp, JSProperty **propp)
 {
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING);
     if (lookup) {
         if (!lookup(cx, obj, id, objp, propp))
             return false;
     } else {
         if (!baseops::LookupProperty(cx, obj, id, objp, propp))
             return false;
     }
     if (!*propp)
         return true;
 
-    if (*objp == obj)
+    if (objp == obj)
         return true;
 
     JSObject *outer = NULL;
-    if (JSObjectOp op = (*objp)->getClass()->ext.outerObject) {
-        Rooted<JSObject*> inner(cx, *objp);
+    if (JSObjectOp op = objp->getClass()->ext.outerObject) {
+        Rooted<JSObject*> inner(cx, objp);
         outer = op(cx, inner);
         if (!outer)
             return false;
     }
 
-    if (outer != *objp)
+    if (outer != objp)
         *propp = NULL;
     return true;
 }
 
 /* ES5 15.2.4.6. */
 static JSBool
 obj_isPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
 {
@@ -1341,17 +1341,17 @@ obj_propertyIsEnumerable(JSContext *cx, 
 
     /* Steps 3-5. */
     return js_PropertyIsEnumerable(cx, obj, id, vp);
 }
 
 JSBool
 js_PropertyIsEnumerable(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
 {
-    JSObject *pobj;
+    RootedObject pobj(cx);
     JSProperty *prop;
     if (!obj->lookupGeneric(cx, id, &pobj, &prop))
         return false;
 
     if (!prop) {
         vp->setBoolean(false);
         return true;
     }
@@ -1451,17 +1451,17 @@ obj_lookupGetter(JSContext *cx, unsigned
         vp->setUndefined();
         PropertyDescriptor desc;
         if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
             return JS_FALSE;
         if (desc.obj && (desc.attrs & JSPROP_GETTER) && desc.getter)
             *vp = CastAsObjectJsval(desc.getter);
         return JS_TRUE;
     }
-    JSObject *pobj;
+    RootedObject pobj(cx);
     JSProperty *prop;
     if (!obj->lookupGeneric(cx, id, &pobj, &prop))
         return JS_FALSE;
     vp->setUndefined();
     if (prop) {
         if (pobj->isNative()) {
             Shape *shape = (Shape *) prop;
             if (shape->hasGetterValue())
@@ -1486,17 +1486,17 @@ obj_lookupSetter(JSContext *cx, unsigned
         vp->setUndefined();
         PropertyDescriptor desc;
         if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
             return JS_FALSE;
         if (desc.obj && (desc.attrs & JSPROP_SETTER) && desc.setter)
             *vp = CastAsObjectJsval(desc.setter);
         return JS_TRUE;
     }
-    JSObject *pobj;
+    RootedObject pobj(cx);
     JSProperty *prop;
     if (!obj->lookupGeneric(cx, id, &pobj, &prop))
         return JS_FALSE;
     vp->setUndefined();
     if (prop) {
         if (pobj->isNative()) {
             Shape *shape = (Shape *) prop;
             if (shape->hasSetterValue())
@@ -1618,17 +1618,17 @@ PropDesc::makeObject(JSContext *cx)
 }
 
 bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, PropertyDescriptor *desc)
 {
     if (obj->isProxy())
         return Proxy::getOwnPropertyDescriptor(cx, obj, id, false, desc);
 
-    JSObject *pobj;
+    RootedObject pobj(cx);
     JSProperty *prop;
     if (!js_HasOwnProperty(cx, obj->getOps()->lookupGeneric, obj, id, &pobj, &prop))
         return false;
     if (!prop) {
         desc->obj = NULL;
         return true;
     }
 
@@ -1659,17 +1659,18 @@ bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
 {
     AutoPropertyDescriptorRooter desc(cx);
     return GetOwnPropertyDescriptor(cx, obj, id, &desc) &&
            NewPropertyDescriptorObject(cx, &desc, vp);
 }
 
 bool
-GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *method, JSObject **objp)
+GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *method,
+                         MutableHandleObject objp)
 {
     if (argc == 0) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              method, "0", "s");
         return false;
     }
 
     const Value &v = vp[2];
@@ -1678,38 +1679,38 @@ GetFirstArgumentAsObject(JSContext *cx, 
         if (!bytes)
             return false;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                              bytes, "not an object");
         JS_free(cx, bytes);
         return false;
     }
 
-    *objp = &v.toObject();
+    objp.set(&v.toObject());
     return true;
 }
 
 } /* namespace js */
 
 static JSBool
 obj_getOwnPropertyDescriptor(JSContext *cx, unsigned argc, Value *vp)
 {
     RootedObject obj(cx);
-    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyDescriptor", obj.address()))
+    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyDescriptor", &obj))
         return JS_FALSE;
     RootedId id(cx);
     if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), id.address()))
         return JS_FALSE;
     return GetOwnPropertyDescriptor(cx, obj, id, vp);
 }
 
 static JSBool
 obj_keys(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj;
+    RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.keys", &obj))
         return false;
 
     AutoIdVector props(cx);
     if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props))
         return false;
 
     AutoValueVector vals(cx);
@@ -1959,17 +1960,17 @@ js::CheckDefineProperty(JSContext *cx, H
 static JSBool
 DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &desc,
                        bool throwError, bool *rval)
 {
     /* 8.12.9 step 1. */
     JSProperty *current;
     RootedObject obj2(cx);
     JS_ASSERT(!obj->getOps()->lookupGeneric);
-    if (!js_HasOwnProperty(cx, NULL, obj, id, obj2.address(), &current))
+    if (!js_HasOwnProperty(cx, NULL, obj, id, &obj2, &current))
         return JS_FALSE;
 
     JS_ASSERT(!obj->getOps()->defineProperty);
 
     /* 8.12.9 steps 2-4. */
     if (!current) {
         if (!obj->isExtensible())
             return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
@@ -2337,17 +2338,17 @@ js_DefineOwnProperty(JSContext *cx, Hand
     return true;
 }
 
 /* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */
 static JSBool
 obj_defineProperty(JSContext *cx, unsigned argc, Value *vp)
 {
     RootedObject obj(cx);
-    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperty", obj.address()))
+    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperty", &obj))
         return false;
 
     RootedId id(cx);
     if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), id.address()))
         return JS_FALSE;
 
     const Value descval = argc >= 3 ? vp[4] : UndefinedValue();
 
@@ -2405,17 +2406,17 @@ js_PopulateObject(JSContext *cx, HandleO
 }
 
 /* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
 static JSBool
 obj_defineProperties(JSContext *cx, unsigned argc, Value *vp)
 {
     /* Steps 1 and 7. */
     RootedObject obj(cx);
-    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperties", obj.address()))
+    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperties", &obj))
         return false;
     vp->setObject(*obj);
 
     /* Step 2. */
     if (argc < 2) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "Object.defineProperties", "0", "s");
         return false;
@@ -2484,17 +2485,17 @@ obj_create(JSContext *cx, unsigned argc,
     /* 5. Return obj. */
     args.rval().setObject(*obj);
     return true;
 }
 
 static JSBool
 obj_getOwnPropertyNames(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj;
+    RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyNames", &obj))
         return false;
 
     AutoIdVector keys(cx);
     if (!GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &keys))
         return false;
 
     AutoValueVector vals(cx);
@@ -2521,28 +2522,28 @@ obj_getOwnPropertyNames(JSContext *cx, u
 
     vp->setObject(*aobj);
     return true;
 }
 
 static JSBool
 obj_isExtensible(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj;
+    RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isExtensible", &obj))
         return false;
 
     vp->setBoolean(obj->isExtensible());
     return true;
 }
 
 static JSBool
 obj_preventExtensions(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj;
+    RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
         return false;
 
     vp->setObject(*obj);
     if (!obj->isExtensible())
         return true;
 
     return obj->preventExtensions(cx);
@@ -2672,55 +2673,55 @@ JSObject::isSealedOrFrozen(JSContext *cx
     /* All properties checked out. This object is sealed/frozen. */
     *resultp = true;
     return true;
 }
 
 static JSBool
 obj_freeze(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj;
+    RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.freeze", &obj))
         return false;
 
     vp->setObject(*obj);
 
     return obj->freeze(cx);
 }
 
 static JSBool
 obj_isFrozen(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj;
+    RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
         return false;
 
     bool frozen;
     if (!obj->isFrozen(cx, &frozen))
         return false;
     vp->setBoolean(frozen);
     return true;
 }
 
 static JSBool
 obj_seal(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj;
+    RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.seal", &obj))
         return false;
 
     vp->setObject(*obj);
 
     return obj->seal(cx);
 }
 
 static JSBool
 obj_isSealed(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj;
+    RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isSealed", &obj))
         return false;
 
     bool sealed;
     if (!obj->isSealed(cx, &sealed))
         return false;
     vp->setBoolean(sealed);
     return true;
@@ -2868,23 +2869,24 @@ js::NewObjectWithGivenProto(JSContext *c
 
     if (entry != -1 && !obj->hasDynamicSlots())
         cache.fillProto(entry, clasp, proto, kind, obj);
 
     return obj;
 }
 
 JSObject *
-js::NewObjectWithClassProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent_,
+js::NewObjectWithClassProto(JSContext *cx, js::Class *clasp, JSObject *proto_, JSObject *parent_,
                             gc::AllocKind kind)
 {
-    if (proto)
-        return NewObjectWithGivenProto(cx, clasp, proto, parent_, kind);
+    if (proto_)
+        return NewObjectWithGivenProto(cx, clasp, proto_, parent_, kind);
 
     RootedObject parent(cx, parent_);
+    RootedObject proto(cx, proto_);
 
     if (CanBeFinalizedInBackground(kind, clasp))
         kind = GetBackgroundAllocKind(kind);
 
     if (!parent)
         parent = GetCurrentGlobal(cx);
 
     /*
@@ -3865,17 +3867,17 @@ js_InitClass(JSContext *cx, HandleObject
      * of js_InitClass depend on this nicety. Note that in
      * js_InitFunctionAndObjectClasses, we specially hack the resolving table
      * and then depend on js_GetClassPrototype here leaving protoProto NULL and
      * returning true.
      */
     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
     if (key != JSProto_Null &&
         !protoProto &&
-        !js_GetClassPrototype(cx, obj, JSProto_Object, protoProto.address())) {
+        !js_GetClassPrototype(cx, obj, JSProto_Object, &protoProto)) {
         return NULL;
     }
 
     return DefineConstructorAndPrototype(cx, obj, key, atom, protoProto, clasp, constructor, nargs,
                                          ps, fs, static_ps, static_fs, ctorp, ctorKind);
 }
 
 inline bool
@@ -4261,59 +4263,57 @@ SetProto(JSContext *cx, HandleObject obj
     MarkTypeObjectUnknownProperties(cx, type, true);
 
     obj->setType(type);
     return true;
 }
 
 }
 
-JSBool
-js_GetClassObject(JSContext *cx, JSObject *obj_, JSProtoKey key,
-                  JSObject **objp)
-{
-    RootedObject obj(cx, obj_);
-
-    obj = &obj->global();
-    if (!obj->isGlobal()) {
-        *objp = NULL;
+bool
+js_GetClassObject(JSContext *cx, HandleObject obj, JSProtoKey key,
+                  MutableHandleObject objp)
+{
+
+    RootedObject global(cx, &obj->global());
+    if (!global->isGlobal()) {
+        objp.set(NULL);
         return true;
     }
 
-    Value v = obj->getReservedSlot(key);
+    Value v = global->getReservedSlot(key);
     if (v.isObject()) {
-        *objp = &v.toObject();
+        objp.set(&v.toObject());
         return true;
     }
 
-    AutoResolving resolving(cx, obj, NameToId(cx->runtime->atomState.classAtoms[key]));
+    AutoResolving resolving(cx, global, NameToId(cx->runtime->atomState.classAtoms[key]));
     if (resolving.alreadyStarted()) {
-        /* Already caching id in obj -- suppress recursion. */
-        *objp = NULL;
+        /* Already caching id in global -- suppress recursion. */
+        objp.set(NULL);
         return true;
     }
 
     JSObject *cobj = NULL;
     if (JSClassInitializerOp init = lazy_prototype_init[key]) {
-        if (!init(cx, obj))
+        if (!init(cx, global))
             return false;
-        v = obj->getReservedSlot(key);
+        v = global->getReservedSlot(key);
         if (v.isObject())
             cobj = &v.toObject();
     }
 
-    *objp = cobj;
+    objp.set(cobj);
     return true;
 }
 
-JSBool
-js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
-                   Value *vp, Class *clasp)
-{
-    JSObject *cobj, *pobj;
+bool
+js_FindClassObject(JSContext *cx, HandleObject start, JSProtoKey protoKey,
+                   MutableHandleValue vp, Class *clasp)
+{
     RootedId id(cx);
     JSProperty *prop;
     const Shape *shape;
 
     RootedObject obj(cx);
 
     if (start) {
         obj = &start->global();
@@ -4322,43 +4322,45 @@ js_FindClassObject(JSContext *cx, JSObje
         obj = GetGlobalForScopeChain(cx);
     }
     if (!obj)
         return false;
 
     if (protoKey != JSProto_Null) {
         JS_ASSERT(JSProto_Null < protoKey);
         JS_ASSERT(protoKey < JSProto_LIMIT);
+        RootedObject cobj(cx);
         if (!js_GetClassObject(cx, obj, protoKey, &cobj))
             return false;
         if (cobj) {
-            vp->setObject(*cobj);
+            vp.set(ObjectValue(*cobj));
             return JS_TRUE;
         }
         id = NameToId(cx->runtime->atomState.classAtoms[protoKey]);
     } else {
         JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
         if (!atom)
             return false;
         id = AtomToId(atom);
     }
 
     JS_ASSERT(obj->isNative());
+    RootedObject pobj(cx);
     if (!LookupPropertyWithFlags(cx, obj, id, 0, &pobj, &prop))
         return false;
-    Value v = UndefinedValue();
+    RootedValue v(cx, UndefinedValue());
     if (prop && pobj->isNative()) {
         shape = (Shape *) prop;
         if (shape->hasSlot()) {
             v = pobj->nativeGetSlot(shape->slot());
-            if (v.isPrimitive())
-                v.setUndefined();
+            if (v.reference().isPrimitive())
+                v.reference().setUndefined();
         }
     }
-    *vp = v;
+    vp.set(v);
     return true;
 }
 
 bool
 JSObject::allocSlot(JSContext *cx, uint32_t *slotp)
 {
     uint32_t slot = slotSpan();
     JS_ASSERT(slot >= JSSLOT_FREE(getClass()));
@@ -4561,28 +4563,28 @@ DefineNativeProperty(JSContext *cx, Hand
 
     /*
      * If defining a getter or setter, we must check for its counterpart and
      * update the attributes and property ops.  A getter or setter is really
      * only half of a property.
      */
     RootedShape shape(cx);
     if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
-        JSObject *pobj;
         JSProperty *prop;
 
         /* Type information for getter/setter properties is unknown. */
         AddTypePropertyId(cx, obj, id, types::Type::UnknownType());
         MarkTypePropertyConfigured(cx, obj, id);
 
         /*
          * If we are defining a getter whose setter was already defined, or
          * vice versa, finish the job via obj->changeProperty, and refresh the
          * property cache line for (obj, id) to map shape.
          */
+        RootedObject pobj(cx);
         if (!baseops::LookupProperty(cx, obj, id, &pobj, &prop))
             return NULL;
         if (prop && pobj == obj) {
             shape = (Shape *) prop;
             if (shape->isAccessorDescriptor()) {
                 shape = obj->changeProperty(cx, shape, attrs,
                                             JSPROP_GETTER | JSPROP_SETTER,
                                             (attrs & JSPROP_GETTER)
@@ -4664,17 +4666,17 @@ DefineNativeProperty(JSContext *cx, Hand
  *   - If the resolve hook finds or defines the sought property, set *objp and
  *     *propp appropriately, set *recursedp = false, and return true.
  *
  *   - Otherwise no property was resolved. Set *propp = NULL and *recursedp = false
  *     and return true.
  */
 static JSBool
 CallResolveOp(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-              JSObject **objp, JSProperty **propp, bool *recursedp)
+              MutableHandleObject objp, JSProperty **propp, bool *recursedp)
 {
     Class *clasp = obj->getClass();
     JSResolveOp resolve = clasp->resolve;
 
     /*
      * Avoid recursion on (obj, id) already being resolved on cx.
      *
      * Once we have successfully added an entry for (obj, key) to
@@ -4693,17 +4695,17 @@ CallResolveOp(JSContext *cx, HandleObjec
     *propp = NULL;
 
     if (clasp->flags & JSCLASS_NEW_RESOLVE) {
         JSNewResolveOp newresolve = reinterpret_cast<JSNewResolveOp>(resolve);
         if (flags == RESOLVE_INFER)
             flags = js_InferFlags(cx, 0);
 
         RootedObject obj2(cx, NULL);
-        if (!newresolve(cx, obj, id, flags, obj2.address()))
+        if (!newresolve(cx, obj, id, flags, &obj2))
             return false;
 
         /*
          * We trust the new style resolve hook to set obj2 to NULL when
          * the id cannot be resolved. But, when obj2 is not null, we do
          * not assume that id must exist and do full nativeLookup for
          * compatibility.
          */
@@ -4718,34 +4720,34 @@ CallResolveOp(JSContext *cx, HandleObjec
         obj = obj2;
     } else {
         if (!resolve(cx, obj, id))
             return false;
     }
 
     if (!obj->nativeEmpty()) {
         if (const Shape *shape = obj->nativeLookup(cx, id)) {
-            *objp = obj;
+            objp.set(obj);
             *propp = (JSProperty *) shape;
         }
     }
 
     return true;
 }
 
 static JS_ALWAYS_INLINE bool
 LookupPropertyWithFlagsInline(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                              JSObject **objp, JSProperty **propp)
+                              MutableHandleObject objp, JSProperty **propp)
 {
     /* Search scopes starting with obj and following the prototype link. */
     RootedObject current(cx, obj);
     while (true) {
         const Shape *shape = current->nativeLookup(cx, id);
         if (shape) {
-            *objp = current;
+            objp.set(current);
             *propp = (JSProperty *) shape;
             return true;
         }
 
         /* Try obj's class resolve hook if id was not found in obj's scope. */
         if (current->getClass()->resolve != JS_ResolveStub) {
             bool recursed;
             if (!CallResolveOp(cx, current, id, flags, objp, propp, &recursed))
@@ -4772,64 +4774,65 @@ LookupPropertyWithFlagsInline(JSContext 
              * Non-native objects must have either non-native lookup results,
              * or else native results from the non-native's prototype chain.
              *
              * See StackFrame::getValidCalleeObject, where we depend on this
              * fact to force a prototype-delegated joined method accessed via
              * arguments.callee through the delegating |this| object's method
              * read barrier.
              */
-            if (*propp && (*objp)->isNative()) {
-                while ((proto = proto->getProto()) != *objp)
+            if (*propp && objp->isNative()) {
+                while ((proto = proto->getProto()) != objp.value())
                     JS_ASSERT(proto);
             }
 #endif
             return true;
         }
 
         current = proto;
     }
 
-    *objp = NULL;
+    objp.set(NULL);
     *propp = NULL;
     return true;
 }
 
 JS_FRIEND_API(JSBool)
-baseops::LookupProperty(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp,
+baseops::LookupProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
                         JSProperty **propp)
 {
     return LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp);
 }
 
 JS_FRIEND_API(JSBool)
-baseops::LookupElement(JSContext *cx, HandleObject obj, uint32_t index, JSObject **objp, JSProperty **propp)
+baseops::LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
+                       MutableHandleObject objp, JSProperty **propp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
 
     return LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp);
 }
 
 bool
 js::LookupPropertyWithFlags(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                            JSObject **objp, JSProperty **propp)
+                            MutableHandleObject objp, JSProperty **propp)
 {
     return LookupPropertyWithFlagsInline(cx, obj, id, flags, objp, propp);
 }
 
 bool
 js::FindPropertyHelper(JSContext *cx,
                        HandlePropertyName name, bool cacheResult, HandleObject scopeChain,
-                       JSObject **objp, JSObject **pobjp, JSProperty **propp)
+                       MutableHandleObject objp, MutableHandleObject pobjp, JSProperty **propp)
 {
     RootedId id(cx, NameToId(name));
 
-    JSObject *pobj;
+    RootedObject pobj(cx);
     int scopeIndex;
     JSProperty *prop;
 
     /* Scan entries on the scope chain that we can cache across. */
     RootedObject obj(cx, scopeChain);
     RootedObject parent(cx, obj->enclosingScope());
     for (scopeIndex = 0;
          parent
@@ -4896,29 +4899,29 @@ js::FindPropertyHelper(JSContext *cx,
             pobj = NULL;
             break;
         }
         obj = parent;
     }
 
   out:
     JS_ASSERT(!!pobj == !!prop);
-    *objp = obj;
-    *pobjp = pobj;
+    objp.set(obj);
+    pobjp.set(pobj);
     *propp = prop;
     return true;
 }
 
 /*
  * On return, if |*pobjp| is a native object, then |*propp| is a |Shape *|.
  * Otherwise, its type and meaning depends on the host object's implementation.
  */
 bool
 js::FindProperty(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
-                 JSObject **objp, JSObject **pobjp, JSProperty **propp)
+                 MutableHandleObject objp, MutableHandleObject pobjp, JSProperty **propp)
 {
     return !!FindPropertyHelper(cx, name, false, scopeChain, objp, pobjp, propp);
 }
 
 JSObject *
 js::FindIdentifierBase(JSContext *cx, HandleObject scopeChain, HandlePropertyName name)
 {
     /*
@@ -4935,18 +4938,19 @@ js::FindIdentifierBase(JSContext *cx, Ha
      * farther checks or lookups. For details see the JSOP_BINDNAME case of
      * js_Interpret.
      *
      * The test order here matters because IsCacheableNonGlobalScope
      * must not be passed a global object (i.e. one with null parent).
      */
     for (int scopeIndex = 0;
          obj->isGlobal() || IsCacheableNonGlobalScope(obj);
-         scopeIndex++) {
-        JSObject *pobj;
+         scopeIndex++)
+    {
+        RootedObject pobj(cx);
         JSProperty *prop;
         if (!LookupPropertyWithFlags(cx, obj, name.value(), cx->resolveFlags, &pobj, &prop))
             return NULL;
         if (prop) {
             if (!pobj->isNative()) {
                 JS_ASSERT(obj->isGlobal());
                 return obj;
             }
@@ -4958,17 +4962,17 @@ js::FindIdentifierBase(JSContext *cx, Ha
         JSObject *parent = obj->enclosingScope();
         if (!parent)
             return obj;
         obj = parent;
     }
 
     /* Loop until we find a property or reach the global object. */
     do {
-        JSObject *pobj;
+        RootedObject pobj(cx);
         JSProperty *prop;
         if (!obj->lookupProperty(cx, name, &pobj, &prop))
             return NULL;
         if (prop)
             break;
 
         /*
          * We conservatively assume that a resolve hook could mutate the scope
@@ -5079,17 +5083,17 @@ js_GetPropertyHelperInline(JSContext *cx
                            uint32_t getHow, Value *vp)
 {
     JSProperty *prop;
 
     RootedId id(cx, id_);
 
     /* This call site is hot -- use the always-inlined variant of LookupPropertyWithFlags(). */
     RootedObject obj2(cx);
-    if (!LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, obj2.address(), &prop))
+    if (!LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, &obj2, &prop))
         return false;
 
     if (!prop) {
         vp->setUndefined();
 
         if (!CallJSPropertyOp(cx, obj->getClass()->getProperty, obj, id, vp))
             return JS_FALSE;
 
@@ -5191,17 +5195,17 @@ baseops::GetElement(JSContext *cx, Handl
     return js_GetPropertyHelperInline(cx, obj, receiver, id, 0, vp);
 }
 
 JSBool
 baseops::GetPropertyDefault(JSContext *cx, HandleObject obj, HandleId id, const Value &def, Value *vp)
 {
     JSProperty *prop;
     RootedObject obj2(cx);
-    if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, obj2.address(), &prop))
+    if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
         return false;
 
     if (!prop) {
         *vp = def;
         return true;
     }
 
     return baseops::GetProperty(cx, obj2, id, vp);
@@ -5280,17 +5284,16 @@ JSObject::callMethod(JSContext *cx, Hand
     return GetMethod(cx, obj, id, 0, &fval) &&
            Invoke(cx, ObjectValue(*obj), fval, argc, argv, vp);
 }
 
 JSBool
 baseops::SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
                            unsigned defineHow, Value *vp, JSBool strict)
 {
-    JSObject *pobj;
     JSProperty *prop;
     unsigned attrs, flags;
     int shortid;
     Class *clasp;
     PropertyOp getter;
     StrictPropertyOp setter;
     bool added;
 
@@ -5298,16 +5301,17 @@ baseops::SetPropertyHelper(JSContext *cx
 
     if (JS_UNLIKELY(obj->watched())) {
         /* Fire watchpoints, if any. */
         WatchpointMap *wpmap = cx->compartment->watchpointMap;
         if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
             return false;
     }
 
+    RootedObject pobj(cx);
     if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
         return false;
     if (prop) {
         if (!pobj->isNative()) {
             if (pobj->isProxy()) {
                 AutoPropertyDescriptorRooter pd(cx);
                 if (!Proxy::getPropertyDescriptor(cx, pobj, id, true, &pd))
                     return false;
@@ -5475,17 +5479,17 @@ baseops::SetElementHelper(JSContext *cx,
     if (!IndexToId(cx, index, id.address()))
         return false;
     return baseops::SetPropertyHelper(cx, obj, receiver, id, defineHow, vp, strict);
 }
 
 JSBool
 baseops::GetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
-    JSObject *nobj;
+    RootedObject nobj(cx);
     JSProperty *prop;
     if (!baseops::LookupProperty(cx, obj, id, &nobj, &prop))
         return false;
     if (!prop) {
         *attrsp = 0;
         return true;
     }
     if (!nobj->isNative())
@@ -5494,17 +5498,17 @@ baseops::GetAttributes(JSContext *cx, Ha
     const Shape *shape = (Shape *)prop;
     *attrsp = shape->attributes();
     return true;
 }
 
 JSBool
 baseops::GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 {
-    JSObject *nobj;
+    RootedObject nobj(cx);
     JSProperty *prop;
     if (!baseops::LookupElement(cx, obj, index, &nobj, &prop))
         return false;
     if (!prop) {
         *attrsp = 0;
         return true;
     }
     if (!nobj->isNative())
@@ -5513,50 +5517,50 @@ baseops::GetElementAttributes(JSContext 
     const Shape *shape = (Shape *)prop;
     *attrsp = shape->attributes();
     return true;
 }
 
 JSBool
 baseops::SetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
-    JSObject *nobj;
+    RootedObject nobj(cx);
     JSProperty *prop;
     if (!baseops::LookupProperty(cx, obj, id, &nobj, &prop))
         return false;
     if (!prop)
         return true;
     return nobj->isNative()
            ? nobj->changePropertyAttributes(cx, (Shape *) prop, *attrsp)
            : nobj->setGenericAttributes(cx, id, attrsp);
 }
 
 JSBool
 baseops::SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 {
-    JSObject *nobj;
+    RootedObject nobj(cx);
     JSProperty *prop;
     if (!baseops::LookupElement(cx, obj, index, &nobj, &prop))
         return false;
     if (!prop)
         return true;
     return nobj->isNative()
            ? nobj->changePropertyAttributes(cx, (Shape *) prop, *attrsp)
            : nobj->setElementAttributes(cx, index, attrsp);
 }
 
 JSBool
 baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, Value *rval, JSBool strict)
 {
-    JSObject *proto;
     JSProperty *prop;
     const Shape *shape;
 
     rval->setBoolean(true);
 
+    RootedObject proto(cx);
     if (!baseops::LookupProperty(cx, obj, id, &proto, &prop))
         return false;
     if (!prop || proto != obj) {
         /*
          * If no property, or the property comes from a prototype, call the
          * class's delProperty hook, passing rval as the result parameter.
          */
         return CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, id, rval);
@@ -5767,17 +5771,17 @@ CheckAccess(JSContext *cx, JSObject *obj
       case JSACC_PROTO:
         pobj = obj;
         if (!writing)
             vp->setObjectOrNull(obj->getProto());
         *attrsp = JSPROP_PERMANENT;
         break;
 
       default:
-        if (!obj->lookupGeneric(cx, id, pobj.address(), &prop))
+        if (!obj->lookupGeneric(cx, id, &pobj, &prop))
             return JS_FALSE;
         if (!prop) {
             if (!writing)
                 vp->setUndefined();
             *attrsp = 0;
             pobj = obj;
             break;
         }
@@ -5837,58 +5841,58 @@ js_IsDelegate(JSContext *cx, JSObject *o
     while ((obj2 = obj2->getProto()) != NULL) {
         if (obj2 == obj)
             return true;
     }
     return false;
 }
 
 bool
-js::FindClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
-                       JSObject **protop, Class *clasp)
-{
-    Value v;
+js::FindClassPrototype(JSContext *cx, HandleObject scopeobj, JSProtoKey protoKey,
+                       MutableHandleObject protop, Class *clasp)
+{
+    RootedValue v(cx);
     if (!js_FindClassObject(cx, scopeobj, protoKey, &v, clasp))
         return false;
 
     if (IsFunctionObject(v)) {
-        JSObject *ctor = &v.toObject();
-        if (!ctor->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &v))
+        JSObject *ctor = &v.reference().toObject();
+        if (!ctor->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, v.address()))
             return false;
     }
 
-    *protop = v.isObject() ? &v.toObject() : NULL;
+    protop.set(v.reference().isObject() ? &v.reference().toObject() : NULL);
     return true;
 }
 
 /*
  * The first part of this function has been hand-expanded and optimized into
  * NewBuiltinClassInstance in jsobjinlines.h.
  */
-JSBool
-js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
-                     JSObject **protop, Class *clasp)
+bool
+js_GetClassPrototype(JSContext *cx, HandleObject scopeobj, JSProtoKey protoKey,
+                     MutableHandleObject protop, Class *clasp)
 {
     JS_ASSERT(JSProto_Null <= protoKey);
     JS_ASSERT(protoKey < JSProto_LIMIT);
 
     if (protoKey != JSProto_Null) {
         GlobalObject *global;
         if (scopeobj) {
             global = &scopeobj->global();
         } else {
             global = GetCurrentGlobal(cx);
             if (!global) {
-                *protop = NULL;
+                protop.set(NULL);
                 return true;
             }
         }
         const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey);
         if (v.isObject()) {
-            *protop = &v.toObject();
+            protop.set(&v.toObject());
             return true;
         }
     }
 
     return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp);
 }
 
 JSObject *
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -93,30 +93,30 @@ typedef Vector<PropDesc, 1> PropDescArra
 namespace baseops {
 
 /*
  * On success, and if id was found, return true with *objp non-null and with a
  * property of *objp stored in *propp. If successful but id was not found,
  * return true with both *objp and *propp null.
  */
 extern JS_FRIEND_API(JSBool)
-LookupProperty(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp,
+LookupProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
                JSProperty **propp);
 
 inline bool
 LookupProperty(JSContext *cx, HandleObject obj, PropertyName *name,
-               JSObject **objp, JSProperty **propp)
+               MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return LookupProperty(cx, obj, id, objp, propp);
 }
 
 extern JS_FRIEND_API(JSBool)
 LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-              JSObject **objp, JSProperty **propp);
+              MutableHandleObject objp, JSProperty **propp);
 
 extern JSBool
 DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, const js::Value *value,
                JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
 
 inline JSBool
 DefineProperty(JSContext *cx, HandleObject obj, PropertyName *name, const js::Value *value,
                JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
@@ -780,22 +780,22 @@ struct JSObject : public js::ObjectImpl
     inline bool changePropertyAttributes(JSContext *cx, js::Shape *shape, unsigned attrs);
 
     /* Remove the property named by id from this object. */
     bool removeProperty(JSContext *cx, jsid id);
 
     /* Clear the scope, making it empty. */
     void clear(JSContext *cx);
 
-    inline JSBool lookupGeneric(JSContext *cx, js::HandleId id, JSObject **objp, JSProperty **propp);
-    inline JSBool lookupProperty(JSContext *cx, js::PropertyName *name, JSObject **objp, JSProperty **propp);
+    inline JSBool lookupGeneric(JSContext *cx, js::HandleId id, js::MutableHandleObject objp, JSProperty **propp);
+    inline JSBool lookupProperty(JSContext *cx, js::PropertyName *name, js::MutableHandleObject objp, JSProperty **propp);
     inline JSBool lookupElement(JSContext *cx, uint32_t index,
-                                JSObject **objp, JSProperty **propp);
+                                js::MutableHandleObject objp, JSProperty **propp);
     inline JSBool lookupSpecial(JSContext *cx, js::SpecialId sid,
-                                JSObject **objp, JSProperty **propp);
+                                js::MutableHandleObject objp, JSProperty **propp);
 
     inline JSBool defineGeneric(JSContext *cx, js::HandleId id, const js::Value &value,
                                 JSPropertyOp getter = JS_PropertyStub,
                                 JSStrictPropertyOp setter = JS_StrictPropertyStub,
                                 unsigned attrs = JSPROP_ENUMERATE);
     inline JSBool defineProperty(JSContext *cx, js::PropertyName *name, const js::Value &value,
                                  JSPropertyOp getter = JS_PropertyStub,
                                  JSStrictPropertyOp setter = JS_StrictPropertyStub,
@@ -1041,17 +1041,17 @@ extern void
 js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map);
 
 extern JSBool
 js_HasOwnPropertyHelper(JSContext *cx, js::LookupGenericOp lookup, unsigned argc,
                         js::Value *vp);
 
 extern JSBool
 js_HasOwnProperty(JSContext *cx, js::LookupGenericOp lookup, js::HandleObject obj, js::HandleId id,
-                  JSObject **objp, JSProperty **propp);
+                  js::MutableHandleObject objp, JSProperty **propp);
 
 extern JSBool
 js_PropertyIsEnumerable(JSContext *cx, js::HandleObject obj, js::HandleId id, js::Value *vp);
 
 #if JS_HAS_OBJ_PROTO_PROP
 extern JSPropertySpec object_props[];
 #else
 #define object_props NULL
@@ -1087,27 +1087,27 @@ extern const char js_lookupSetter_str[];
 #endif
 
 extern JSBool
 js_PopulateObject(JSContext *cx, js::HandleObject newborn, JSObject *props);
 
 /*
  * Fast access to immutable standard objects (constructors and prototypes).
  */
-extern JSBool
-js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
-                  JSObject **objp);
+extern bool
+js_GetClassObject(JSContext *cx, js::HandleObject obj, JSProtoKey key,
+                  js::MutableHandleObject objp);
 
 /*
  * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
  * JSProto_Null, clasp must non-null.
  */
-extern JSBool
-js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey key,
-                   js::Value *vp, js::Class *clasp = NULL);
+bool
+js_FindClassObject(JSContext *cx, js::HandleObject start, JSProtoKey protoKey,
+                   js::MutableHandleValue vp, js::Class *clasp = NULL);
 
 // Specialized call for constructing |this| with a known function callee,
 // and a known prototype.
 extern JSObject *
 js_CreateThisForFunctionWithProto(JSContext *cx, js::HandleObject callee, JSObject *proto);
 
 // Specialized call for constructing |this| with a known function callee.
 extern JSObject *
@@ -1160,21 +1160,21 @@ DefineNativeProperty(JSContext *cx, Hand
                                 shortid, defineHow);
 }
 
 /*
  * Specialized subroutine that allows caller to preset JSRESOLVE_* flags.
  */
 extern bool
 LookupPropertyWithFlags(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                        JSObject **objp, JSProperty **propp);
+                        js::MutableHandleObject objp, JSProperty **propp);
 
 inline bool
 LookupPropertyWithFlags(JSContext *cx, HandleObject obj, PropertyName *name, unsigned flags,
-                        JSObject **objp, JSProperty **propp)
+                        js::MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return LookupPropertyWithFlags(cx, obj, id, flags, objp, propp);
 }
 
 /*
  * Call the [[DefineOwnProperty]] internal method of obj.
  *
@@ -1203,25 +1203,25 @@ ReadPropertyDescriptors(JSContext *cx, J
 static const unsigned RESOLVE_INFER = 0xffff;
 
 /*
  * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success.
  */
 extern bool
 FindPropertyHelper(JSContext *cx, HandlePropertyName name,
                    bool cacheResult, HandleObject scopeChain,
-                   JSObject **objp, JSObject **pobjp, JSProperty **propp);
+                   MutableHandleObject objp, MutableHandleObject pobjp, JSProperty **propp);
 
 /*
  * Search for name either on the current scope chain or on the scope chain's
  * global object, per the global parameter.
  */
 extern bool
 FindProperty(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
-             JSObject **objp, JSObject **pobjp, JSProperty **propp);
+             MutableHandleObject objp, MutableHandleObject pobjp, JSProperty **propp);
 
 extern JSObject *
 FindIdentifierBase(JSContext *cx, HandleObject scopeChain, HandlePropertyName name);
 
 }
 
 extern JSObject *
 js_FindVariableScope(JSContext *cx, JSFunction **funp);
@@ -1355,19 +1355,19 @@ js_Object(JSContext *cx, unsigned argc, 
 
 /*
  * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
  * JSProto_Null, clasp must non-null.
  *
  * If protoKey is constant and scope is non-null, use GlobalObject's prototype
  * methods instead.
  */
-extern JS_FRIEND_API(JSBool)
-js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey,
-                     JSObject **protop, js::Class *clasp = NULL);
+extern JS_FRIEND_API(bool)
+js_GetClassPrototype(JSContext *cx, js::HandleObject scopeobj, JSProtoKey protoKey,
+                     js::MutableHandleObject protop, js::Class *clasp = NULL);
 
 namespace js {
 
 extern bool
 SetProto(JSContext *cx, HandleObject obj, HandleObject proto, bool checkForCycles);
 
 extern JSString *
 obj_toStringHelper(JSContext *cx, JSObject *obj);
@@ -1403,17 +1403,18 @@ NonNullObject(JSContext *cx, const Value
 
 extern const char *
 InformalValueTypeName(const Value &v);
 
 inline void
 DestroyIdArray(FreeOp *fop, JSIdArray *ida);
 
 extern bool
-GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *method, JSObject **objp);
+GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *method,
+                         MutableHandleObject objp);
 
 /* Helpers for throwing. These always return false. */
 extern bool
 Throw(JSContext *cx, jsid id, unsigned errorNumber);
 
 extern bool
 Throw(JSContext *cx, JSObject *obj, unsigned errorNumber);
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -921,17 +921,17 @@ JSObject::finish(js::FreeOp *fop)
         fop->free_(slots);
     if (hasDynamicElements())
         fop->free_(getElementsHeader());
 }
 
 inline bool
 JSObject::hasProperty(JSContext *cx, js::HandleId id, bool *foundp, unsigned flags)
 {
-    JSObject *pobj;
+    js::RootedObject pobj(cx);
     JSProperty *prop;
     JSAutoResolveFlags rf(cx, flags);
     if (!lookupGeneric(cx, id, &pobj, &prop))
         return false;
     *foundp = !!prop;
     return true;
 }
 
@@ -1029,28 +1029,28 @@ JSObject::sizeOfExcludingThis(JSMallocSi
     if (isArguments()) {
         *miscSize += asArguments().sizeOfMisc(mallocSizeOf);
     } else if (isRegExpStatics()) {
         *miscSize += js::SizeOfRegExpStaticsData(this, mallocSizeOf);
     }
 }
 
 inline JSBool
-JSObject::lookupGeneric(JSContext *cx, js::HandleId id, JSObject **objp, JSProperty **propp)
+JSObject::lookupGeneric(JSContext *cx, js::HandleId id, js::MutableHandleObject objp, JSProperty **propp)
 {
     js::RootedObject self(cx, this);
 
     js::LookupGenericOp op = getOps()->lookupGeneric;
     if (op)
         return op(cx, self, id, objp, propp);
     return js::baseops::LookupProperty(cx, self, id, objp, propp);
 }
 
 inline JSBool
-JSObject::lookupProperty(JSContext *cx, js::PropertyName *name, JSObject **objp, JSProperty **propp)
+JSObject::lookupProperty(JSContext *cx, js::PropertyName *name, js::MutableHandleObject objp, JSProperty **propp)
 {
     js::Rooted<jsid> id(cx, js::NameToId(name));
     return lookupGeneric(cx, id, objp, propp);
 }
 
 inline JSBool
 JSObject::defineGeneric(JSContext *cx, js::HandleId id, const js::Value &value,
                         JSPropertyOp getter /* = JS_PropertyStub */,
@@ -1092,26 +1092,26 @@ JSObject::defineSpecial(JSContext *cx, j
                         JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
                         unsigned attrs /* = JSPROP_ENUMERATE */)
 {
     js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return defineGeneric(cx, id, value, getter, setter, attrs);
 }
 
 inline JSBool
-JSObject::lookupElement(JSContext *cx, uint32_t index, JSObject **objp, JSProperty **propp)
+JSObject::lookupElement(JSContext *cx, uint32_t index, js::MutableHandleObject objp, JSProperty **propp)
 {
     js::RootedObject self(cx, this);
 
     js::LookupElementOp op = getOps()->lookupElement;
     return (op ? op : js::baseops::LookupElement)(cx, self, index, objp, propp);
 }
 
 inline JSBool
-JSObject::lookupSpecial(JSContext *cx, js::SpecialId sid, JSObject **objp, JSProperty **propp)
+JSObject::lookupSpecial(JSContext *cx, js::SpecialId sid, js::MutableHandleObject objp, JSProperty **propp)
 {
     js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return lookupGeneric(cx, id, objp, propp);
 }
 
 inline JSBool
 JSObject::getElement(JSContext *cx, js::HandleObject receiver, uint32_t index, js::Value *vp)
 {
@@ -1148,17 +1148,17 @@ JSObject::getElementIfPresent(JSContext 
      * For now, do the index-to-id conversion just once, then use
      * lookupGeneric/getGeneric.  Once lookupElement and getElement stop both
      * doing index-to-id conversions, we can use those here.
      */
     js::RootedId id(cx);
     if (!js::IndexToId(cx, index, id.address()))
         return false;
 
-    JSObject *obj2;
+    js::RootedObject obj2(cx);
     JSProperty *prop;
     if (!self->lookupGeneric(cx, id, &obj2, &prop))
         return false;
 
     if (!prop) {
         *present = false;
         js::Debug_SetValueRangeToCrashOnTouch(vp, 1);
         return true;
@@ -1435,22 +1435,22 @@ GetClassProtoKey(js::Class *clasp)
     if (key != JSProto_Null)
         return key;
     if (clasp->flags & JSCLASS_IS_ANONYMOUS)
         return JSProto_Object;
     return JSProto_Null;
 }
 
 inline bool
-FindProto(JSContext *cx, js::Class *clasp, HandleObject parent, JSObject **proto)
+FindProto(JSContext *cx, js::Class *clasp, HandleObject parent, MutableHandleObject proto)
 {
     JSProtoKey protoKey = GetClassProtoKey(clasp);
     if (!js_GetClassPrototype(cx, parent, protoKey, proto, clasp))
         return false;
-    if (!(*proto) && !js_GetClassPrototype(cx, parent, JSProto_Object, proto))
+    if (!proto && !js_GetClassPrototype(cx, parent, JSProto_Object, proto))
         return false;
     return true;
 }
 
 /*
  * Make an object with the prototype set according to the specified prototype or class:
  *
  * if proto is non-null:
@@ -1498,18 +1498,18 @@ NewBuiltinClassInstance(JSContext *cx, C
 inline GlobalObject *
 GetCurrentGlobal(JSContext *cx)
 {
     JSObject *scopeChain = (cx->hasfp()) ? cx->fp()->scopeChain() : cx->globalObject;
     return scopeChain ? &scopeChain->global() : NULL;
 }
 
 bool
-FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
-                   Class *clasp);
+FindClassPrototype(JSContext *cx, HandleObject scope, JSProtoKey protoKey,
+                   MutableHandleObject protop, Class *clasp);
 
 /*
  * Create a plain object with the specified type. This bypasses getNewType to
  * avoid losing creation site information for objects made by scripted 'new'.
  */
 JSObject *
 NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc::AllocKind kind);
 
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1216,53 +1216,54 @@ Proxy::iteratorNext(JSContext *cx, JSObj
 
 static JSObject *
 proxy_innerObject(JSContext *cx, HandleObject obj)
 {
     return GetProxyPrivate(obj).toObjectOrNull();
 }
 
 static JSBool
-proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp,
+proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
                     JSProperty **propp)
 {
     bool found;
     if (!Proxy::has(cx, obj, id, &found))
         return false;
 
     if (found) {
         *propp = (JSProperty *)0x1;
-        *objp = obj;
+        objp.set(obj);
     } else {
-        *objp = NULL;
+        objp.set(NULL);
         *propp = NULL;
     }
     return true;
 }
 
 static JSBool
-proxy_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSObject **objp,
-                     JSProperty **propp)
+proxy_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                     MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
-proxy_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, JSObject **objp,
+proxy_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp,
                     JSProperty **propp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
-proxy_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSObject **objp, JSProperty **propp)
+proxy_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                    MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 proxy_DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -2833,17 +2833,17 @@ ASTSerializer::literal(ParseNode *pn, Va
         val.setString(pn->pn_atom);
         break;
 
       case PNK_REGEXP:
       {
         JSObject *re1 = pn->pn_objbox ? pn->pn_objbox->object : NULL;
         LOCAL_ASSERT(re1 && re1->isRegExp());
 
-        JSObject *proto;
+        RootedObject proto(cx);
         if (!js_GetClassPrototype(cx, cx->fp()->scopeChain(), JSProto_RegExp, &proto))
             return false;
 
         JSObject *re2 = CloneRegExpObject(cx, re1, proto);
         if (!re2)
             return false;
 
         val.setObject(*re2);
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -631,17 +631,17 @@ struct JSScript : public js::gc::Cell
      * Associates this script with a specific function, constructing a new type
      * object for the function if necessary.
      */
     bool typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton = false);
 
     inline bool hasGlobal() const;
     inline bool hasClearedGlobal() const;
 
-    inline js::GlobalObject *global() const;
+    inline js::GlobalObject * global() const;
     inline js::types::TypeScriptNesting *nesting() const;
 
     inline void clearNesting();
 
     /* Return creation time global or null. */
     js::GlobalObject *getGlobalObjectOrNull() const {
         return (isCachedEval || isActiveEval) ? NULL : globalObject.get();
     }
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -373,33 +373,33 @@ str_enumerate(JSContext *cx, HandleObjec
         }
     }
 
     return true;
 }
 
 static JSBool
 str_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-            JSObject **objp)
+            MutableHandleObject objp)
 {
     if (!JSID_IS_INT(id))
         return JS_TRUE;
 
     JSString *str = obj->asString().unbox();
 
     int32_t slot = JSID_TO_INT(id);
     if ((size_t)slot < str->length()) {
         JSString *str1 = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(slot));
         if (!str1)
             return JS_FALSE;
         if (!obj->defineElement(cx, uint32_t(slot), StringValue(str1), NULL, NULL,
                                 STRING_ELEMENT_ATTRS)) {
             return JS_FALSE;
         }
-        *objp = obj;
+        objp.set(obj);
     }
     return JS_TRUE;
 }
 
 Class js::StringClass = {
     js_String_str,
     JSCLASS_HAS_RESERVED_SLOTS(StringObject::RESERVED_SLOTS) |
     JSCLASS_NEW_RESOLVE | JSCLASS_HAS_CACHED_PROTO(JSProto_String),
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -294,21 +294,21 @@ ArrayBufferObject::obj_trace(JSTracer *t
         obj->setPrivateUnbarriered(delegate);
     }
 }
 
 static JSProperty * const PROPERTY_FOUND = reinterpret_cast<JSProperty *>(1);
 
 JSBool
 ArrayBufferObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                                     JSObject **objp, JSProperty **propp)
+                                     MutableHandleObject objp, JSProperty **propp)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         *propp = PROPERTY_FOUND;
-        *objp = getArrayBuffer(obj);
+        objp.set(getArrayBuffer(obj));
         return true;
     }
 
     RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
     if (!delegate)
         return false;
 
     JSBool delegateResult = delegate->lookupGeneric(cx, id, objp, propp);
@@ -317,73 +317,73 @@ ArrayBufferObject::obj_lookupGeneric(JSC
      * Otherwise, if propp is non-null, the property
      * was found. Otherwise it was not
      * found so look in the prototype chain.
      */
     if (!delegateResult)
         return false;
 
     if (*propp != NULL) {
-        if (*objp == delegate)
-            *objp = obj;
+        if (objp.value() == delegate)
+            objp.set(obj);
         return true;
     }
 
     JSObject *proto = obj->getProto();
     if (!proto) {
-        *objp = NULL;
+        objp.set(NULL);
         *propp = NULL;
         return true;
     }
 
     return proto->lookupGeneric(cx, id, objp, propp);
 }
 
 JSBool
 ArrayBufferObject::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                      JSObject **objp, JSProperty **propp)
+                                      MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return obj_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 ArrayBufferObject::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                                     JSObject **objp, JSProperty **propp)
+                                     MutableHandleObject objp, JSProperty **propp)
 {
     RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
     if (!delegate)
         return false;
 
     /*
      * If false, there was an error, so propagate it.
      * Otherwise, if propp is non-null, the property
      * was found. Otherwise it was not
      * found so look in the prototype chain.
      */
     if (!delegate->lookupElement(cx, index, objp, propp))
         return false;
 
     if (*propp != NULL) {
-        if (*objp == delegate)
-            *objp = obj;
+        if (objp.value() == delegate)
+            objp.set(obj);
         return true;
     }
 
     if (JSObject *proto = obj->getProto())
         return proto->lookupElement(cx, index, objp, propp);
 
-    *objp = NULL;
+    objp.set(NULL);
     *propp = NULL;
     return true;
 }
 
 JSBool
 ArrayBufferObject::obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                                     JSObject **objp, JSProperty **propp)
+                                     MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return obj_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 ArrayBufferObject::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *v,
                                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
@@ -722,17 +722,17 @@ ArrayBufferObject::obj_typeOf(JSContext 
  * ArrayBufferViews of various sorts
  */
 
 static JSObject *
 GetProtoForClass(JSContext *cx, Class *clasp)
 {
     // Pass in the proto from this compartment
     Rooted<GlobalObject*> parent(cx, GetCurrentGlobal(cx));
-    JSObject *proto;
+    RootedObject proto(cx);
     if (!FindProto(cx, clasp, parent, &proto))
         return NULL;
     return proto;
 }
 
 /*
  * TypedArray
  *
@@ -769,69 +769,69 @@ bool
 js::IsDataView(JSObject* obj)
 {
     JS_ASSERT(obj);
     return obj->isDataView();
 }
 
 JSBool
 TypedArray::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                              JSObject **objp, JSProperty **propp)
+                              MutableHandleObject objp, JSProperty **propp)
 {
     JSObject *tarray = getTypedArray(obj);
     JS_ASSERT(tarray);
 
     if (isArrayIndex(cx, tarray, id)) {
         *propp = PROPERTY_FOUND;
-        *objp = obj;
+        objp.set(obj);
         return true;
     }
 
     JSObject *proto = obj->getProto();
     if (!proto) {
-        *objp = NULL;
+        objp.set(NULL);
         *propp = NULL;
         return true;
     }
 
     return proto->lookupGeneric(cx, id, objp, propp);
 }
 
 JSBool
 TypedArray::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                               JSObject **objp, JSProperty **propp)
+                               MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return obj_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 TypedArray::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                              JSObject **objp, JSProperty **propp)
+                              MutableHandleObject objp, JSProperty **propp)
 {
     JSObject *tarray = getTypedArray(obj);
     JS_ASSERT(tarray);
 
     if (index < length(tarray)) {
         *propp = PROPERTY_FOUND;
-        *objp = obj;
+        objp.set(obj);
         return true;
     }
 
     if (JSObject *proto = obj->getProto())
         return proto->lookupElement(cx, index, objp, propp);
 
-    *objp = NULL;
+    objp.set(NULL);
     *propp = NULL;
     return true;
 }
 
 JSBool
 TypedArray::obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                              JSObject **objp, JSProperty **propp)
+                              MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return obj_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 TypedArray::obj_getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
@@ -2300,28 +2300,28 @@ JSBool
 DataViewObject::constructWithProto(JSContext *cx, unsigned argc, Value *vp)
 {
     // Pop the proto argument off the end
     CallArgs args = CallArgsFromVp(argc, vp);
     JSObject &proto = args[args.length() - 1].toObject();
 
     // And now mimic class_constructor for everything else, but pass in the proto
     args = CallArgsFromVp(argc - 1, vp);
-    JSObject *bufobj;
+    RootedObject bufobj(cx);
     if (!GetFirstArgumentAsObject(cx, args.length(), args.base(), "DataView constructor", &bufobj))
         return false;
     return construct(cx, bufobj, args, &proto);
 }
 
 JSBool
 DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    JSObject *bufobj;
+    RootedObject bufobj(cx);
     if (!GetFirstArgumentAsObject(cx, args.length(), args.base(), "DataView constructor", &bufobj))
         return false;
 
     if (bufobj->isWrapper() && UnwrapObject(bufobj)->isArrayBuffer()) {
         JSObject *proto = GetProtoForClass(cx, &DataViewClass);
         if (!proto)
             return false;
 
@@ -3246,17 +3246,17 @@ DataViewObject::initClass(JSContext *cx)
 
 JSObject *
 js_InitTypedArrayClasses(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
 
     /* Idempotency required: we initialize several things, possibly lazily. */
-    JSObject *stop;
+    RootedObject stop(cx);
     if (!js_GetClassObject(cx, global, JSProto_ArrayBuffer, &stop))
         return NULL;
     if (stop)
         return stop;
 
     if (!InitTypedArrayClass<Int8Array>(cx) ||
         !InitTypedArrayClass<Uint8Array>(cx) ||
         !InitTypedArrayClass<Int16Array>(cx) ||
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -42,26 +42,26 @@ class ArrayBufferObject : public JSObjec
     static JSObject *createSlice(JSContext *cx, ArrayBufferObject &arrayBuffer,
                                  uint32_t begin, uint32_t end);
 
     static void
     obj_trace(JSTracer *trc, JSObject *obj);
 
     static JSBool
     obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                      JSObject **objp, JSProperty **propp);
+                      MutableHandleObject objp, JSProperty **propp);
     static JSBool
     obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                       JSObject **objp, JSProperty **propp);
+                       MutableHandleObject objp, JSProperty **propp);
     static JSBool
     obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                      JSObject **objp, JSProperty **propp);
+                      MutableHandleObject objp, JSProperty **propp);
     static JSBool
-    obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSObject **objp,
-                      JSProperty **propp);
+    obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                      MutableHandleObject objp, JSProperty **propp);
 
     static JSBool
     obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *v,
                       PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
     static JSBool
     obj_defineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, const Value *v,
                        PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
     static JSBool
@@ -184,23 +184,23 @@ struct TypedArray {
     // and MUST NOT be used to construct new objects.
     static Class classes[TYPE_MAX];
 
     // These are the proto/original classes, used
     // fo constructing new objects
     static Class protoClasses[TYPE_MAX];
 
     static JSBool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                                    JSObject **objp, JSProperty **propp);
+                                    MutableHandleObject objp, JSProperty **propp);
     static JSBool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                     JSObject **objp, JSProperty **propp);
+                                     MutableHandleObject objp, JSProperty **propp);
     static JSBool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                                    JSObject **objp, JSProperty **propp);
+                                    MutableHandleObject objp, JSProperty **propp);
     static JSBool obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                                    JSObject **objp, JSProperty **propp);
+                                    MutableHandleObject objp, JSProperty **propp);
 
     static JSBool obj_getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
     static JSBool obj_getPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp);
     static JSBool obj_getElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp);
     static JSBool obj_getSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp);
 
     static JSBool obj_setGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
     static JSBool obj_setPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp);
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -1160,17 +1160,16 @@ js::RemapWrapper(JSContext *cx, JSObject
 
 // Remap all cross-compartment wrappers pointing to |oldTarget| to point to
 // |newTarget|. All wrappers are recomputed.
 bool
 js::RemapAllWrappersForObject(JSContext *cx, JSObject *oldTarget,
                               JSObject *newTarget)
 {
     Value origv = ObjectValue(*oldTarget);
-    Value targetv = ObjectValue(*newTarget);
 
     AutoValueVector toTransplant(cx);
     if (!toTransplant.reserve(cx->runtime->compartments.length()))
         return false;
 
     for (CompartmentsIter c(cx->runtime); !c.done(); c.next()) {
         WrapperMap &pmap = c->crossCompartmentWrappers;
         if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -488,28 +488,29 @@ NewXMLAttributeName(JSContext *cx, JSLin
         return NULL;
     JS_ASSERT(obj->isQName());
     if (!InitXMLQName(cx, obj, uri, prefix, localName))
         return NULL;
     return obj;
 }
 
 static JSObject *
-ConstructObjectWithArguments(JSContext *cx, Class *clasp, JSObject *parent,
+ConstructObjectWithArguments(JSContext *cx, Class *clasp,
                              unsigned argc, jsval *argv)
 {
-    assertSameCompartment(cx, parent, JSValueArray(argv, argc));
+    assertSameCompartment(cx, JSValueArray(argv, argc));
 
     AutoArrayRooter argtvr(cx, argc, argv);
 
     JSProtoKey protoKey = GetClassProtoKey(clasp);
 
     /* Protect constructor in case a crazy getter for .prototype uproots it. */
     RootedValue value(cx);
-    if (!js_FindClassObject(cx, parent, protoKey, value.address(), clasp))
+    RootedObject null(cx);
+    if (!js_FindClassObject(cx, null, protoKey, &value, clasp))
         return NULL;
 
     Value rval;
     if (!InvokeConstructor(cx, value, argc, argv, &rval))
         return NULL;
 
     /*
      * If the instance's class differs from what was requested, throw a type
@@ -535,17 +536,17 @@ js_ConstructXMLQNameObject(JSContext *cx
      */
     if (nsval.isObject() &&
         nsval.toObject().getClass() == &AnyNameClass) {
         argv[0].setNull();
     } else {
         argv[0] = nsval;
     }
     argv[1] = lnval;
-    return ConstructObjectWithArguments(cx, &QNameClass, NULL, 2, argv);
+    return ConstructObjectWithArguments(cx, &QNameClass, 2, argv);
 }
 
 static JSBool
 IsXMLName(const jschar *cp, size_t n)
 {
     JSBool rv;
     jschar c;
 
@@ -1656,25 +1657,25 @@ fail:
 
 /*
  * XML helper, object-ops, and library functions.  We start with the helpers,
  * in ECMA-357 order, but merging XML (9.1) and XMLList (9.2) helpers.
  */
 static JSBool
 GetXMLSetting(JSContext *cx, const char *name, jsval *vp)
 {
-    jsval v;
-
-    if (!js_FindClassObject(cx, NULL, JSProto_XML, &v))
+    RootedValue v(cx);
+    RootedObject null(cx);
+    if (!js_FindClassObject(cx, null, JSProto_XML, &v))
         return JS_FALSE;
-    if (JSVAL_IS_PRIMITIVE(v) || !JSVAL_TO_OBJECT(v)->isFunction()) {
+    if (v.reference().isPrimitive() || !v.reference().toObject().isFunction()) {
         *vp = JSVAL_VOID;
         return JS_TRUE;
     }
-    return JS_GetProperty(cx, JSVAL_TO_OBJECT(v), name, vp);
+    return JS_GetProperty(cx, &v.reference().toObject(), name, vp);
 }
 
 static JSBool
 GetBooleanXMLSetting(JSContext *cx, const char *name, JSBool *bp)
 {
     jsval v;
 
     return GetXMLSetting(cx, name, &v) && JS_ValueToBoolean(cx, v, bp);
@@ -2267,17 +2268,17 @@ GetNamespace(JSContext *cx, JSObject *qn
             }
         }
     }
 
     /* If we didn't match, make a new namespace from qn. */
     if (!match) {
         argv[0] = prefix ? STRING_TO_JSVAL(prefix) : JSVAL_VOID;
         argv[1] = STRING_TO_JSVAL(uri);
-        ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, 2, argv);
+        ns = ConstructObjectWithArguments(cx, &NamespaceClass, 2, argv);
         if (!ns)
             return NULL;
         match = ns;
     }
     return match;
 }
 
 static JSLinearString *
@@ -2948,17 +2949,17 @@ ToXMLName(JSContext *cx, jsval v, jsid *
         if (!name)
             return NULL;
         *funidp = JSID_VOID;
         return ToAttributeName(cx, STRING_TO_JSVAL(name));
     }
 
 construct:
     v = STRING_TO_JSVAL(name);
-    obj = ConstructObjectWithArguments(cx, &QNameClass, NULL, 1, &v);
+    obj = ConstructObjectWithArguments(cx, &QNameClass, 1, &v);
     if (!obj)
         return NULL;
 
 out:
     JSAtom *localName;
     *funidp = GetLocalNameFromFunctionQName(obj, &localName, cx)
               ? AtomToId(localName)
               : JSID_VOID;
@@ -4626,25 +4627,25 @@ HasIndexedProperty(JSXML *xml, uint32_t 
 }
 
 static JSBool
 HasSimpleContent(JSXML *xml);
 
 static JSBool
 HasFunctionProperty(JSContext *cx, JSObject *obj_, jsid funid_, JSBool *found)
 {
-    JSObject *pobj;
     JSProperty *prop;
     JSXML *xml;
 
     JS_ASSERT(obj_->getClass() == &XMLClass);
 
     RootedId funid(cx, funid_);
 
     Rooted<JSObject*> obj(cx, obj_);
+    RootedObject pobj(cx);
     if (!baseops::LookupProperty(cx, obj, funid, &pobj, &prop))
         return false;
     if (!prop) {
         xml = (JSXML *) obj->getPrivate();
         if (HasSimpleContent(xml)) {
             /*
              * Search in String.prototype to set found whenever
              * GetXMLFunction returns existing function.
@@ -4737,17 +4738,18 @@ HasProperty(JSContext *cx, JSObject *obj
  * We partially workaround the problem in GetXMLFunction. There we take
  * advantage of the fact that typically function:: is used to access the
  * functions from XML.prototype. So when js_GetProperty returns a non-function
  * property, we assume that it represents the result of GetProperty setter
  * hiding the function and use an extra prototype chain lookup to recover it.
  * For a proper solution see bug 355257.
 */
 static JSBool
-xml_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp, JSProperty **propp)
+xml_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
+                  JSProperty **propp)
 {
     JSBool found;
     JSXML *xml;
     uint32_t i;
     JSObject *qn;
 
     RootedId funid(cx);
 
@@ -4758,68 +4760,69 @@ xml_lookupGeneric(JSContext *cx, HandleO
         qn = ToXMLName(cx, IdToJsval(id), funid.address());
         if (!qn)
             return JS_FALSE;
         if (!JSID_IS_VOID(funid))
             return baseops::LookupProperty(cx, obj, funid, objp, propp);
         found = HasNamedProperty(xml, qn);
     }
     if (!found) {
-        *objp = NULL;
+        objp.set(NULL);
         *propp = NULL;
     } else {
         const Shape *shape =
             js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty,
                                  SHAPE_INVALID_SLOT, JSPROP_ENUMERATE,
                                  0, 0);
         if (!shape)
             return JS_FALSE;
 
-        *objp = obj;
+        objp.set(obj);
         *propp = (JSProperty *) shape;
     }
     return JS_TRUE;
 }
 
 static JSBool
-xml_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSObject **objp,
-                   JSProperty **propp)
+xml_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                   MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return xml_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
-xml_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, JSObject **objp,
+xml_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp,
                   JSProperty **propp)
 {
     JSXML *xml = reinterpret_cast<JSXML *>(obj->getPrivate());
     if (!HasIndexedProperty(xml, index)) {
-        *objp = NULL;
+        objp.set(NULL);
         *propp = NULL;
         return true;
     }
 
     jsid id;
     if (!IndexToId(cx, index, &id))
         return false;
 
     const Shape *shape =
         js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, SHAPE_INVALID_SLOT,
                              JSPROP_ENUMERATE, 0, 0);
     if (!shape)
         return false;
 
-    *objp = obj;
+    objp.set(obj);
     *propp = (JSProperty *) shape;
     return true;
 }
 
 static JSBool
-xml_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSObject **objp, JSProperty **propp)
+xml_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                  MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return xml_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 xml_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *v,
                   PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
@@ -5414,43 +5417,43 @@ JS_FRIEND_DATA(Class) js::XMLClass = {
         xml_enumerate,
         xml_typeOf,
         NULL,       /* thisObject     */
         xml_clear
     }
 };
 
 static JSXML *
-StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp)
+StartNonListXMLMethod(JSContext *cx, jsval *vp, MutableHandleObject objp)
 {
     JSXML *xml;
     JSFunction *fun;
     char numBuf[12];
 
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp));
     JS_ASSERT(JSVAL_TO_OBJECT(*vp)->isFunction());
 
-    *objp = ToObject(cx, &vp[1]);
-    if (!*objp)
+    objp.set(ToObject(cx, &vp[1]));
+    if (!objp)
         return NULL;
-    if (!(*objp)->isXML()) {
+    if (!objp->isXML()) {
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);
         return NULL;
     }
-    xml = (JSXML *) (*objp)->getPrivate();
+    xml = (JSXML *) objp->getPrivate();
     if (!xml || xml->xml_class != JSXML_CLASS_LIST)
         return xml;
 
     if (xml->xml_kids.length == 1) {
         xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
         if (xml) {
-            *objp = js_GetXMLObject(cx, xml);
-            if (!*objp)
+            objp.set(js_GetXMLObject(cx, xml));
+            if (!objp)
                 return NULL;
-            vp[1] = OBJECT_TO_JSVAL(*objp);
+            vp[1] = OBJECT_TO_JSVAL(objp);
             return xml;
         }
     }
 
     fun = JSVAL_TO_OBJECT(*vp)->toFunction();
     JS_snprintf(numBuf, sizeof numBuf, "%u", xml->xml_kids.length);
     JSAutoByteString funNameBytes;
     if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
@@ -5469,18 +5472,18 @@ StartNonListXMLMethod(JSContext *cx, jsv
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);      \
         return JS_FALSE;                                                      \
     }                                                                         \
     JSXML *xml = (JSXML *)obj->getPrivate();                                  \
     if (!xml)                                                                 \
         return JS_FALSE
 
 #define NON_LIST_XML_METHOD_PROLOG                                            \
-    RootedObject obj(cx);                                                  \
-    JSXML *xml = StartNonListXMLMethod(cx, vp, obj.address());                \
+    RootedObject obj(cx);                                                     \
+    JSXML *xml = StartNonListXMLMethod(cx, vp, &obj);                         \
     if (!xml)                                                                 \
         return JS_FALSE;                                                      \
     JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST)
 
 static JSBool
 xml_addNamespace(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSObject *ns;
@@ -6683,17 +6686,17 @@ xml_replace(JSContext *cx, unsigned argc
     return JS_TRUE;
 }
 
 static JSBool
 xml_setChildren(JSContext *cx, unsigned argc, jsval *vp)
 {
     RootedObject obj(cx);
 
-    if (!StartNonListXMLMethod(cx, vp, obj.address()))
+    if (!StartNonListXMLMethod(cx, vp, &obj))
         return JS_FALSE;
 
     Rooted<jsid> id(cx, NameToId(cx->runtime->atomState.starAtom));
     *vp = argc != 0 ? vp[2] : JSVAL_VOID;     /* local root */
     if (!PutProperty(cx, obj, id, false, vp))
         return JS_FALSE;
 
     *vp = OBJECT_TO_JSVAL(obj);
@@ -6752,17 +6755,17 @@ xml_setName(JSContext *cx, unsigned argc
         name = vp[2];
         if (!JSVAL_IS_PRIMITIVE(name) &&
             JSVAL_TO_OBJECT(name)->getClass() == &QNameClass &&
             !(nameqn = JSVAL_TO_OBJECT(name))->getNameURI()) {
             name = vp[2] = nameqn->getQNameLocalNameVal();
         }
     }
 
-    nameqn = ConstructObjectWithArguments(cx, &QNameClass, NULL, 1, &name);
+    nameqn = ConstructObjectWithArguments(cx, &QNameClass, 1, &name);
     if (!nameqn)
         return JS_FALSE;
 
     /* ECMA-357 13.4.4.35 Step 4. */
     if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION)
         nameqn->setNameURI(cx->runtime->emptyString);
 
     xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
@@ -6857,25 +6860,25 @@ xml_setNamespace(JSContext *cx, unsigned
     JSObject *ns;
     jsval qnargv[2];
     JSXML *nsowner;
 
     NON_LIST_XML_METHOD_PROLOG;
     if (!JSXML_HAS_NAME(xml))
         return JS_TRUE;
 
-    ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, argc == 0 ? 0 : 1, vp + 2);
+    ns = ConstructObjectWithArguments(cx, &NamespaceClass, argc == 0 ? 0 : 1, vp + 2);
     if (!ns)
         return JS_FALSE;
     vp[0] = OBJECT_TO_JSVAL(ns);
     ns->setNamespaceDeclared(JSVAL_TRUE);
 
     qnargv[0] = OBJECT_TO_JSVAL(ns);
     qnargv[1] = OBJECT_TO_JSVAL(xml->name);
-    qn = ConstructObjectWithArguments(cx, &QNameClass, NULL, 2, qnargv);
+    qn = ConstructObjectWithArguments(cx, &QNameClass, 2, qnargv);
     if (!qn)
         return JS_FALSE;
 
     /*
      * Erratum: setting the namespace of an attribute may cause it to duplicate
      * an already-existing attribute.  To preserve the invariant that there are
      * not multiple attributes with the same name, we delete the existing
      * attribute so that the mutated attribute will not be a duplicate.
@@ -7607,17 +7610,17 @@ js_GetDefaultXMLNamespace(JSContext *cx,
             return JS_FALSE;
         if (!JSVAL_IS_PRIMITIVE(v)) {
             *vp = v;
             return JS_TRUE;
         }
         obj = tmp;
     }
 
-    ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, 0, NULL);
+    ns = ConstructObjectWithArguments(cx, &NamespaceClass, 0, NULL);
     if (!ns)
         return JS_FALSE;
     v = OBJECT_TO_JSVAL(ns);
     if (!obj->defineSpecial(cx, SpecialId::defaultXMLNamespace(), v,
                             JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
     }
     *vp = v;
@@ -7625,17 +7628,17 @@ js_GetDefaultXMLNamespace(JSContext *cx,
 }
 
 JSBool
 js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
 {
     Value argv[2];
     argv[0].setString(cx->runtime->emptyString);
     argv[1] = v;
-    JSObject *ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, 2, argv);
+    JSObject *ns = ConstructObjectWithArguments(cx, &NamespaceClass, 2, argv);
     if (!ns)
         return JS_FALSE;
 
     JSObject &varobj = cx->fp()->varObj();
     if (!varobj.defineSpecial(cx, SpecialId::defaultXMLNamespace(), ObjectValue(*ns),
                               JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
     }
@@ -7728,32 +7731,32 @@ js_GetAnyName(JSContext *cx, jsid *idp)
         v.setObject(*obj);
         SetReservedSlot(global, JSProto_AnyName, v);
     }
     *idp = OBJECT_TO_JSID(&v.toObject());
     return true;
 }
 
 JSBool
-js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *idp)
+js_FindXMLProperty(JSContext *cx, const Value &nameval, MutableHandleObject objp, jsid *idp)
 {
     JSObject *nameobj;
     jsval v;
     JSObject *qn;
     RootedId funid(cx);
-    JSObject *obj, *target, *proto, *pobj;
+    JSObject *obj, *target, *proto;
     JSXML *xml;
     JSBool found;
     JSProperty *prop;
 
     JS_ASSERT(nameval.isObject());
     nameobj = &nameval.toObject();
     if (nameobj->getClass() == &AnyNameClass) {
         v = STRING_TO_JSVAL(cx->runtime->atomState.starAtom);
-        nameobj = ConstructObjectWithArguments(cx, &QNameClass, NULL, 1, &v);
+        nameobj = ConstructObjectWithArguments(cx, &QNameClass, 1, &v);
         if (!nameobj)
             return JS_FALSE;
     } else {
         JS_ASSERT(nameobj->getClass() == &AttributeNameClass ||
                   nameobj->getClass() == &QNameClass);
     }
 
     qn = nameobj;
@@ -7779,25 +7782,26 @@ js_FindXMLProperty(JSContext *cx, const 
                 xml = (JSXML *) target->getPrivate();
                 found = HasNamedProperty(xml, qn);
             } else {
                 if (!HasFunctionProperty(cx, target, funid, &found))
                     return JS_FALSE;
             }
             if (found) {
                 *idp = OBJECT_TO_JSID(nameobj);
-                *objp = target;
+                objp.set(target);
                 return JS_TRUE;
             }
         } else if (!JSID_IS_VOID(funid)) {
+            RootedObject pobj(cx);
             if (!target->lookupGeneric(cx, funid, &pobj, &prop))
                 return JS_FALSE;
             if (prop) {
                 *idp = funid;
-                *objp = target;
+                objp.set(target);
                 return JS_TRUE;
             }
         }
     } while ((obj = obj->enclosingScope()) != NULL);
 
     JSAutoByteString printable;
     JSString *str = ConvertQNameToString(cx, nameobj);
     if (str && js_ValueToPrintable(cx, StringValue(str), &printable)) {
--- a/js/src/jsxml.h
+++ b/js/src/jsxml.h
@@ -249,17 +249,18 @@ js_ConstructXMLQNameObject(JSContext *cx
 
 extern JSBool
 js_GetAnyName(JSContext *cx, jsid *idp);
 
 /*
  * Note: nameval must be either QName, AttributeName, or AnyName.
  */
 extern JSBool
-js_FindXMLProperty(JSContext *cx, const js::Value &nameval, JSObject **objp, jsid *idp);
+js_FindXMLProperty(JSContext *cx, const js::Value &nameval,
+                   js::MutableHandleObject objp, jsid *idp);
 
 extern JSBool
 js_GetXMLMethod(JSContext *cx, js::HandleObject obj, jsid id, js::Value *vp);
 
 extern JSBool
 js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
 
 extern JSBool
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -5065,17 +5065,17 @@ mjit::Compiler::testSingletonProperty(Ha
     while (nobj) {
         if (!nobj->isNative())
             return false;
         if (nobj->getClass()->ops.lookupGeneric)
             return false;
         nobj = nobj->getProto();
     }
 
-    JSObject *holder;
+    RootedObject holder(cx);
     JSProperty *prop = NULL;
     if (!obj->lookupGeneric(cx, id, &holder, &prop))
         return false;
     if (!prop)
         return false;
 
     Shape *shape = (Shape *) prop;
     if (shape->hasDefaultGetter()) {
@@ -5140,17 +5140,17 @@ mjit::Compiler::testSingletonPropertyTyp
         }
         return false;
 
       default:
         return false;
     }
 
     RootedObject proto(cx);
-    if (!js_GetClassPrototype(cx, globalObj, key, proto.address(), NULL))
+    if (!js_GetClassPrototype(cx, globalObj, key, &proto, NULL))
         return false;
 
     return testSingletonProperty(proto, id);
 }
 
 bool
 mjit::Compiler::jsop_getprop_dispatch(PropertyName *name)
 {
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -2680,17 +2680,17 @@ mjit::Compiler::jsop_initprop()
 
     if (!baseobj || monitored(PC)) {
         prepareStubCall(Uses(2));
         masm.move(ImmPtr(name), Registers::ArgReg1);
         INLINE_STUBCALL(stubs::InitProp, REJOIN_FALLTHROUGH);
         return;
     }
 
-    JSObject *holder;
+    RootedObject holder(cx);
     JSProperty *prop = NULL;
     Rooted<jsid> id(cx, NameToId(name));
 #ifdef DEBUG
     bool res =
 #endif
     LookupPropertyWithFlags(cx, baseobj, id, JSRESOLVE_QUALIFIED, &holder, &prop);
     JS_ASSERT(res && prop && holder == baseobj);
 
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -448,17 +448,17 @@ class SetPropCompiler : public PICStubCo
 
         if (clasp->setProperty != JS_StrictPropertyStub)
             return disable("set property hook");
         if (clasp->ops.lookupProperty)
             return disable("ops lookup property hook");
         if (clasp->ops.setProperty)
             return disable("ops set property hook");
 
-        JSObject *holder;
+        RootedObject holder(cx);
         JSProperty *prop = NULL;
 
         /* lookupProperty can trigger recompilations. */
         RecompilationMonitor monitor(cx);
         if (!obj->lookupProperty(cx, name, &holder, &prop))
             return error();
         if (monitor.recompiled())
             return Lookup_Uncacheable;
@@ -647,33 +647,33 @@ IsCacheableProtoChain(JSObject *obj, JSO
         obj = proto;
     }
     return true;
 }
 
 template <typename IC>
 struct GetPropHelper {
     // These fields are set in the constructor and describe a property lookup.
-    JSContext   *cx;
-    JSObject    *obj;
+    JSContext          *cx;
+    RootedObject       obj;
     RootedPropertyName name;
-    IC          &ic;
-    VMFrame     &f;
+    IC                 &ic;
+    VMFrame            &f;
 
     // These fields are set by |bind| and |lookup|. After a call to either
     // function, these are set exactly as they are in JSOP_GETPROP or JSOP_NAME.
-    JSObject    *holder;
-    JSProperty  *prop;
+    RootedObject       holder;
+    JSProperty         *prop;
 
     // This field is set by |bind| and |lookup| only if they returned
     // Lookup_Cacheable, otherwise it is NULL.
     const Shape *shape;
 
     GetPropHelper(JSContext *cx, JSObject *obj, PropertyName *name, IC &ic, VMFrame &f)
-      : cx(cx), obj(obj), name(cx, name), ic(ic), f(f), holder(NULL), prop(NULL), shape(NULL)
+      : cx(cx), obj(cx, obj), name(cx, name), ic(ic), f(f), holder(cx), prop(NULL), shape(NULL)
     { }
 
   public:
     LookupStatus bind() {
         RecompilationMonitor monitor(cx);
         RootedObject scopeChain(cx, cx->stack.currentScriptedScopeChain());
         if (js_CodeSpec[*f.pc()].format & JOF_GNAME)
             scopeChain = &scopeChain->global();
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -187,17 +187,17 @@ stubs::ToId(VMFrame &f)
 }
 
 void JS_FASTCALL
 stubs::ImplicitThis(VMFrame &f, PropertyName *name_)
 {
     RootedObject scopeObj(f.cx, f.cx->stack.currentScriptedScopeChain());
     RootedPropertyName name(f.cx, name_);
 
-    JSObject *obj, *obj2;
+    RootedObject obj(f.cx), obj2(f.cx);
     JSProperty *prop;
     if (!FindPropertyHelper(f.cx, name, false, scopeObj, &obj, &obj2, &prop))
         THROW();
 
     if (!ComputeImplicitThis(f.cx, obj, &f.regs.sp[0]))
         THROW();
 }
 
@@ -334,17 +334,17 @@ stubs::DefFun(VMFrame &f, JSFunction *fu
      * current scope chain even for the case of function expression statements
      * and functions defined by eval inside let or with blocks.
      */
     Rooted<JSObject*> parent(cx, &fp->varObj());
 
     /* ES5 10.5 (NB: with subsequent errata). */
     PropertyName *name = fun->atom->asPropertyName();
     JSProperty *prop = NULL;
-    JSObject *pobj;
+    RootedObject pobj(cx);
     if (!parent->lookupProperty(cx, name, &pobj, &prop))
         THROW();
 
     Value rval = ObjectValue(*fun);
 
     do {
         /* Steps 5d, 5f. */
         if (!prop || pobj != parent) {
@@ -1333,17 +1333,17 @@ stubs::Pos(VMFrame &f)
 }
 
 void JS_FASTCALL
 stubs::DelName(VMFrame &f, PropertyName *name_)
 {
     RootedObject scopeObj(f.cx, f.cx->stack.currentScriptedScopeChain());
     RootedPropertyName name(f.cx, name_);
 
-    JSObject *obj, *obj2;
+    RootedObject obj(f.cx), obj2(f.cx);
     JSProperty *prop;
     if (!FindProperty(f.cx, name, scopeObj, &obj, &obj2, &prop))
         THROW();
 
     /* Strict mode code should never contain JSOP_DELNAME opcodes. */
     JS_ASSERT(!f.script()->strictModeCode);
 
     /* ECMA says to return true if name is undefined or inherited. */
@@ -1433,17 +1433,17 @@ stubs::In(VMFrame &f)
         THROWV(JS_FALSE);
     }
 
     JSObject *obj = &rref.toObject();
     RootedId id(cx);
     if (!FetchElementId(f.cx, obj, f.regs.sp[-2], id.address(), &f.regs.sp[-2]))
         THROWV(JS_FALSE);
 
-    JSObject *obj2;
+    RootedObject obj2(cx);
     JSProperty *prop;
     if (!obj->lookupGeneric(cx, id, &obj2, &prop))
         THROWV(JS_FALSE);
 
     return !!prop;
 }
 
 template void JS_FASTCALL stubs::DelElem<true>(VMFrame &f);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2484,34 +2484,34 @@ sandbox_enumerate(JSContext *cx, HandleO
         return false;
 
     JS_ValueToBoolean(cx, v, &b);
     return !b || JS_EnumerateStandardClasses(cx, obj);
 }
 
 static JSBool
 sandbox_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                JSObject **objp)
+                MutableHandleObject objp)
 {
     jsval v;
     JSBool b, resolved;
 
     if (!JS_GetProperty(cx, obj, "lazy", &v))
         return false;
 
     JS_ValueToBoolean(cx, v, &b);
     if (b && (flags & JSRESOLVE_ASSIGNING) == 0) {
         if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
             return false;
         if (resolved) {
-            *objp = obj;
+            objp.set(obj);
             return true;
         }
     }
-    *objp = NULL;
+    objp.set(NULL);
     return true;
 }
 
 static JSClass sandbox_class = {
     "sandbox",
     JSCLASS_NEW_RESOLVE | JSCLASS_GLOBAL_FLAGS,
     JS_PropertyStub,   JS_PropertyStub,
     JS_PropertyStub,   JS_StrictPropertyStub,
@@ -2682,24 +2682,24 @@ ShapeOf(JSContext *cx, unsigned argc, JS
 
 /*
  * If referent has an own property named id, copy that property to obj[id].
  * Since obj is native, this isn't totally transparent; properties of a
  * non-native referent may be simplified to data properties.
  */
 static JSBool
 CopyProperty(JSContext *cx, HandleObject obj, HandleObject referent, HandleId id,
-             unsigned lookupFlags, JSObject **objp)
+             unsigned lookupFlags, MutableHandleObject objp)
 {
     JSProperty *prop;
     PropertyDescriptor desc;
     unsigned propFlags = 0;
-    JSObject *obj2;
-
-    *objp = NULL;
+    RootedObject obj2(cx);
+
+    objp.set(NULL);
     if (referent->isNative()) {
         if (!LookupPropertyWithFlags(cx, referent, id, lookupFlags, &obj2, &prop))
             return false;
         if (obj2 != referent)
             return true;
 
         const Shape *shape = (Shape *) prop;
         if (shape->hasSlot()) {
@@ -2721,50 +2721,51 @@ CopyProperty(JSContext *cx, HandleObject
         PropertyDescriptor desc;
         if (!Proxy::getOwnPropertyDescriptor(cx, referent, id, false, &desc))
             return false;
         if (!desc.obj)
             return true;
     } else {
         if (!referent->lookupGeneric(cx, id, objp, &prop))
             return false;
-        if (*objp != referent)
+        if (objp != referent)
             return true;
         if (!referent->getGeneric(cx, id, &desc.value) ||
             !referent->getGenericAttributes(cx, id, &desc.attrs)) {
             return false;
         }
         desc.attrs &= JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
         desc.getter = JS_PropertyStub;
         desc.setter = JS_StrictPropertyStub;
         desc.shortid = 0;
     }
 
-    *objp = obj;
+    objp.set(obj);
     return !!DefineNativeProperty(cx, obj, id, desc.value, desc.getter, desc.setter,
                                   desc.attrs, propFlags, desc.shortid);
 }
 
 static JSBool
-resolver_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, JSObject **objp)
+resolver_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
+                 MutableHandleObject objp)
 {
     jsval v = JS_GetReservedSlot(obj, 0);
     Rooted<JSObject*> vobj(cx, &v.toObject());
     return CopyProperty(cx, obj, vobj, id, flags, objp);
 }
 
 static JSBool
 resolver_enumerate(JSContext *cx, HandleObject obj)
 {
     jsval v = JS_GetReservedSlot(obj, 0);
     RootedObject referent(cx, JSVAL_TO_OBJECT(v));
 
     AutoIdArray ida(cx, JS_Enumerate(cx, referent));
     bool ok = !!ida;
-    JSObject *ignore;
+    RootedObject ignore(cx);
     for (size_t i = 0; ok && i < ida.length(); i++) {
         Rooted<jsid> id(cx, ida[i]);
         ok = CopyProperty(cx, obj, referent, id, JSRESOLVE_QUALIFIED, &ignore);
     }
     return ok;
 }
 
 static JSClass resolver_class = {
@@ -3956,17 +3957,17 @@ its_enumerate(JSContext *cx, HandleObjec
         break;
     }
 
     return true;
 }
 
 static JSBool
 its_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-            JSObject **objp)
+            MutableHandleObject objp)
 {
     if (its_noisy) {
         IdStringifier idString(cx, id);
         fprintf(gOutFile, "resolving its property %s, flags {%s,%s,%s}\n",
                idString.getBytes(),
                (flags & JSRESOLVE_QUALIFIED) ? "qualified" : "",
                (flags & JSRESOLVE_ASSIGNING) ? "assigning" : "",
                (flags & JSRESOLVE_DETECTING) ? "detecting" : "");
@@ -4270,25 +4271,25 @@ global_enumerate(JSContext *cx, HandleOb
     return JS_EnumerateStandardClasses(cx, obj);
 #else
     return true;
 #endif
 }
 
 static JSBool
 global_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-               JSObject **objp)
+               MutableHandleObject objp)
 {
 #ifdef LAZY_STANDARD_CLASSES
     JSBool resolved;
 
     if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
         return false;
     if (resolved) {
-        *objp = obj;
+        objp.set(obj);
         return true;
     }
 #endif
 
 #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
     if (!(flags & JSRESOLVE_QUALIFIED)) {
         /*
          * Do this expensive hack only for unoptimized Unix builds, which are
@@ -4325,17 +4326,17 @@ global_resolve(JSContext *cx, HandleObje
             found = (access(full, X_OK) == 0);
             if (*comp != '\0')
                 free(full);
             if (found) {
                 fun = JS_DefineFunction(cx, obj, name, Exec, 0,
                                         JSPROP_ENUMERATE);
                 ok = (fun != NULL);
                 if (ok)
-                    *objp = obj;
+                    objp.set(obj);
                 break;
             }
         }
         JS_free(cx, path);
         return ok;
     }
 #else
     return true;
@@ -4419,17 +4420,17 @@ env_enumerate(JSContext *cx, HandleObjec
     }
 
     reflected = true;
     return true;
 }
 
 static JSBool
 env_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-            JSObject **objp)
+            MutableHandleObject objp)
 {
     JSString *valstr;
     const char *name, *value;
 
     if (flags & JSRESOLVE_ASSIGNING)
         return true;
 
     IdStringifier idstr(cx, id, true);
@@ -4441,17 +4442,17 @@ env_resolve(JSContext *cx, HandleObject 
     if (value) {
         valstr = JS_NewStringCopyZ(cx, value);
         if (!valstr)
             return false;
         if (!JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
                                NULL, NULL, JSPROP_ENUMERATE)) {
             return false;
         }
-        *objp = obj;
+        objp.set(obj);
     }
     return true;
 }
 
 static JSClass env_class = {
     "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
     JS_PropertyStub,  JS_PropertyStub,
     JS_PropertyStub,  env_setProperty,
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -203,19 +203,19 @@ ArgSetter(JSContext *cx, HandleObject ob
      */
     RootedValue value(cx);
     return baseops::DeleteGeneric(cx, obj, id, value.address(), false) &&
            baseops::DefineGeneric(cx, obj, id, vp, NULL, NULL, JSPROP_ENUMERATE);
 }
 
 static JSBool
 args_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-             JSObject **objp)
+             MutableHandleObject objp)
 {
-    *objp = NULL;
+    objp.set(NULL);
 
     Rooted<NormalArgumentsObject*> argsobj(cx, &obj->asNormalArguments());
 
     unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
     if (JSID_IS_INT(id)) {
         uint32_t arg = uint32_t(JSID_TO_INT(id));
         if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg))
             return true;
@@ -231,17 +231,17 @@ args_resolve(JSContext *cx, HandleObject
         if (argsobj->callee().isMagic(JS_OVERWRITTEN_CALLEE))
             return true;
     }
 
     Value undef = UndefinedValue();
     if (!baseops::DefineGeneric(cx, argsobj, id, &undef, ArgGetter, ArgSetter, attrs))
         return JS_FALSE;
 
-    *objp = argsobj;
+    objp.set(argsobj);
     return true;
 }
 
 static JSBool
 args_enumerate(JSContext *cx, HandleObject obj)
 {
     Rooted<NormalArgumentsObject*> argsobj(cx, &obj->asNormalArguments());
     RootedId id(cx);
@@ -253,17 +253,17 @@ args_enumerate(JSContext *cx, HandleObje
     int argc = int(argsobj->initialLength());
     for (int i = -2; i != argc; i++) {
         id = (i == -2)
              ? NameToId(cx->runtime->atomState.lengthAtom)
              : (i == -1)
              ? NameToId(cx->runtime->atomState.calleeAtom)
              : INT_TO_JSID(i);
 
-        JSObject *pobj;
+        RootedObject pobj(cx);
         JSProperty *prop;
         if (!baseops::LookupProperty(cx, argsobj, id, &pobj, &prop))
             return false;
     }
     return true;
 }
 
 static JSBool
@@ -315,19 +315,20 @@ StrictArgSetter(JSContext *cx, HandleObj
      * collect its value.
      */
     RootedValue value(cx);
     return baseops::DeleteGeneric(cx, argsobj, id, value.address(), strict) &&
            baseops::SetPropertyHelper(cx, argsobj, argsobj, id, 0, vp, strict);
 }
 
 static JSBool
-strictargs_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, JSObject **objp)
+strictargs_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
+                   MutableHandleObject objp)
 {
-    *objp = NULL;
+    objp.set(NULL);
 
     Rooted<StrictArgumentsObject*> argsobj(cx, &obj->asStrictArguments());
 
     unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
     PropertyOp getter = StrictArgGetter;
     StrictPropertyOp setter = StrictArgSetter;
 
     if (JSID_IS_INT(id)) {
@@ -349,30 +350,30 @@ strictargs_resolve(JSContext *cx, Handle
         getter = CastAsPropertyOp(argsobj->global().getThrowTypeError());
         setter = CastAsStrictPropertyOp(argsobj->global().getThrowTypeError());
     }
 
     Value undef = UndefinedValue();
     if (!baseops::DefineGeneric(cx, argsobj, id, &undef, getter, setter, attrs))
         return false;
 
-    *objp = argsobj;
+    objp.set(argsobj);
     return true;
 }
 
 static JSBool
 strictargs_enumerate(JSContext *cx, HandleObject obj)
 {
     Rooted<StrictArgumentsObject*> argsobj(cx, &obj->asStrictArguments());
 
     /*
      * Trigger reflection in strictargs_resolve using a series of
      * js_LookupProperty calls.
      */
-    JSObject *pobj;
+    RootedObject pobj(cx);
     JSProperty *prop;
     RootedId id(cx);
 
     // length
     id = NameToId(cx->runtime->atomState.lengthAtom);
     if (!baseops::LookupProperty(cx, argsobj, id, &pobj, &prop))
         return false;
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4409,17 +4409,17 @@ DebuggerEnv_find(JSContext *cx, unsigned
     {
         AutoCompartment ac(cx, env);
         if (!ac.enter() || !cx->compartment->wrapId(cx, id.address()))
             return false;
 
         /* This can trigger resolve hooks. */
         ErrorCopier ec(ac, dbg->toJSObject());
         JSProperty *prop = NULL;
-        JSObject *pobj;
+        RootedObject pobj(cx);
         for (; env && !prop; env = env->enclosingScope()) {
             if (!env->lookupGeneric(cx, id, &pobj, &prop))
                 return false;
             if (prop)
                 break;
         }
     }
 
--- a/js/src/vm/ObjectImpl.cpp
+++ b/js/src/vm/ObjectImpl.cpp
@@ -509,17 +509,17 @@ js::GetOwnProperty(JSContext *cx, Handle
         Class *clasp = obj->getClass();
         JSResolveOp resolve = clasp->resolve;
         if (resolve != JS_ResolveStub) {
             Rooted<jsid> id(cx, pid.reference().asId());
             Rooted<JSObject*> robj(cx, static_cast<JSObject*>(obj.value()));
             if (clasp->flags & JSCLASS_NEW_RESOLVE) {
                 Rooted<JSObject*> obj2(cx, NULL);
                 JSNewResolveOp op = reinterpret_cast<JSNewResolveOp>(resolve);
-                if (!op(cx, robj, id, resolveFlags, obj2.address()))
+                if (!op(cx, robj, id, resolveFlags, &obj2))
                     return false;
             } else {
                 if (!resolve(cx, robj, id))
                     return false;
             }
         }
 
         /* Now look it up again. */
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -345,40 +345,43 @@ WithObject::create(JSContext *cx, Handle
         return NULL;
 
     obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp));
 
     return &obj->asWith();
 }
 
 static JSBool
-with_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp, JSProperty **propp)
+with_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
+                   MutableHandleObject objp, JSProperty **propp)
 {
     return obj->asWith().object().lookupGeneric(cx, id, objp, propp);
 }
 
 static JSBool
-with_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSObject **objp, JSProperty **propp)
+with_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                    MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return with_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
-with_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, JSObject **objp,
+with_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp,
                    JSProperty **propp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return with_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
-with_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSObject **objp, JSProperty **propp)
+with_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                   MutableHandleObject objp, JSProperty **propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return with_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 with_GetGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, Value *vp)
 {
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -896,17 +896,17 @@ env_enumerate(JSContext *cx, JSHandleObj
     }
 
     reflected = true;
     return true;
 }
 
 static JSBool
 env_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
-            JSObject **objp)
+            JSMutableHandleObject objp)
 {
     JSString *idstr, *valstr;
 
     if (flags & JSRESOLVE_ASSIGNING)
         return true;
 
     jsval idval;
     if (!JS_IdToValue(cx, id, &idval))
@@ -922,17 +922,17 @@ env_resolve(JSContext *cx, JSHandleObjec
     if (value) {
         valstr = JS_NewStringCopyZ(cx, value);
         if (!valstr)
             return false;
         if (!JS_DefinePropertyById(cx, obj, id, STRING_TO_JSVAL(valstr),
                                    NULL, NULL, JSPROP_ENUMERATE)) {
             return false;
         }
-        *objp = obj;
+        objp.set(obj);
     }
     return true;
 }
 
 static JSClass env_class = {
     "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
     JS_PropertyStub,  JS_PropertyStub,
     JS_PropertyStub,  env_setProperty,
--- a/js/xpconnect/src/XPCRuntimeService.cpp
+++ b/js/xpconnect/src/XPCRuntimeService.cpp
@@ -32,33 +32,37 @@ NS_IMPL_THREADSAFE_RELEASE(BackstagePass
                             nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES
 #include "xpc_map_end.h" /* This will #undef the above */
 
 /* bool newResolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval id, in PRUint32 flags, out JSObjectPtr objp); */
 NS_IMETHODIMP
 BackstagePass::NewResolve(nsIXPConnectWrappedNative *wrapper,
                           JSContext * cx, JSObject * obj_,
                           jsid id_, PRUint32 flags,
-                          JSObject * *objp, bool *_retval)
+                          JSObject * *objp_, bool *_retval)
 {
     JS::RootedObject obj(cx, obj_);
     JS::RootedId id(cx, id_);
 
     JSBool resolved;
 
     *_retval = !!JS_ResolveStandardClass(cx, obj, id, &resolved);
-    if (!*_retval)
-        return NS_OK;
-
-    if (resolved) {
-        *objp = obj;
+    if (!*_retval) {
+        *objp_ = nsnull;
         return NS_OK;
     }
 
-    *_retval = !!ResolveWorkerClasses(cx, obj, id, flags, objp);
+    if (resolved) {
+        *objp_ = obj;
+        return NS_OK;
+    }
+
+    JS::RootedObject objp(cx, *objp_);
+    *_retval = !!ResolveWorkerClasses(cx, obj, id, flags, &objp);
+    *objp_ = objp;
     return NS_OK;
 }
 
 /***************************************************************************/
 /* void getInterfaces (out PRUint32 count, [array, size_is (count), retval]
                        out nsIIDPtr array); */
 NS_IMETHODIMP
 BackstagePass::GetInterfaces(PRUint32 *aCount, nsIID * **aArray)
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -999,17 +999,17 @@ XPC_WN_Helper_HasInstance(JSContext *cx,
 static void
 XPC_WN_Helper_Finalize(js::FreeOp *fop, JSObject *obj)
 {
     WrappedNativeFinalize(fop, obj, WN_HELPER);
 }
 
 static JSBool
 XPC_WN_Helper_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
-                         JSObject **objp)
+                         JSMutableHandleObject objp)
 {
     nsresult rv = NS_OK;
     bool retval = true;
     JSObject* obj2FromScriptable = nsnull;
     if (IS_SLIM_WRAPPER(obj)) {
         XPCNativeScriptableInfo *si =
             GetSlimWrapperProto(obj)->GetScriptableInfo();
         if (!si->GetFlags().WantNewResolve())
@@ -1020,17 +1020,17 @@ XPC_WN_Helper_NewResolve(JSContext *cx, 
                      "We don't support these flags for slim wrappers!");
 
         rv = si->GetCallback()->NewResolve(nsnull, cx, obj, id, flags,
                                            &obj2FromScriptable, &retval);
         if (NS_FAILED(rv))
             return Throw(rv, cx);
 
         if (obj2FromScriptable)
-            *objp = obj2FromScriptable;
+            objp.set(obj2FromScriptable);
 
         return retval;
     }
 
     XPCCallContext ccx(JS_CALLER, cx, obj);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
@@ -1054,17 +1054,17 @@ XPC_WN_Helper_NewResolve(JSContext *cx, 
     old = ccx.SetResolveName(old);
     NS_ASSERTION(old == id, "bad nest");
 
     if (NS_FAILED(rv)) {
         return Throw(rv, cx);
     }
 
     if (obj2FromScriptable) {
-        *objp = obj2FromScriptable;
+        objp.set(obj2FromScriptable);
     } else if (wrapper->HasMutatedSet()) {
         // We are here if scriptable did not resolve this property and
         // it *might* be in the instance set but not the proto set.
 
         XPCNativeSet* set = wrapper->GetSet();
         XPCNativeSet* protoSet = wrapper->HasProto() ?
                                     wrapper->GetProto()->GetSet() : nsnull;
         XPCNativeMember* member;
@@ -1091,17 +1091,17 @@ XPC_WN_Helper_NewResolve(JSContext *cx, 
                                            set, iface, member,
                                            wrapper->GetScope(),
                                            false,
                                            wrapperForInterfaceNames,
                                            nsnull, si,
                                            enumFlag, &resolved);
             (void)ccx.SetResolvingWrapper(oldResolvingWrapper);
             if (retval && resolved)
-                *objp = obj;
+                objp.set(obj);
         }
     }
 
     return retval;
 }
 
 /***************************************************************************/