Bug 863289 - GC: Continue the rooting of XPConnect r=bholley
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 17 Apr 2013 16:38:44 +0100
changeset 129565 aa442c0ebfb229e8cce48d2726faba742f79b489
parent 129564 3fb99a9ab106d18da2e8050bc1d391e213337d3a
child 129566 cbf65101089e22dbffaaabd654b1e4ed7ed8837e
push id26903
push userjcoppeard@mozilla.com
push dateTue, 23 Apr 2013 09:58:13 +0000
treeherdermozilla-inbound@7712c68becc6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs863289
milestone23.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 863289 - GC: Continue the rooting of XPConnect r=bholley
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/wrappers/AccessCheck.cpp
js/xpconnect/wrappers/ChromeObjectWrapper.cpp
js/xpconnect/wrappers/WrapperFactory.cpp
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -24,16 +24,17 @@
 #include "jsfriendapi.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/PrimitiveConversions.h"
 
 using namespace xpc;
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace JS;
 
 //#define STRICT_CHECK_OF_UNICODE
 #ifdef STRICT_CHECK_OF_UNICODE
 #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF80))
 #else // STRICT_CHECK_OF_UNICODE
 #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF00))
 #endif // STRICT_CHECK_OF_UNICODE
 
@@ -164,17 +165,17 @@ XPCConvert::NativeData2JS(XPCLazyCallCon
             XPC_LOG_ERROR(("XPCConvert::NativeData2JS : void* params not supported"));
             return false;
 
         case nsXPTType::T_IID:
             {
                 nsID* iid2 = *((nsID**)s);
                 if (!iid2)
                     break;
-                JS::RootedObject scope(cx, lccx.GetScopeForNewJSObjects());
+                RootedObject scope(cx, lccx.GetScopeForNewJSObjects());
                 JSObject* obj;
                 if (!(obj = xpc_NewIDObject(cx, scope, *iid2)))
                     return false;
                 *d = OBJECT_TO_JSVAL(obj);
                 break;
             }
 
         case nsXPTType::T_ASTRING:
@@ -364,17 +365,17 @@ CheckJSCharInCharRange(jschar c)
 template<typename T>
 bool ConvertToPrimitive(JSContext *cx, const JS::Value& v, T *retval)
 {
     return ValueToPrimitive<T, eDefault>(cx, v, retval);
 }
 
 // static
 JSBool
-XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s,
+XPCConvert::JSData2Native(JSContext* cx, void* d, HandleValue s,
                           const nsXPTType& type,
                           JSBool useAllocator, const nsID* iid,
                           nsresult* pErr)
 {
     NS_PRECONDITION(d, "bad param");
 
     JSBool isDOMString = true;
 
@@ -749,28 +750,28 @@ XPCConvert::JSData2Native(JSContext* cx,
 
         // only wrap JSObjects
         if (!s.isObject()) {
             if (pErr && s.isInt32() && 0 == s.toInt32())
                 *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL;
             return false;
         }
 
-        return JSObject2NativeInterface(cx, (void**)d, &s.toObject(), iid,
-                                        nullptr, pErr);
+        RootedObject src(cx, &s.toObject());
+        return JSObject2NativeInterface(cx, (void**)d, src, iid, nullptr, pErr);
     }
     default:
         NS_ERROR("bad type");
         return false;
     }
     return true;
 }
 
 inline JSBool
-CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj, jsval* d,
+CreateHolderIfNeeded(XPCCallContext& ccx, HandleObject obj, jsval* d,
                      nsIXPConnectJSObjectHolder** dest)
 {
     if (dest) {
         XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(ccx, obj);
         if (!objHolder)
             return false;
 
         NS_ADDREF(*dest = objHolder);
@@ -825,17 +826,17 @@ XPCConvert::NativeInterface2JSObject(XPC
     // Note: If |cache->IsProxy()| is true, then it means that the object
     // implementing it doesn't want a wrapped native as its JS Object, but
     // instead it provides its own proxy object. In that case, the object
     // to use is found as cache->GetWrapper(). If that is null, then the
     // object will create (and fill the cache) from its WrapObject call.
     nsWrapperCache *cache = aHelper.GetWrapperCache();
 
     bool tryConstructSlimWrapper = false;
-    JS::RootedObject flat(cx);
+    RootedObject flat(cx);
     if (cache) {
         flat = cache->GetWrapper();
         if (cache->IsDOMBinding()) {
             XPCCallContext &ccx = lccx.GetXPCCallContext();
             if (!ccx.IsValid())
                 return false;
 
             if (!flat) {
@@ -869,17 +870,17 @@ XPCConvert::NativeInterface2JSObject(XPC
 
     // If we're not handing this wrapper to an nsIXPConnectJSObjectHolder, and
     // the object supports slim wrappers, try to create one here.
     if (tryConstructSlimWrapper) {
         XPCCallContext &ccx = lccx.GetXPCCallContext();
         if (!ccx.IsValid())
             return false;
 
-        jsval slim;
+        RootedValue slim(cx);
         if (ConstructSlimWrapper(ccx, aHelper, xpcscope, &slim)) {
             *d = slim;
             return true;
         }
 
         if (JS_IsExceptionPending(cx))
             return false;
 
@@ -970,17 +971,17 @@ XPCConvert::NativeInterface2JSObject(XPC
             *dest = strongWrapper.forget().get();
         if (pErr)
             *pErr = NS_OK;
         return true;
     }
 
     // The call to wrap here handles both cross-compartment and same-compartment
     // security wrappers.
-    JSObject *original = flat;
+    RootedObject original(cx, flat);
     if (!JS_WrapObject(ccx, flat.address()))
         return false;
 
     *d = OBJECT_TO_JSVAL(flat);
 
     if (dest) {
         // The strongWrapper still holds the original flat object.
         if (flat == original) {
@@ -1001,17 +1002,17 @@ XPCConvert::NativeInterface2JSObject(XPC
     return true;
 }
 
 /***************************************************************************/
 
 // static
 JSBool
 XPCConvert::JSObject2NativeInterface(JSContext* cx,
-                                     void** dest, JSObject* src,
+                                     void** dest, HandleObject src,
                                      const nsID* iid,
                                      nsISupports* aOuter,
                                      nsresult* pErr)
 {
     NS_ASSERTION(dest, "bad param");
     NS_ASSERTION(src, "bad param");
     NS_ASSERTION(iid, "bad param");
 
@@ -1148,33 +1149,34 @@ public:
 
     ~AutoExceptionRestorer()
     {
         JS_SetPendingException(mContext, tvr.jsval_value());
     }
 
 private:
     JSContext * const mContext;
-    JS::AutoValueRooter tvr;
+    AutoValueRooter tvr;
 };
 
 // static
 nsresult
 XPCConvert::JSValToXPCException(XPCCallContext& ccx,
-                                jsval s,
+                                jsval sArg,
                                 const char* ifaceName,
                                 const char* methodName,
                                 nsIException** exceptn)
 {
     JSContext* cx = ccx.GetJSContext();
+    RootedValue s(cx, sArg);
     AutoExceptionRestorer aer(cx, s);
 
     if (!JSVAL_IS_PRIMITIVE(s)) {
         // we have a JSObject
-        JSObject* obj = JSVAL_TO_OBJECT(s);
+        RootedObject obj(cx, JSVAL_TO_OBJECT(s));
 
         if (!obj) {
             NS_ERROR("when is an object not an object?");
             return NS_ERROR_FAILURE;
         }
 
         // is this really a native xpcom object with a wrapper?
         JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
@@ -1250,24 +1252,24 @@ XPCConvert::JSValToXPCException(XPCCallC
                 return NS_ERROR_FAILURE;
 
             JSAutoByteString strBytes(cx, str);
             if (!strBytes)
                 return NS_ERROR_FAILURE;
 
             return ConstructException(NS_ERROR_XPC_JS_THREW_JS_OBJECT,
                                       strBytes.ptr(), ifaceName, methodName,
-                                      nullptr, exceptn, cx, &s);
+                                      nullptr, exceptn, cx, s.address());
         }
     }
 
     if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
         return ConstructException(NS_ERROR_XPC_JS_THREW_NULL,
                                   nullptr, ifaceName, methodName, nullptr,
-                                  exceptn, cx, &s);
+                                  exceptn, cx, s.address());
     }
 
     if (JSVAL_IS_NUMBER(s)) {
         // lets see if it looks like an nsresult
         nsresult rv;
         double number;
         JSBool isResult = false;
 
@@ -1288,46 +1290,46 @@ XPCConvert::JSValToXPCException(XPCCallC
                 rv = (nsresult)(uint32_t) number;
                 if (NS_FAILED(rv))
                     isResult = true;
             }
         }
 
         if (isResult)
             return ConstructException(rv, nullptr, ifaceName, methodName,
-                                      nullptr, exceptn, cx, &s);
+                                      nullptr, exceptn, cx, s.address());
         else {
             // XXX all this nsISupportsDouble code seems a little redundant
             // now that we're storing the jsval in the exception...
             nsISupportsDouble* data;
             nsCOMPtr<nsIComponentManager> cm;
             if (NS_FAILED(NS_GetComponentManager(getter_AddRefs(cm))) || !cm ||
                 NS_FAILED(cm->CreateInstanceByContractID(NS_SUPPORTS_DOUBLE_CONTRACTID,
                                                          nullptr,
                                                          NS_GET_IID(nsISupportsDouble),
                                                          (void**)&data)))
                 return NS_ERROR_FAILURE;
             data->SetData(number);
             rv = ConstructException(NS_ERROR_XPC_JS_THREW_NUMBER, nullptr,
-                                    ifaceName, methodName, data, exceptn, cx, &s);
+                                    ifaceName, methodName, data, exceptn, cx, s.address());
             NS_RELEASE(data);
             return rv;
         }
     }
 
     // otherwise we'll just try to convert it to a string
     // Note: e.g., JSBools get converted to JSStrings by this code.
 
     JSString* str = JS_ValueToString(cx, s);
     if (str) {
         JSAutoByteString strBytes(cx, str);
         if (!!strBytes) {
             return ConstructException(NS_ERROR_XPC_JS_THREW_STRING,
                                       strBytes.ptr(), ifaceName, methodName,
-                                      nullptr, exceptn, cx, &s);
+                                      nullptr, exceptn, cx, s.address());
         }
     }
     return NS_ERROR_FAILURE;
 }
 
 /********************************/
 
 // static
@@ -1655,17 +1657,17 @@ XPCConvert::JSArray2Native(JSContext* cx
     }
 
     if (!s.isObject()) {
         if (pErr)
             *pErr = NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY;
         return false;
     }
 
-    JSObject* jsarray = &s.toObject();
+    RootedObject jsarray(cx, &s.toObject());
 
     // If this is a typed array, then try a fast conversion with memcpy.
     if (JS_IsTypedArrayObject(jsarray)) {
         return JSTypedArray2Native(d, jsarray, count, type, pErr);
     }
 
     if (!JS_IsArrayObject(cx, jsarray)) {
         if (pErr)
@@ -1678,42 +1680,42 @@ XPCConvert::JSArray2Native(JSContext* cx
         if (pErr)
             *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
         return false;
     }
 
     if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
 
-#define POPULATE(_mode, _t)                                                   \
-    PR_BEGIN_MACRO                                                            \
-        cleanupMode = _mode;                                                  \
-        size_t max = UINT32_MAX / sizeof(_t);                              \
-        if (count > max ||                                                    \
+#define POPULATE(_mode, _t)                                                    \
+    PR_BEGIN_MACRO                                                             \
+        cleanupMode = _mode;                                                   \
+        size_t max = UINT32_MAX / sizeof(_t);                                  \
+        if (count > max ||                                                     \
             nullptr == (array = nsMemory::Alloc(count * sizeof(_t)))) {        \
-            if (pErr)                                                         \
-                *pErr = NS_ERROR_OUT_OF_MEMORY;                               \
-            goto failure;                                                     \
-        }                                                                     \
-        for (initedCount = 0; initedCount < count; initedCount++) {           \
-            if (!JS_GetElement(cx, jsarray, initedCount, &current) ||         \
-                !JSData2Native(cx, ((_t*)array)+initedCount, current, type,  \
-                               true, iid, pErr))                              \
-                goto failure;                                                 \
-        }                                                                     \
+            if (pErr)                                                          \
+                *pErr = NS_ERROR_OUT_OF_MEMORY;                                \
+            goto failure;                                                      \
+        }                                                                      \
+        for (initedCount = 0; initedCount < count; initedCount++) {            \
+            if (!JS_GetElement(cx, jsarray, initedCount, current.address()) || \
+                !JSData2Native(cx, ((_t*)array)+initedCount, current, type,    \
+                               true, iid, pErr))                               \
+                goto failure;                                                  \
+        }                                                                      \
     PR_END_MACRO
 
     // No Action, FRee memory, RElease object
     enum CleanupMode {na, fr, re};
 
     CleanupMode cleanupMode;
 
     void *array = nullptr;
     uint32_t initedCount;
-    jsval current;
+    RootedValue current(cx);
 
     // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
     // XXX make extra space at end of char* and wchar* and null termintate
 
     switch (type.TagPart()) {
     case nsXPTType::T_I8            : POPULATE(na, int8_t);         break;
     case nsXPTType::T_I16           : POPULATE(na, int16_t);        break;
     case nsXPTType::T_I32           : POPULATE(na, int32_t);        break;
--- a/js/xpconnect/src/XPCQuickStubs.cpp
+++ b/js/xpconnect/src/XPCQuickStubs.cpp
@@ -9,16 +9,17 @@
 #include "jsfriendapi.h"
 #include "nsCOMPtr.h"
 #include "xpcprivate.h"
 #include "XPCInlines.h"
 #include "XPCQuickStubs.h"
 #include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
+using namespace JS;
 
 extern const char* xpc_qsStringTable;
 
 static inline QITableEntry *
 GetOffsets(nsISupports *identity, XPCWrappedNativeProto* proto)
 {
     QITableEntry* offsets = proto ? proto->GetOffsets() : nullptr;
     if (!offsets) {
@@ -94,31 +95,32 @@ PointerFinalize(JSFreeOp *fop, JSObject 
 JSClass
 PointerHolderClass = {
     "Pointer", JSCLASS_HAS_PRIVATE,
     JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PointerFinalize
 };
 
 JSBool
-xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, unsigned flags,
+xpc_qsDefineQuickStubs(JSContext *cx, JSObject *protoArg, unsigned flags,
                        uint32_t ifacec, const nsIID **interfaces,
                        uint32_t tableSize, const xpc_qsHashEntry *table,
                        const xpc_qsPropertySpec *propspecs,
                        const xpc_qsFunctionSpec *funcspecs,
                        const char *stringTable)
 {
     /*
      * Walk interfaces in reverse order to behave like XPConnect when a
      * feature is defined in more than one of the interfaces.
      *
      * XPCNativeSet::FindMethod returns the first matching feature it finds,
      * searching the interfaces forward.  Here, definitions toward the
      * front of 'interfaces' overwrite those toward the back.
      */
+    RootedObject proto(cx, protoArg);
     for (uint32_t i = ifacec; i-- != 0;) {
         const nsID &iid = *interfaces[i];
         const xpc_qsHashEntry *entry =
             LookupInterfaceOrAncestor(tableSize, table, iid);
 
         if (entry) {
             for (;;) {
                 // Define quick stubs for attributes.
@@ -217,17 +219,17 @@ GetMethodInfo(JSContext *cx, jsval *vp, 
     JSString *str = JS_GetFunctionId(JS_GetObjectFunction(funobj));
     jsid methodId = str ? INTERNED_STRING_TO_JSID(cx, str) : JSID_VOID;
     GetMemberInfo(JSVAL_TO_OBJECT(vp[1]), methodId, ifaceNamep);
     *memberIdp = methodId;
 }
 
 static bool
 ThrowCallFailed(JSContext *cx, nsresult rv,
-                const char *ifaceName, jsid memberId, const char *memberName)
+                const char *ifaceName, HandleId memberId, const char *memberName)
 {
     /* Only one of memberId or memberName should be given. */
     MOZ_ASSERT(JSID_IS_VOID(memberId) != !memberName);
 
     // From XPCThrower::ThrowBadResult.
     char* sz;
     const char* format;
     const char* name;
@@ -268,27 +270,29 @@ ThrowCallFailed(JSContext *cx, nsresult 
     if (sz)
         JS_smprintf_free(sz);
 
     return false;
 }
 
 JSBool
 xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *obj,
-                              jsid memberId)
+                              jsid memberIdArg)
 {
+    RootedId memberId(cx, memberIdArg);
     const char *ifaceName;
     GetMemberInfo(obj, memberId, &ifaceName);
     return ThrowCallFailed(cx, rv, ifaceName, memberId, NULL);
 }
 
 JSBool
-xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *obj,
+xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *objArg,
                               const char* memberName)
 {
+    RootedObject obj(cx, objArg);
     JSString *str = JS_InternString(cx, memberName);
     if (!str) {
         return false;
     }
     return xpc_qsThrowGetterSetterFailed(cx, rv, obj,
                                          INTERNED_STRING_TO_JSID(cx, str));
 }
 
@@ -299,34 +303,34 @@ xpc_qsThrowGetterSetterFailed(JSContext 
     return xpc_qsThrowGetterSetterFailed(cx, rv, obj,
                                          xpc_qsStringTable + memberIndex);
 }
 
 JSBool
 xpc_qsThrowMethodFailed(JSContext *cx, nsresult rv, jsval *vp)
 {
     const char *ifaceName;
-    jsid memberId;
-    GetMethodInfo(cx, vp, &ifaceName, &memberId);
+    RootedId memberId(cx);
+    GetMethodInfo(cx, vp, &ifaceName, memberId.address());
     return ThrowCallFailed(cx, rv, ifaceName, memberId, NULL);
 }
 
 JSBool
 xpc_qsThrowMethodFailedWithCcx(XPCCallContext &ccx, nsresult rv)
 {
     ThrowBadResult(rv, ccx);
     return false;
 }
 
 bool
 xpc_qsThrowMethodFailedWithDetails(JSContext *cx, nsresult rv,
                                    const char *ifaceName,
                                    const char *memberName)
 {
-    return ThrowCallFailed(cx, rv, ifaceName, JSID_VOID, memberName);
+    return ThrowCallFailed(cx, rv, ifaceName, JSID_VOIDHANDLE, memberName);
 }
 
 static void
 ThrowBadArg(JSContext *cx, nsresult rv, const char *ifaceName,
             jsid memberId, const char *memberName, unsigned paramnum)
 {
     /* Only one memberId or memberName should be given. */
     MOZ_ASSERT(JSID_IS_VOID(memberId) != !memberName);
@@ -381,18 +385,19 @@ xpc_qsThrowBadSetterValue(JSContext *cx,
 {
     const char *ifaceName;
     GetMemberInfo(obj, propId, &ifaceName);
     ThrowBadArg(cx, rv, ifaceName, propId, NULL, 0);
 }
 
 void
 xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv,
-                          JSObject *obj, const char* propName)
+                          JSObject *objArg, const char* propName)
 {
+    RootedObject obj(cx, objArg);
     JSString *str = JS_InternString(cx, propName);
     if (!str) {
         return;
     }
     xpc_qsThrowBadSetterValue(cx, rv, obj, INTERNED_STRING_TO_JSID(cx, str));
 }
 
 void
@@ -489,17 +494,17 @@ xpc_qsAUTF8String::xpc_qsAUTF8String(JSC
 
     new(mBuf) implementation_type(chars, len);
     mValid = true;
 }
 
 static nsresult
 getNative(nsISupports *idobj,
           QITableEntry* entries,
-          JSObject *obj,
+          HandleObject obj,
           const nsIID &iid,
           void **ppThis,
           nsISupports **pThisRef,
           jsval *vp)
 {
     // Try using the QITableEntry to avoid the extra AddRef and Release.
     if (entries) {
         for (QITableEntry* e = entries; e->iid; e++) {
@@ -522,18 +527,19 @@ getNative(nsISupports *idobj,
 inline nsresult
 getNativeFromWrapper(JSContext *cx,
                      XPCWrappedNative *wrapper,
                      const nsIID &iid,
                      void **ppThis,
                      nsISupports **pThisRef,
                      jsval *vp)
 {
+    RootedObject obj(cx, wrapper->GetFlatJSObject());
     return getNative(wrapper->GetIdentityObject(), wrapper->GetOffsets(),
-                     wrapper->GetFlatJSObject(), iid, ppThis, pThisRef, vp);
+                     obj, iid, ppThis, pThisRef, vp);
 }
 
 
 nsresult
 getWrapper(JSContext *cx,
            JSObject *obj,
            XPCWrappedNative **wrapper,
            JSObject **cur,
@@ -590,24 +596,25 @@ getWrapper(JSContext *cx,
     }
 
     return NS_OK;
 }
 
 nsresult
 castNative(JSContext *cx,
            XPCWrappedNative *wrapper,
-           JSObject *cur,
+           JSObject *curArg,
            XPCWrappedNativeTearOff *tearoff,
            const nsIID &iid,
            void **ppThis,
            nsISupports **pThisRef,
            jsval *vp,
            XPCLazyCallContext *lccx)
 {
+    RootedObject cur(cx, curArg);
     if (wrapper) {
         nsresult rv = getNativeFromWrapper(cx,wrapper, iid, ppThis, pThisRef,
                                            vp);
 
         if (lccx && NS_SUCCEEDED(rv))
             lccx->SetWrapper(wrapper, tearoff);
 
         if (rv != NS_ERROR_NO_INTERFACE)
@@ -648,34 +655,34 @@ xpc_qsUnwrapThisFromCcxImpl(XPCCallConte
                             void **ppThis,
                             nsISupports **pThisRef,
                             jsval *vp)
 {
     nsISupports *native = ccx.GetIdentityObject();
     if (!native)
         return xpc_qsThrow(ccx.GetJSContext(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN);
 
+    RootedObject obj(ccx, ccx.GetFlattenedJSObject());
     nsresult rv = getNative(native, GetOffsets(native, ccx.GetProto()),
-                            ccx.GetFlattenedJSObject(), iid, ppThis, pThisRef,
-                            vp);
+                            obj, iid, ppThis, pThisRef, vp);
     if (NS_FAILED(rv))
         return xpc_qsThrow(ccx.GetJSContext(), rv);
     return true;
 }
 
 nsresult
 xpc_qsUnwrapArgImpl(JSContext *cx,
                     jsval v,
                     const nsIID &iid,
                     void **ppArg,
                     nsISupports **ppArgRef,
                     jsval *vp)
 {
     nsresult rv;
-    JSObject *src = xpc_qsUnwrapObj(v, ppArgRef, &rv);
+    RootedObject src(cx, xpc_qsUnwrapObj(v, ppArgRef, &rv));
     if (!src) {
         *ppArg = nullptr;
 
         return rv;
     }
 
     XPCWrappedNative *wrapper;
     XPCWrappedNativeTearOff *tearoff;
--- a/js/xpconnect/src/XPCVariant.cpp
+++ b/js/xpconnect/src/XPCVariant.cpp
@@ -6,16 +6,18 @@
 
 /* nsIVariant implementation for xpconnect. */
 
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 
 #include "jsfriendapi.h"
 
+using namespace JS;
+
 NS_IMPL_CLASSINFO(XPCVariant, NULL, 0, XPCVARIANT_CID)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XPCVariant)
   NS_INTERFACE_MAP_ENTRY(XPCVariant)
   NS_INTERFACE_MAP_ENTRY(nsIVariant)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_IMPL_QUERY_CLASSINFO(XPCVariant)
 NS_INTERFACE_MAP_END
 NS_IMPL_CI_INTERFACE_GETTER2(XPCVariant, XPCVariant, nsIVariant)
@@ -144,17 +146,17 @@ private:
         tVar       ,  // nsVariant - last ditch if no other common type found.
         tErr          // No valid state or type has this value.
     };
 
     // Table has tUnk as a state (column) but not as a type (row).
     static const Type StateTable[tTypeCount][tTypeCount-1];
 
 public:
-    static JSBool GetTypeForArray(JSContext* cx, JSObject* array,
+    static JSBool GetTypeForArray(JSContext* cx, HandleObject array,
                                   uint32_t length,
                                   nsXPTType* resultType, nsID* resultID);
 };
 
 
 // Current state is the column down the side.
 // Current type is the row along the top.
 // New state is in the box at the intersection.
@@ -169,44 +171,45 @@ XPCArrayHomogenizer::StateTable[tTypeCou
 /* tStr  */{tStr ,tVar ,tVar ,tVar ,tStr ,tVar ,tVar ,tVar  },
 /* tID   */{tID  ,tVar ,tVar ,tVar ,tVar ,tID  ,tVar ,tVar  },
 /* tArr  */{tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr  },
 /* tISup */{tISup,tVar ,tVar ,tVar ,tVar ,tVar ,tVar ,tISup },
 /* tUnk  */{tNull,tInt ,tDbl ,tBool,tStr ,tID  ,tVar ,tISup }};
 
 // static
 JSBool
-XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, JSObject* array,
+XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array,
                                      uint32_t length,
                                      nsXPTType* resultType, nsID* resultID)
 {
     Type state = tUnk;
     Type type;
 
+    RootedValue val(cx);
+    RootedObject jsobj(cx);
     for (uint32_t i = 0; i < length; i++) {
-        JS::Value val;
-        if (!JS_GetElement(cx, array, i, &val))
+        if (!JS_GetElement(cx, array, i, val.address()))
             return false;
 
         if (val.isInt32()) {
             type = tInt;
         } else if (val.isDouble()) {
             type = tDbl;
         } else if (val.isBoolean()) {
             type = tBool;
-        } else if (val.isUndefined()) { 
+        } else if (val.isUndefined()) {
             state = tVar;
             break;
         } else if (val.isNull()) {
             type = tNull;
         } else if (val.isString()) {
             type = tStr;
         } else {
             NS_ASSERTION(val.isObject(), "invalid type of jsval!");
-            JSObject* jsobj = &val.toObject();
+            jsobj = &val.toObject();
             if (JS_IsArrayObject(cx, jsobj))
                 type = tArr;
             else if (xpc_JSObjectIsID(cx, jsobj))
                 type = tID;
             else
                 type = tISup;
         }
 
@@ -262,17 +265,17 @@ XPCArrayHomogenizer::GetTypeForArray(JSC
     }
     return true;
 }
 
 JSBool XPCVariant::InitializeData(JSContext* cx)
 {
     JS_CHECK_RECURSION(cx, return false);
 
-    JS::Value val = GetJSVal();
+    RootedValue val(cx, GetJSVal());
 
     if (val.isInt32())
         return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, val.toInt32()));
     if (val.isDouble())
         return NS_SUCCEEDED(nsVariant::SetFromDouble(&mData, val.toDouble()));
     if (val.isBoolean())
         return NS_SUCCEEDED(nsVariant::SetFromBool(&mData, val.toBoolean()));
     if (val.isUndefined())
@@ -304,17 +307,17 @@ JSBool XPCVariant::InitializeData(JSCont
         mData.mType = nsIDataType::VTYPE_WSTRING_SIZE_IS;
 
         return true;
     }
 
     // leaving only JSObject...
     NS_ASSERTION(val.isObject(), "invalid type of jsval!");
 
-    JSObject* jsobj = &val.toObject();
+    RootedObject jsobj(cx, &val.toObject());
 
     // Let's see if it is a xpcJSID.
 
     const nsID* id = xpc_JSObjectToID(cx, jsobj);
     if (id)
         return NS_SUCCEEDED(nsVariant::SetFromID(&mData, *id));
 
     // Let's see if it is a js array object.
@@ -373,39 +376,38 @@ XPCVariant::VariantDataToJS(XPCLazyCallC
                             nsIVariant* variant,
                             nsresult* pErr, jsval* pJSVal)
 {
     // Get the type early because we might need to spoof it below.
     uint16_t type;
     if (NS_FAILED(variant->GetDataType(&type)))
         return false;
 
-    jsval realVal;
-    nsresult rv = variant->GetAsJSVal(&realVal);
+    JSContext *cx = lccx.GetJSContext();
+    RootedValue realVal(cx);
+    nsresult rv = variant->GetAsJSVal(realVal.address());
 
     if (NS_SUCCEEDED(rv) &&
         (JSVAL_IS_PRIMITIVE(realVal) ||
          type == nsIDataType::VTYPE_ARRAY ||
          type == nsIDataType::VTYPE_EMPTY_ARRAY ||
          type == nsIDataType::VTYPE_ID)) {
-        JSContext *cx = lccx.GetJSContext();
-        if (!JS_WrapValue(cx, &realVal))
+        if (!JS_WrapValue(cx, realVal.address()))
             return false;
         *pJSVal = realVal;
         return true;
     }
 
     nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
     if (xpcvariant && xpcvariant->mReturnRawObject) {
         NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE ||
                      type == nsIDataType::VTYPE_INTERFACE_IS,
                      "Weird variant");
 
-        JSContext *cx = lccx.GetJSContext();
-        if (!JS_WrapValue(cx, &realVal))
+        if (!JS_WrapValue(cx, realVal.address()))
             return false;
         *pJSVal = realVal;
         return true;
     }
 
     // else, it's an object and we really need to double wrap it if we've
     // already decided that its 'natural' type is as some sort of interface.
 
@@ -420,17 +422,16 @@ XPCVariant::VariantDataToJS(XPCLazyCallC
     nsID iid;
     nsAutoString astring;
     nsAutoCString cString;
     nsUTF8String utf8String;
     uint32_t size;
     xpctvar.flags = 0;
     JSBool success;
 
-    JSContext* cx = lccx.GetJSContext();
     NS_ABORT_IF_FALSE(js::IsObjectInContextCompartment(lccx.GetScopeForNewJSObjects(), cx),
                       "bad scope for new JSObjects");
 
     switch (type) {
         case nsIDataType::VTYPE_INT8:
         case nsIDataType::VTYPE_INT16:
         case nsIDataType::VTYPE_INT32:
         case nsIDataType::VTYPE_INT64:
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -401,18 +401,18 @@ nsXPCWrappedJSClass::BuildPropertyEnumer
         nsresult rv;
         if (!GetNamedPropertyAsVariantRaw(ccx, aJSObj, idName,
                                           getter_AddRefs(value), &rv)) {
             if (NS_FAILED(rv))
                 return rv;
             return NS_ERROR_FAILURE;
         }
 
-        jsval jsvalName;
-        if (!JS_IdToValue(cx, idName, &jsvalName))
+        RootedValue jsvalName(cx);
+        if (!JS_IdToValue(cx, idName, jsvalName.address()))
             return NS_ERROR_FAILURE;
 
         JSString* name = JS_ValueToString(cx, jsvalName);
         if (!name)
             return NS_ERROR_FAILURE;
 
         size_t length;
         const jschar *chars = JS_GetStringCharsAndLength(cx, name, &length);
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -3611,17 +3611,17 @@ MorphSlimWrapper(JSContext *cx, HandleOb
 
 #ifdef DEBUG_slimwrappers
 static uint32_t sSlimWrappers;
 #endif
 
 JSBool
 ConstructSlimWrapper(XPCCallContext &ccx,
                      xpcObjectHelper &aHelper,
-                     XPCWrappedNativeScope* xpcScope, jsval *rval)
+                     XPCWrappedNativeScope* xpcScope, MutableHandleValue rval)
 {
     nsISupports *identityObj = aHelper.GetCanonical();
     nsXPCClassInfo *classInfoHelper = aHelper.GetXPCClassInfo();
 
     if (!classInfoHelper) {
         SLIM_LOG_NOT_CREATED(ccx, identityObj, "No classinfo helper");
         return false;
     }
@@ -3667,17 +3667,17 @@ ConstructSlimWrapper(XPCCallContext &ccx
         }
     }
 
     // The PreCreate hook could have forced the creation of a wrapper, need
     // to check for that here and return early.
     nsWrapperCache *cache = aHelper.GetWrapperCache();
     JSObject* wrapper = cache->GetWrapper();
     if (wrapper) {
-        *rval = OBJECT_TO_JSVAL(wrapper);
+        rval.setObject(*wrapper);
 
         return true;
     }
 
     uint32_t interfacesBitmap = classInfoHelper->GetInterfacesBitmap();
     XPCNativeScriptableCreateInfo
         sciProto(aHelper.forgetXPCClassInfo(), flags, interfacesBitmap);
 
@@ -3704,12 +3704,12 @@ ConstructSlimWrapper(XPCCallContext &ccx
     // Transfer ownership to the wrapper's private.
     aHelper.forgetCanonical();
 
     cache->SetWrapper(wrapper);
 
     SLIM_LOG(("+++++ %i created slim wrapper (%p, %p, %p)\n", ++sSlimWrappers,
               wrapper, p, xpcScope));
 
-    *rval = OBJECT_TO_JSVAL(wrapper);
+    rval.setObject(*wrapper);
 
     return true;
 }
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -2416,23 +2416,23 @@ nsXPConnect::NotifyDidPaint()
     return NS_OK;
 }
 
 const uint8_t HAS_PRINCIPALS_FLAG               = 1;
 const uint8_t HAS_ORIGIN_PRINCIPALS_FLAG        = 2;
 
 static nsresult
 WriteScriptOrFunction(nsIObjectOutputStream *stream, JSContext *cx,
-                      JSScript *script, HandleObject functionObj)
+                      JSScript *scriptArg, HandleObject functionObj)
 {
     // Exactly one of script or functionObj must be given
-    MOZ_ASSERT(!script != !functionObj);
-
-    if (!script)
-        script = JS_GetFunctionScript(cx, JS_GetObjectFunction(functionObj));
+    MOZ_ASSERT(!scriptArg != !functionObj);
+
+    RootedScript script(cx, scriptArg ? scriptArg :
+                                        JS_GetFunctionScript(cx, JS_GetObjectFunction(functionObj)));
 
     nsIPrincipal *principal =
         nsJSPrincipals::get(JS_GetScriptPrincipals(script));
     nsIPrincipal *originPrincipal =
         nsJSPrincipals::get(JS_GetScriptOriginPrincipals(script));
 
     uint8_t flags = 0;
     if (principal)
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2511,17 +2511,17 @@ private:
     XPCNativeScriptableInfo* mScriptableInfo;
     QITableEntry*            mOffsets;
 };
 
 class xpcObjectHelper;
 extern JSBool ConstructSlimWrapper(XPCCallContext &ccx,
                                    xpcObjectHelper &aHelper,
                                    XPCWrappedNativeScope* xpcScope,
-                                   jsval *rval);
+                                   JS::MutableHandleValue rval);
 extern JSBool MorphSlimWrapper(JSContext *cx, JS::HandleObject obj);
 
 /***********************************************/
 // XPCWrappedNativeTearOff represents the info needed to make calls to one
 // interface on the underlying native object of a XPCWrappedNative.
 
 class XPCWrappedNativeTearOff
 {
@@ -3296,17 +3296,17 @@ public:
         XPCLazyCallContext lccx(ccx);
         return NativeData2JS(lccx, d, s, type, iid, pErr);
     }
 
     static JSBool NativeData2JS(XPCLazyCallContext& lccx, jsval* d,
                                 const void* s, const nsXPTType& type,
                                 const nsID* iid, nsresult* pErr);
 
-    static JSBool JSData2Native(JSContext* cx, void* d, jsval s,
+    static JSBool JSData2Native(JSContext* cx, void* d, JS::HandleValue s,
                                 const nsXPTType& type,
                                 JSBool useAllocator, const nsID* iid,
                                 nsresult* pErr);
 
     /**
      * Convert a native nsISupports into a JSObject.
      *
      * @param ccx the context for the whole procedure
@@ -3344,17 +3344,17 @@ public:
                                            bool allowNativeWrapper,
                                            nsresult* pErr);
 
     static JSBool GetNativeInterfaceFromJSObject(XPCCallContext& ccx,
                                                  void** dest, JSObject* src,
                                                  const nsID* iid,
                                                  nsresult* pErr);
     static JSBool JSObject2NativeInterface(JSContext* cx,
-                                           void** dest, JSObject* src,
+                                           void** dest, JS::HandleObject src,
                                            const nsID* iid,
                                            nsISupports* aOuter,
                                            nsresult* pErr);
     static JSBool GetISupportsFromJSObject(JSObject* obj, nsISupports** iface);
 
     /**
      * Convert a native array into a jsval.
      *
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -161,18 +161,21 @@ IsPermitted(const char *name, JSFlatStri
 }
 
 #undef NAME
 #undef RW
 #undef R
 #undef W
 
 static bool
-IsFrameId(JSContext *cx, JSObject *obj, jsid id)
+IsFrameId(JSContext *cx, JSObject *objArg, jsid idArg)
 {
+    RootedObject obj(cx, objArg);
+    RootedId id(cx, idArg);
+
     obj = JS_ObjectToInnerObject(cx, obj);
     MOZ_ASSERT(!js::IsWrapper(obj));
     XPCWrappedNative *wn = IS_WN_WRAPPER(obj) ? XPCWrappedNative::Get(obj)
                                               : nullptr;
     if (!wn) {
         return false;
     }
 
@@ -274,24 +277,26 @@ enum Access { READ = (1<<0), WRITE = (1<
 static void
 EnterAndThrow(JSContext *cx, JSObject *wrapper, const char *msg)
 {
     JSAutoCompartment ac(cx, wrapper);
     JS_ReportError(cx, msg);
 }
 
 bool
-ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act)
+ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapperArg, jsid idArg, Wrapper::Action act)
 {
-    JSObject *wrappedObject = Wrapper::wrappedObject(wrapper);
+    RootedObject wrapper(cx, wrapperArg);
+    RootedId id(cx, idArg);
+    RootedObject wrappedObject(cx, Wrapper::wrappedObject(wrapper));
 
     if (act == Wrapper::CALL)
         return true;
 
-    jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS);
+    RootedId exposedPropsId(cx, GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS));
 
     // We need to enter the wrappee's compartment to look at __exposedProps__,
     // but we want to be in the wrapper's compartment if we call Deny().
     //
     // Unfortunately, |cx| can be in either compartment when we call ::check. :-(
     JSAutoCompartment ac(cx, wrappedObject);
 
     JSBool found = false;
@@ -309,18 +314,18 @@ ExposedPropertiesOnly::check(JSContext *
     // If no __exposedProps__ existed, deny access.
     if (!found) {
         return false;
     }
 
     if (id == JSID_VOID)
         return true;
 
-    JS::Value exposedProps;
-    if (!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, &exposedProps))
+    RootedValue exposedProps(cx);
+    if (!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, exposedProps.address()))
         return false;
 
     if (exposedProps.isNullOrUndefined())
         return false;
 
     if (!exposedProps.isObject()) {
         EnterAndThrow(cx, wrapper, "__exposedProps__ must be undefined, null, or an Object");
         return false;
@@ -393,18 +398,20 @@ ExposedPropertiesOnly::check(JSContext *
 bool
 ExposedPropertiesOnly::allowNativeCall(JSContext *cx, JS::IsAcceptableThis test,
                                        JS::NativeImpl impl)
 {
     return js::IsReadOnlyDateMethod(test, impl) || js::IsTypedArrayThisCheck(test);
 }
 
 bool
-ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act)
+ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapperArg, jsid idArg, Wrapper::Action act)
 {
+    RootedObject wrapper(cx, wrapperArg);
+    RootedId id(cx, idArg);
     JSAutoCompartment ac(cx, wrapper);
 
     if (JSID_IS_STRING(id) && act == Wrapper::GET) {
         JSFlatString *flatId = JSID_TO_FLAT_STRING(id);
         if (JS_FlatStringEqualsAscii(flatId, "isSuccessCode") ||
             JS_FlatStringEqualsAscii(flatId, "lookupMethod") ||
             JS_FlatStringEqualsAscii(flatId, "interfaces") ||
             JS_FlatStringEqualsAscii(flatId, "interfacesByID") ||
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
@@ -1,10 +1,12 @@
 #include "ChromeObjectWrapper.h"
 
+using namespace JS;
+
 namespace xpc {
 
 // When creating wrappers for chrome objects in content, we detect if the
 // prototype of the wrapped chrome object is a prototype for a standard class
 // (like Array.prototype). If it is, we use the corresponding standard prototype
 // from the wrapper's scope, rather than the wrapped standard prototype
 // from the wrappee's scope.
 //
@@ -12,60 +14,60 @@ namespace xpc {
 // chromeArray.forEach(..) to Just Work without explicitly listing them in
 // __exposedProps__. Since proxies don't automatically inherit behavior from
 // their prototype, we have to instrument the traps to do this manually.
 ChromeObjectWrapper ChromeObjectWrapper::singleton;
 
 using js::assertEnteredPolicy;
 
 static bool
-AllowedByBase(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
+AllowedByBase(JSContext *cx, HandleObject wrapper, HandleId id,
               js::Wrapper::Action act)
 {
     MOZ_ASSERT(js::Wrapper::wrapperHandler(wrapper) ==
                &ChromeObjectWrapper::singleton);
     bool bp;
     ChromeObjectWrapper *handler = &ChromeObjectWrapper::singleton;
     return handler->ChromeObjectWrapperBase::enter(cx, wrapper, id, act, &bp);
 }
 
 static bool
 PropIsFromStandardPrototype(JSContext *cx, JSPropertyDescriptor *desc)
 {
     MOZ_ASSERT(desc->obj);
-    JSObject *unwrapped = js::UncheckedUnwrap(desc->obj);
+    RootedObject unwrapped(cx, js::UncheckedUnwrap(desc->obj));
     JSAutoCompartment ac(cx, unwrapped);
     return JS_IdentifyClassPrototype(cx, unwrapped) != JSProto_Null;
 }
 
 // Note that we're past the policy enforcement stage, here, so we can query
 // ChromeObjectWrapperBase and get an unfiltered view of the underlying object.
 // This lets us determine whether the property we would have found (given a
 // transparent wrapper) would have come off a standard prototype.
 static bool
-PropIsFromStandardPrototype(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                            JS::Handle<jsid> id)
+PropIsFromStandardPrototype(JSContext *cx, HandleObject wrapper,
+                            HandleId id)
 {
     MOZ_ASSERT(js::Wrapper::wrapperHandler(wrapper) ==
                &ChromeObjectWrapper::singleton);
-    JSPropertyDescriptor desc;
+    Rooted<JSPropertyDescriptor> desc(cx);
     ChromeObjectWrapper *handler = &ChromeObjectWrapper::singleton;
     if (!handler->ChromeObjectWrapperBase::getPropertyDescriptor(cx, wrapper, id,
-                                                                 &desc, 0) ||
-        !desc.obj)
+                                                                 desc.address(), 0) ||
+        !desc.object())
     {
         return false;
     }
-    return PropIsFromStandardPrototype(cx, &desc);
+    return PropIsFromStandardPrototype(cx, desc.address());
 }
 
 bool
 ChromeObjectWrapper::getPropertyDescriptor(JSContext *cx,
-                                           JS::Handle<JSObject*> wrapper,
-                                           JS::Handle<jsid> id,
+                                           HandleObject wrapper,
+                                           HandleId id,
                                            js::PropertyDescriptor *desc,
                                            unsigned flags)
 {
     assertEnteredPolicy(cx, wrapper, id);
     // First, try a lookup on the base wrapper if permitted.
     desc->obj = NULL;
     if (AllowedByBase(cx, wrapper, id, Wrapper::GET) &&
         !ChromeObjectWrapperBase::getPropertyDescriptor(cx, wrapper, id,
@@ -75,59 +77,59 @@ ChromeObjectWrapper::getPropertyDescript
 
     // If the property is something that can be found on a standard prototype,
     // prefer the one we'll get via the prototype chain in the content
     // compartment.
     if (desc->obj && PropIsFromStandardPrototype(cx, desc))
         desc->obj = NULL;
 
     // If we found something or have no proto, we're done.
-    JSObject *wrapperProto;
-    if (!JS_GetPrototype(cx, wrapper, &wrapperProto))
+    RootedObject wrapperProto(cx);
+    if (!JS_GetPrototype(cx, wrapper, wrapperProto.address()))
       return false;
     if (desc->obj || !wrapperProto)
         return true;
 
     // If not, try doing the lookup on the prototype.
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
     return JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, desc);
 }
 
 bool
-ChromeObjectWrapper::has(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                         JS::Handle<jsid> id, bool *bp)
+ChromeObjectWrapper::has(JSContext *cx, HandleObject wrapper,
+                         HandleId id, bool *bp)
 {
     assertEnteredPolicy(cx, wrapper, id);
     // Try the lookup on the base wrapper if permitted.
     if (AllowedByBase(cx, wrapper, id, js::Wrapper::GET) &&
         !ChromeObjectWrapperBase::has(cx, wrapper, id, bp))
     {
         return false;
     }
 
     // If we found something or have no prototype, we're done.
-    JSObject *wrapperProto;
-    if (!JS_GetPrototype(cx, wrapper, &wrapperProto))
+    RootedObject wrapperProto(cx);
+    if (!JS_GetPrototype(cx, wrapper, wrapperProto.address()))
         return false;
     if (*bp || !wrapperProto)
         return true;
 
     // Try the prototype if that failed.
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
-    JSPropertyDescriptor desc;
-    if (!JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, &desc))
+    Rooted<JSPropertyDescriptor> desc(cx);
+    if (!JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, desc.address()))
         return false;
-    *bp = !!desc.obj;
+    *bp = !!desc.object();
     return true;
 }
 
 bool
-ChromeObjectWrapper::get(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                         JS::Handle<JSObject*> receiver, JS::Handle<jsid> id,
-                         JS::MutableHandle<JS::Value> vp)
+ChromeObjectWrapper::get(JSContext *cx, HandleObject wrapper,
+                         HandleObject receiver, HandleId id,
+                         MutableHandleValue vp)
 {
     assertEnteredPolicy(cx, wrapper, id);
     vp.setUndefined();
     JSPropertyDescriptor desc;
     // Only call through to the get trap on the underlying object if we're
     // allowed to see the property, and if what we'll find is not on a standard
     // prototype.
     if (AllowedByBase(cx, wrapper, id, js::Wrapper::GET) &&
@@ -137,54 +139,52 @@ ChromeObjectWrapper::get(JSContext *cx, 
         if (!ChromeObjectWrapperBase::get(cx, wrapper, receiver, id, vp))
             return false;
         // If we found something, we're done.
         if (!vp.isUndefined())
             return true;
     }
 
     // If we have no proto, we're done.
-    JSObject *wrapperProto;
-    if (!JS_GetPrototype(cx, wrapper, &wrapperProto))
+    RootedObject wrapperProto(cx);
+    if (!JS_GetPrototype(cx, wrapper, wrapperProto.address()))
         return false;
     if (!wrapperProto)
         return true;
 
     // Try the prototype.
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
     return js::GetGeneric(cx, wrapperProto, receiver, id, vp.address());
 }
 
 // SecurityWrapper categorically returns false for objectClassIs, but the
 // contacts API depends on Array.isArray returning true for COW-implemented
 // contacts. This isn't really ideal, but make it work for now.
 bool
-ChromeObjectWrapper::objectClassIs(JS::Handle<JSObject*> obj, js::ESClassValue classValue,
+ChromeObjectWrapper::objectClassIs(HandleObject obj, js::ESClassValue classValue,
                                    JSContext *cx)
 {
   return CrossCompartmentWrapper::objectClassIs(obj, classValue, cx);
 }
 
 // This mechanism isn't ideal because we end up calling enter() on the base class
 // twice (once during enter() here and once during the trap itself), and policy
 // enforcement or COWs isn't cheap. But it results in the cleanest code, and this
 // whole proto remapping thing for COWs is going to be phased out anyway.
 bool
-ChromeObjectWrapper::enter(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                           JS::Handle<jsid> id, js::Wrapper::Action act, bool *bp)
+ChromeObjectWrapper::enter(JSContext *cx, HandleObject wrapper,
+                           HandleId id, js::Wrapper::Action act, bool *bp)
 {
     if (AllowedByBase(cx, wrapper, id, act))
         return true;
     // COWs fail silently for GETs, and that also happens to be the only case
     // where we might want to redirect the lookup to the home prototype chain.
     *bp = (act == Wrapper::GET);
     if (!*bp || id == JSID_VOID)
         return false;
 
     // Note that PropIsFromStandardPrototype needs to invoke getPropertyDescriptor
     // before we've fully entered the policy. Waive our policy.
-    JS::RootedObject rootedWrapper(cx, wrapper);
-    JS::RootedId rootedId(cx, id);
-    js::AutoWaivePolicy policy(cx, rootedWrapper, rootedId);
+    js::AutoWaivePolicy policy(cx, wrapper, id);
     return PropIsFromStandardPrototype(cx, wrapper, id);
 }
 
 }
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -64,25 +64,25 @@ JSObject *
 WrapperFactory::CreateXrayWaiver(JSContext *cx, HandleObject obj)
 {
     // The caller is required to have already done a lookup.
     // NB: This implictly performs the assertions of GetXrayWaiver.
     MOZ_ASSERT(!GetXrayWaiver(obj));
     XPCWrappedNativeScope *scope = GetObjectScope(obj);
 
     // Get a waiver for the proto.
-    JSObject *proto;
-    if (!js::GetObjectProto(cx, obj, &proto))
+    RootedObject proto(cx);
+    if (!js::GetObjectProto(cx, obj, proto.address()))
         return nullptr;
     if (proto && !(proto = WaiveXray(cx, proto)))
         return nullptr;
 
     // Create the waiver.
     JSAutoCompartment ac(cx, obj);
-    if (!JS_WrapObject(cx, &proto))
+    if (!JS_WrapObject(cx, proto.address()))
         return nullptr;
     JSObject *waiver = Wrapper::New(cx, obj, proto,
                                     JS_GetGlobalForObject(cx, obj),
                                     &XrayWaiver);
     if (!waiver)
         return nullptr;
 
     // Add the new waiver to the map. It's important that we only ever have