Bug 863289 - GC: Continue the rooting of XPConnect r=bholley
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 17 Apr 2013 16:38:44 +0100
changeset 129584 aa442c0ebfb229e8cce48d2726faba742f79b489
parent 129583 3fb99a9ab106d18da2e8050bc1d391e213337d3a
child 129585 cbf65101089e22dbffaaabd654b1e4ed7ed8837e
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbholley
bugs863289
milestone23.0a1
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