Bug 925916 - Handlify various things in XPConnect, r=bholley
authorSteve Fink <sfink@mozilla.com>
Fri, 11 Oct 2013 22:02:39 -0700
changeset 151156 cfe47cb78e84ccedf3367959ef6a823b0c3b7989
parent 151155 601fb33541123bf88486ea503c05ee248430bcba
child 151157 1aae4861f351b1cf9c5f6e9fd43711e96682671f
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbholley
bugs925916
milestone27.0a1
Bug 925916 - Handlify various things in XPConnect, r=bholley
js/xpconnect/public/nsTArrayHelpers.h
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCJSWeakReference.cpp
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCQuickStubs.h
js/xpconnect/src/XPCString.cpp
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeInfo.cpp
js/xpconnect/src/dictionary_helper_gen.py
js/xpconnect/src/event_impl_gen.py
js/xpconnect/src/nsDOMQS.h
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/qsgen.py
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/js/xpconnect/public/nsTArrayHelpers.h
+++ b/js/xpconnect/public/nsTArrayHelpers.h
@@ -26,18 +26,18 @@ nsTArrayToJSArray(JSContext* aCx, const 
   JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
   MOZ_ASSERT(global);
 
   for (uint32_t index = 0; index < aSourceArray.Length(); index++) {
     nsCOMPtr<nsISupports> obj;
     nsresult rv = aSourceArray[index]->QueryInterface(NS_GET_IID(nsISupports), getter_AddRefs(obj));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JS::Rooted<JS::Value> wrappedVal(aCx);
-    rv = nsContentUtils::WrapNative(aCx, global, obj, wrappedVal.address(),
+    JS::RootedValue wrappedVal(aCx);
+    rv = nsContentUtils::WrapNative(aCx, global, obj, &wrappedVal,
                                     nullptr, true);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!JS_SetElement(aCx, arrayObj, index, &wrappedVal)) {
       NS_WARNING("JS_SetElement failed!");
       return NS_ERROR_FAILURE;
     }
   }
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -181,16 +181,18 @@ SandboxImport(JSContext *cx, unsigned ar
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 CreateXMLHttpRequest(JSContext *cx, unsigned argc, jsval *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
     if (!ssm)
         return false;
 
     nsIPrincipal *subjectPrincipal = ssm->GetCxSubjectPrincipal(cx);
     if (!subjectPrincipal)
         return false;
 
@@ -201,17 +203,17 @@ CreateXMLHttpRequest(JSContext *cx, unsi
         static_cast<nsIScriptObjectPrincipal *>(xpc_GetJSPrivate(global));
     nsCOMPtr<nsIGlobalObject> iglobal = do_QueryInterface(sop);
 
     nsCOMPtr<nsIXMLHttpRequest> xhr = new nsXMLHttpRequest();
     nsresult rv = xhr->Init(subjectPrincipal, nullptr, iglobal, nullptr);
     if (NS_FAILED(rv))
         return false;
 
-    rv = nsContentUtils::WrapNative(cx, global, xhr, vp);
+    rv = nsContentUtils::WrapNative(cx, global, xhr, args.rval());
     if (NS_FAILED(rv))
         return false;
 
     return true;
 }
 
 /*
  * Instead of simply wrapping a function into another compartment,
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -90,102 +90,101 @@ XPCConvert::GetISupportsFromJSObject(JSO
     *iface = UnwrapDOMObjectToISupports(obj);
     return !!*iface;
 }
 
 /***************************************************************************/
 
 // static
 bool
-XPCConvert::NativeData2JS(jsval* d, const void* s,
+XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
                           const nsXPTType& type, const nsID* iid, nsresult* pErr)
 {
     NS_PRECONDITION(s, "bad param");
-    NS_PRECONDITION(d, "bad param");
 
     AutoJSContext cx;
     if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
 
     switch (type.TagPart()) {
-    case nsXPTType::T_I8    : *d = INT_TO_JSVAL(int32_t(*((int8_t*)s)));             break;
-    case nsXPTType::T_I16   : *d = INT_TO_JSVAL(int32_t(*((int16_t*)s)));            break;
-    case nsXPTType::T_I32   : *d = INT_TO_JSVAL(*((int32_t*)s));                     break;
-    case nsXPTType::T_I64   : *d = DOUBLE_TO_JSVAL(double(*((int64_t*)s)));          break;
-    case nsXPTType::T_U8    : *d = INT_TO_JSVAL(int32_t(*((uint8_t*)s)));            break;
-    case nsXPTType::T_U16   : *d = INT_TO_JSVAL(int32_t(*((uint16_t*)s)));           break;
-    case nsXPTType::T_U32   : *d = UINT_TO_JSVAL(*((uint32_t*)s));                   break;
-    case nsXPTType::T_U64   : *d = DOUBLE_TO_JSVAL(double(*((uint64_t*)s)));         break;
-    case nsXPTType::T_FLOAT : *d = DOUBLE_TO_JSVAL(*((float*)s));                    break;
-    case nsXPTType::T_DOUBLE: *d = DOUBLE_TO_JSVAL(*((double*)s));                   break;
+    case nsXPTType::T_I8    : d.setInt32(*((int8_t*)s));             break;
+    case nsXPTType::T_I16   : d.setInt32(*((int16_t*)s));            break;
+    case nsXPTType::T_I32   : d.setInt32(*((int32_t*)s));            break;
+    case nsXPTType::T_I64   : d.setNumber(double(*((int64_t*)s)));   break;
+    case nsXPTType::T_U8    : d.setInt32(*((uint8_t*)s));            break;
+    case nsXPTType::T_U16   : d.setInt32(*((uint16_t*)s));           break;
+    case nsXPTType::T_U32   : d.setNumber(*((uint32_t*)s));          break;
+    case nsXPTType::T_U64   : d.setNumber(double(*((uint64_t*)s)));  break;
+    case nsXPTType::T_FLOAT : d.setNumber(*((float*)s));             break;
+    case nsXPTType::T_DOUBLE: d.setNumber(*((double*)s));            break;
     case nsXPTType::T_BOOL  :
         {
             bool b = *((bool*)s);
 
             NS_WARN_IF_FALSE(b == 1 || b == 0,
                              "Passing a malformed bool through XPConnect");
-            *d = BOOLEAN_TO_JSVAL(!!b);
+            d.setBoolean(b);
             break;
         }
     case nsXPTType::T_CHAR  :
         {
             char* p = (char*)s;
             if (!p)
                 return false;
 
 #ifdef STRICT_CHECK_OF_UNICODE
             MOZ_ASSERT(! ILLEGAL_CHAR_RANGE(p) , "passing non ASCII data");
 #endif // STRICT_CHECK_OF_UNICODE
 
             JSString* str;
             if (!(str = JS_NewStringCopyN(cx, p, 1)))
                 return false;
-            *d = STRING_TO_JSVAL(str);
+            d.setString(str);
             break;
         }
     case nsXPTType::T_WCHAR :
         {
             jschar* p = (jschar*)s;
             if (!p)
                 return false;
             JSString* str;
             if (!(str = JS_NewUCStringCopyN(cx, p, 1)))
                 return false;
-            *d = STRING_TO_JSVAL(str);
+            d.setString(str);
             break;
         }
 
     case nsXPTType::T_JSVAL :
         {
-            *d = *((jsval*)s);
-            if (!JS_WrapValue(cx, d))
+            d.set(*((Value*)s));
+            if (!JS_WrapValue(cx, d.address()))
                 return false;
             break;
         }
 
     default:
 
         // set the default result
-        *d = JSVAL_NULL;
+        d.setNull();
 
         switch (type.TagPart()) {
         case nsXPTType::T_VOID:
             XPC_LOG_ERROR(("XPCConvert::NativeData2JS : void* params not supported"));
             return false;
 
         case nsXPTType::T_IID:
             {
                 nsID* iid2 = *((nsID**)s);
                 if (!iid2)
                     break;
                 RootedObject scope(cx, JS::CurrentGlobalOrNull(cx));
                 JSObject* obj;
                 if (!(obj = xpc_NewIDObject(cx, scope, *iid2)))
                     return false;
-                *d = OBJECT_TO_JSVAL(obj);
+                d.setObject(*obj);
                 break;
             }
 
         case nsXPTType::T_ASTRING:
             // Fall through to T_DOMSTRING case
 
         case nsXPTType::T_DOMSTRING:
             {
@@ -196,17 +195,17 @@ XPCConvert::NativeData2JS(jsval* d, cons
                 if (!p->IsVoid()) {
                     nsStringBuffer* buf;
                     jsval str = XPCStringConvert::ReadableToJSVal(cx, *p, &buf);
                     if (JSVAL_IS_NULL(str))
                         return false;
                     if (buf)
                         buf->AddRef();
 
-                    *d = str;
+                    d.set(str);
                 }
 
                 // *d is defaulted to JSVAL_NULL so no need to set it
                 // again if p is a "void" string
 
                 break;
             }
 
@@ -223,40 +222,40 @@ XPCConvert::NativeData2JS(jsval* d, cons
                   if (ILLEGAL_CHAR_RANGE(*t))
                       isAscii = false;
                 }
                 MOZ_ASSERT(isAscii, "passing non ASCII data");
 #endif // STRICT_CHECK_OF_UNICODE
                 JSString* str;
                 if (!(str = JS_NewStringCopyZ(cx, p)))
                     return false;
-                *d = STRING_TO_JSVAL(str);
+                d.setString(str);
                 break;
             }
 
         case nsXPTType::T_WCHAR_STR:
             {
                 jschar* p = *((jschar**)s);
                 if (!p)
                     break;
                 JSString* str;
                 if (!(str = JS_NewUCStringCopyZ(cx, p)))
                     return false;
-                *d = STRING_TO_JSVAL(str);
+                d.setString(str);
                 break;
             }
         case nsXPTType::T_UTF8STRING:
             {
                 const nsACString* utf8String = *((const nsACString**)s);
 
                 if (!utf8String || utf8String->IsVoid())
                     break;
 
                 if (utf8String->IsEmpty()) {
-                    *d = JS_GetEmptyStringValue(cx);
+                    d.set(JS_GetEmptyStringValue(cx));
                     break;
                 }
 
                 const uint32_t len = CalcUTF8ToUnicodeLength(*utf8String);
                 // The cString is not empty at this point, but the calculated
                 // UTF-16 length is zero, meaning no valid conversion exists.
                 if (!len)
                     return false;
@@ -280,40 +279,40 @@ XPCConvert::NativeData2JS(jsval* d, cons
                 // successful call will make it the responsiblity of the JS VM
                 // to free the buffer.
                 JSString* str = JS_NewUCString(cx, (jschar*)buffer, len);
                 if (!str) {
                     JS_free(cx, buffer);
                     return false;
                 }
 
-                *d = STRING_TO_JSVAL(str);
+                d.setString(str);
                 break;
             }
         case nsXPTType::T_CSTRING:
             {
                 const nsACString* cString = *((const nsACString**)s);
 
                 if (!cString || cString->IsVoid())
                     break;
 
                 if (cString->IsEmpty()) {
-                    *d = JS_GetEmptyStringValue(cx);
+                    d.set(JS_GetEmptyStringValue(cx));
                     break;
                 }
 
                 // c-strings (binary blobs) are deliberately not converted from
                 // UTF-8 to UTF-16. T_UTF8Sting is for UTF-8 encoded strings
                 // with automatic conversion.
                 JSString* str = JS_NewStringCopyN(cx, cString->Data(),
                                                   cString->Length());
                 if (!str)
                     return false;
 
-                *d = STRING_TO_JSVAL(str);
+                d.setString(str);
                 break;
             }
 
         case nsXPTType::T_INTERFACE:
         case nsXPTType::T_INTERFACE_IS:
             {
                 nsISupports* iface = *((nsISupports**)s);
                 if (iface) {
@@ -327,17 +326,17 @@ XPCConvert::NativeData2JS(jsval* d, cons
                     }
                     // else...
                     xpcObjectHelper helper(iface);
                     if (!NativeInterface2JSObject(d, nullptr, helper, iid,
                                                   nullptr, true, pErr))
                         return false;
 
 #ifdef DEBUG
-                    JSObject* jsobj = JSVAL_TO_OBJECT(*d);
+                    JSObject* jsobj = d.toObjectOrNull();
                     if (jsobj && !js::GetObjectParent(jsobj))
                         MOZ_ASSERT(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
                                    "Why did we recreate this wrapper?");
 #endif
                 }
                 break;
             }
 
@@ -766,48 +765,48 @@ XPCConvert::JSData2Native(void* d, Handl
     default:
         NS_ERROR("bad type");
         return false;
     }
     return true;
 }
 
 static inline bool
-CreateHolderIfNeeded(HandleObject obj, jsval* d,
+CreateHolderIfNeeded(HandleObject obj, MutableHandleValue d,
                      nsIXPConnectJSObjectHolder** dest)
 {
     if (dest) {
         XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(obj);
         if (!objHolder)
             return false;
 
         NS_ADDREF(*dest = objHolder);
     }
 
-    *d = OBJECT_TO_JSVAL(obj);
+    d.setObjectOrNull(obj);
 
     return true;
 }
 
 /***************************************************************************/
 // static
 bool
-XPCConvert::NativeInterface2JSObject(jsval* d,
+XPCConvert::NativeInterface2JSObject(MutableHandleValue d,
                                      nsIXPConnectJSObjectHolder** dest,
                                      xpcObjectHelper& aHelper,
                                      const nsID* iid,
                                      XPCNativeInterface** Interface,
                                      bool allowNativeWrapper,
                                      nsresult* pErr)
 {
     MOZ_ASSERT_IF(Interface, iid);
     if (!iid)
         iid = &NS_GET_IID(nsISupports);
 
-    *d = JSVAL_NULL;
+    d.setNull();
     if (dest)
         *dest = nullptr;
     if (!aHelper.Object())
         return true;
     if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
 
     // We used to have code here that unwrapped and simply exposed the
@@ -830,17 +829,17 @@ XPCConvert::NativeInterface2JSObject(jsv
     // object will create (and fill the cache) from its WrapObject call.
     nsWrapperCache *cache = aHelper.GetWrapperCache();
 
     RootedObject flat(cx);
     if (cache) {
         flat = cache->GetWrapper();
         if (cache->IsDOMBinding()) {
             if (!flat) {
-                JS::Rooted<JSObject*> global(cx, xpcscope->GetGlobalJSObject());
+                RootedObject global(cx, xpcscope->GetGlobalJSObject());
                 flat = cache->WrapObject(cx, global);
                 if (!flat)
                     return false;
             }
 
             if (allowNativeWrapper && !JS_WrapObject(cx, &flat))
                 return false;
 
@@ -853,17 +852,17 @@ XPCConvert::NativeInterface2JSObject(jsv
     // Don't double wrap CPOWs. This is a temporary measure for compatibility
     // with objects that don't provide necessary QIs (such as objects under
     // the new DOM bindings). We expect the other side of the CPOW to have
     // the appropriate wrappers in place.
     RootedObject cpow(cx, UnwrapNativeCPOW(aHelper.Object()));
     if (cpow) {
         if (!JS_WrapObject(cx, &cpow))
             return false;
-        *d = JS::ObjectValue(*cpow);
+        d.setObject(*cpow);
         return true;
     }
 
     // We can't simply construct a slim wrapper. Go ahead and create an
     // XPCWrappedNative for this object. At this point, |flat| could be
     // non-null, meaning that either we already have a wrapped native from
     // the cache (which might need to be QI'd to the new interface) or that
     // we found a slim wrapper that we'll have to morph.
@@ -915,31 +914,31 @@ XPCConvert::NativeInterface2JSObject(jsv
     if (NS_FAILED(rv) || !wrapper)
         return false;
 
     // If we're not creating security wrappers, we can return the
     // XPCWrappedNative as-is here.
     flat = wrapper->GetFlatJSObject();
     jsval v = OBJECT_TO_JSVAL(flat);
     if (!allowNativeWrapper) {
-        *d = v;
+        d.set(v);
         if (dest)
             *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.
     RootedObject original(cx, flat);
     if (!JS_WrapObject(cx, &flat))
         return false;
 
-    *d = OBJECT_TO_JSVAL(flat);
+    d.setObjectOrNull(flat);
 
     if (dest) {
         // The strongWrapper still holds the original flat object.
         if (flat == original) {
             *dest = strongWrapper.forget().get();
         } else {
             nsRefPtr<XPCJSObjectHolder> objHolder =
                 XPCJSObjectHolder::newHolder(flat);
@@ -1338,22 +1337,21 @@ XPCConvert::JSErrorToXPCException(const 
 // array fun...
 
 #ifdef POPULATE
 #undef POPULATE
 #endif
 
 // static
 bool
-XPCConvert::NativeArray2JS(jsval* d, const void** s,
+XPCConvert::NativeArray2JS(MutableHandleValue d, const void** s,
                            const nsXPTType& type, const nsID* iid,
                            uint32_t count, nsresult* pErr)
 {
     NS_PRECONDITION(s, "bad param");
-    NS_PRECONDITION(d, "bad param");
 
     AutoJSContext cx;
 
     // XXX add support for putting chars in a string rather than an array
 
     // XXX add support to indicate *which* array element was not convertable
 
     RootedObject array(cx, JS_NewArrayObject(cx, count, nullptr));
@@ -1364,17 +1362,17 @@ XPCConvert::NativeArray2JS(jsval* d, con
         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
 
     uint32_t i;
     RootedValue current(cx, JSVAL_NULL);
 
 #define POPULATE(_t)                                                                    \
     PR_BEGIN_MACRO                                                                      \
         for (i = 0; i < count; i++) {                                                   \
-            if (!NativeData2JS(current.address(), ((_t*)*s)+i, type, iid, pErr) ||      \
+            if (!NativeData2JS(&current, ((_t*)*s)+i, type, iid, pErr) ||               \
                 !JS_SetElement(cx, array, i, &current))                                 \
                 goto failure;                                                           \
         }                                                                               \
     PR_END_MACRO
 
     // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
 
     switch (type.TagPart()) {
@@ -1401,17 +1399,17 @@ XPCConvert::NativeArray2JS(jsval* d, con
     case nsXPTType::T_UTF8STRING    : NS_ERROR("bad type"); goto failure;
     case nsXPTType::T_CSTRING       : NS_ERROR("bad type"); goto failure;
     case nsXPTType::T_ASTRING       : NS_ERROR("bad type"); goto failure;
     default                         : NS_ERROR("bad type"); goto failure;
     }
 
     if (pErr)
         *pErr = NS_OK;
-    *d = OBJECT_TO_JSVAL(array);
+    d.setObject(*array);
     return true;
 
 failure:
     return false;
 
 #undef POPULATE
 }
 
@@ -1708,49 +1706,48 @@ failure:
 
     return false;
 
 #undef POPULATE
 }
 
 // static
 bool
-XPCConvert::NativeStringWithSize2JS(jsval* d, const void* s,
+XPCConvert::NativeStringWithSize2JS(MutableHandleValue d, const void* s,
                                     const nsXPTType& type,
                                     uint32_t count,
                                     nsresult* pErr)
 {
     NS_PRECONDITION(s, "bad param");
-    NS_PRECONDITION(d, "bad param");
 
     AutoJSContext cx;
     if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
 
     switch (type.TagPart()) {
         case nsXPTType::T_PSTRING_SIZE_IS:
         {
             char* p = *((char**)s);
             if (!p)
                 break;
             JSString* str;
             if (!(str = JS_NewStringCopyN(cx, p, count)))
                 return false;
-            *d = STRING_TO_JSVAL(str);
+            d.setString(str);
             break;
         }
         case nsXPTType::T_PWSTRING_SIZE_IS:
         {
             jschar* p = *((jschar**)s);
             if (!p)
                 break;
             JSString* str;
             if (!(str = JS_NewUCStringCopyN(cx, p, count)))
                 return false;
-            *d = STRING_TO_JSVAL(str);
+            d.setString(str);
             break;
         }
         default:
             XPC_LOG_ERROR(("XPCConvert::NativeStringWithSize2JS : unsupported type"));
             return false;
     }
     return true;
 }
--- a/js/xpconnect/src/XPCJSWeakReference.cpp
+++ b/js/xpconnect/src/XPCJSWeakReference.cpp
@@ -3,16 +3,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "xpcprivate.h"
 #include "XPCJSWeakReference.h"
 
 #include "nsContentUtils.h"
 
+using namespace JS;
+
 xpcJSWeakReference::xpcJSWeakReference()
 {
 }
 
 NS_IMPL_ISUPPORTS1(xpcJSWeakReference, xpcIJSWeakReference)
 
 nsresult xpcJSWeakReference::Init(JSContext* cx, const JS::Value& object)
 {
@@ -64,20 +66,23 @@ xpcJSWeakReference::Get(JSContext* aCx, 
     if (!supports) {
         return NS_OK;
     }
 
     nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(supports);
     if (!wrappedObj) {
         // We have a generic XPCOM object that supports weak references here.
         // Wrap it and pass it out.
-        JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
-        return nsContentUtils::WrapNative(aCx, global,
-                                          supports, &NS_GET_IID(nsISupports),
-                                          aRetval);
+        RootedObject global(aCx, CurrentGlobalOrNull(aCx));
+        RootedValue rval(aCx);
+        nsresult rv = nsContentUtils::WrapNative(aCx, global,
+                                                 supports, &NS_GET_IID(nsISupports),
+                                                 &rval);
+        *aRetval = rval;
+        return rv;
     }
 
     JS::RootedObject obj(aCx, wrappedObj->GetJSObject());
     if (!obj) {
         return NS_OK;
     }
 
     // Most users of XPCWrappedJS don't need to worry about
--- a/js/xpconnect/src/XPCQuickStubs.cpp
+++ b/js/xpconnect/src/XPCQuickStubs.cpp
@@ -408,45 +408,51 @@ xpc_qsGetterOnlyNativeStub(JSContext *cx
 {
     return JS_ReportErrorFlagsAndNumber(cx,
                                         JSREPORT_WARNING | JSREPORT_STRICT |
                                         JSREPORT_STRICT_MODE_ERROR,
                                         js_GetErrorMessage, nullptr,
                                         JSMSG_GETTER_ONLY);
 }
 
-xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
+xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, HandleValue v,
+                                 MutableHandleValue pval, bool notpassed,
                                  StringificationBehavior nullBehavior,
                                  StringificationBehavior undefinedBehavior)
 {
     typedef implementation_type::char_traits traits;
     // From the T_DOMSTRING case in XPCConvert::JSData2Native.
-    JSString *s = InitOrStringify<traits>(cx, v, pval, nullBehavior,
+    JSString *s = InitOrStringify<traits>(cx, v,
+                                          pval, notpassed,
+                                          nullBehavior,
                                           undefinedBehavior);
     if (!s)
         return;
 
     size_t len;
     const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
     if (!chars) {
         mValid = false;
         return;
     }
 
     new(mBuf) implementation_type(chars, len);
     mValid = true;
 }
 
-xpc_qsACString::xpc_qsACString(JSContext *cx, jsval v, jsval *pval,
+xpc_qsACString::xpc_qsACString(JSContext *cx, HandleValue v,
+                               MutableHandleValue pval, bool notpassed,
                                StringificationBehavior nullBehavior,
                                StringificationBehavior undefinedBehavior)
 {
     typedef implementation_type::char_traits traits;
     // From the T_CSTRING case in XPCConvert::JSData2Native.
-    JSString *s = InitOrStringify<traits>(cx, v, pval, nullBehavior,
+    JSString *s = InitOrStringify<traits>(cx, v,
+                                          pval, notpassed,
+                                          nullBehavior,
                                           undefinedBehavior);
     if (!s)
         return;
 
     size_t len = JS_GetStringEncodingLength(cx, s);
     if (len == size_t(-1)) {
         mValid = false;
         return;
@@ -457,21 +463,21 @@ xpc_qsACString::xpc_qsACString(JSContext
         mValid = false;
         return;
     }
 
     new(mBuf) implementation_type(bytes.ptr(), len);
     mValid = true;
 }
 
-xpc_qsAUTF8String::xpc_qsAUTF8String(JSContext *cx, jsval v, jsval *pval)
+xpc_qsAUTF8String::xpc_qsAUTF8String(JSContext *cx, HandleValue v, MutableHandleValue pval, bool notpassed)
 {
     typedef nsCharTraits<PRUnichar> traits;
     // From the T_UTF8STRING  case in XPCConvert::JSData2Native.
-    JSString *s = InitOrStringify<traits>(cx, v, pval, eNull, eNull);
+    JSString *s = InitOrStringify<traits>(cx, v, pval, notpassed, eNull, eNull);
     if (!s)
         return;
 
     size_t len;
     const PRUnichar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
     if (!chars) {
         mValid = false;
         return;
@@ -569,49 +575,49 @@ getWrapper(JSContext *cx,
 nsresult
 castNative(JSContext *cx,
            XPCWrappedNative *wrapper,
            JSObject *curArg,
            XPCWrappedNativeTearOff *tearoff,
            const nsIID &iid,
            void **ppThis,
            nsISupports **pThisRef,
-           jsval *vp)
+           MutableHandleValue vp)
 {
     RootedObject cur(cx, curArg);
     if (wrapper) {
         nsresult rv = getNativeFromWrapper(cx,wrapper, iid, ppThis, pThisRef,
-                                           vp);
+                                           vp.address());
 
         if (rv != NS_ERROR_NO_INTERFACE)
             return rv;
     } else if (cur) {
         nsISupports *native;
         if (!(native = mozilla::dom::UnwrapDOMObjectToISupports(cur))) {
             *pThisRef = nullptr;
             return NS_ERROR_ILLEGAL_VALUE;
         }
 
-        if (NS_SUCCEEDED(getNative(native, cur, iid, ppThis, pThisRef, vp))) {
+        if (NS_SUCCEEDED(getNative(native, cur, iid, ppThis, pThisRef, vp.address()))) {
             return NS_OK;
         }
     }
 
     *pThisRef = nullptr;
     return NS_ERROR_XPC_BAD_OP_ON_WN_PROTO;
 }
 
 nsISupports*
 castNativeFromWrapper(JSContext *cx,
                       JSObject *obj,
                       uint32_t interfaceBit,
                       uint32_t protoID,
                       int32_t protoDepth,
                       nsISupports **pRef,
-                      jsval *pVal,
+                      MutableHandleValue pVal,
                       nsresult *rv)
 {
     XPCWrappedNative *wrapper;
     XPCWrappedNativeTearOff *tearoff;
     JSObject *cur;
 
     if (IS_WN_REFLECTOR(obj)) {
         cur = obj;
@@ -639,17 +645,17 @@ castNativeFromWrapper(JSContext *cx,
             native = nullptr;
         }
     } else {
         native = nullptr;
     }
 
     if (native) {
         *pRef = nullptr;
-        *pVal = OBJECT_TO_JSVAL(cur);
+        pVal.setObjectOrNull(cur);
         *rv = NS_OK;
     } else {
         *rv = NS_ERROR_XPC_BAD_CONVERT_JS;
     }
 
     return native;
 }
 
@@ -668,21 +674,21 @@ xpc_qsUnwrapThisFromCcxImpl(XPCCallConte
     nsresult rv = getNative(native, obj, iid, ppThis, pThisRef, vp);
     if (NS_FAILED(rv))
         return xpc_qsThrow(ccx.GetJSContext(), rv);
     return true;
 }
 
 nsresult
 xpc_qsUnwrapArgImpl(JSContext *cx,
-                    jsval v,
+                    HandleValue v,
                     const nsIID &iid,
                     void **ppArg,
                     nsISupports **ppArgRef,
-                    jsval *vp)
+                    MutableHandleValue vp)
 {
     nsresult rv;
     RootedObject src(cx, xpc_qsUnwrapObj(v, ppArgRef, &rv));
     if (!src) {
         *ppArg = nullptr;
 
         return rv;
     }
@@ -731,17 +737,17 @@ xpc_qsUnwrapArgImpl(JSContext *cx,
 
     // We need to go through the QueryInterface logic to make this return
     // the right thing for the various 'special' interfaces; e.g.
     // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
     // there is an outer to avoid nasty recursion.
     rv = wrappedJS->QueryInterface(iid, ppArg);
     if (NS_SUCCEEDED(rv)) {
         *ppArgRef = static_cast<nsISupports*>(*ppArg);
-        *vp = OBJECT_TO_JSVAL(wrappedJS->GetJSObject());
+        vp.setObjectOrNull(wrappedJS->GetJSObject());
     }
     return rv;
 }
 
 bool
 xpc_qsJsvalToCharStr(JSContext *cx, jsval v, JSAutoByteString *bytes)
 {
     JSString *str;
@@ -780,23 +786,23 @@ xpc_qsJsvalToWcharStr(JSContext *cx, jsv
 
     *pstr = static_cast<const PRUnichar *>(chars);
     return true;
 }
 
 namespace xpc {
 
 bool
-NonVoidStringToJsval(JSContext *cx, nsAString &str, JS::Value *rval)
+NonVoidStringToJsval(JSContext *cx, nsAString &str, MutableHandleValue rval)
 {
     nsStringBuffer* sharedBuffer;
     jsval jsstr = XPCStringConvert::ReadableToJSVal(cx, str, &sharedBuffer);
     if (JSVAL_IS_NULL(jsstr))
         return false;
-    *rval = jsstr;
+    rval.set(jsstr);
     if (sharedBuffer) {
         // The string was shared but ReadableToJSVal didn't addref it.
         // Move the ownership from str to jsstr.
         str.ForgetSharedBuffer();
     }
     return true;
 }
 
@@ -822,17 +828,17 @@ xpc_qsStringToJsstring(JSContext *cx, ns
         str.ForgetSharedBuffer();
     }
     return true;
 }
 
 bool
 xpc_qsXPCOMObjectToJsval(JSContext *cx, qsObjectHelper &aHelper,
                          const nsIID *iid, XPCNativeInterface **iface,
-                         jsval *rval)
+                         MutableHandleValue rval)
 {
     NS_PRECONDITION(iface, "Who did that and why?");
 
     // From the T_INTERFACE case in XPCConvert::NativeData2JS.
     // This is one of the slowest things quick stubs do.
 
     nsresult rv;
     if (!XPCConvert::NativeInterface2JSObject(rval, nullptr,
@@ -842,40 +848,40 @@ xpc_qsXPCOMObjectToJsval(JSContext *cx, 
         // or not.  This is a sloppy stab at the right semantics; the
         // method really ought to be fixed to behave consistently.
         if (!JS_IsExceptionPending(cx))
             xpc_qsThrow(cx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
         return false;
     }
 
 #ifdef DEBUG
-    JSObject* jsobj = JSVAL_TO_OBJECT(*rval);
+    JSObject* jsobj = rval.toObjectOrNull();
     if (jsobj && !js::GetObjectParent(jsobj))
         MOZ_ASSERT(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
                    "Why did we recreate this wrapper?");
 #endif
 
     return true;
 }
 
 bool
 xpc_qsVariantToJsval(JSContext *aCx,
                      nsIVariant *p,
-                     jsval *rval)
+                     MutableHandleValue rval)
 {
     // From the T_INTERFACE case in XPCConvert::NativeData2JS.
     // Error handling is in XPCWrappedNative::CallMethod.
     if (p) {
         nsresult rv;
         bool ok = XPCVariant::VariantDataToJS(p, &rv, rval);
         if (!ok)
             xpc_qsThrow(aCx, rv);
         return ok;
     }
-    *rval = JSVAL_NULL;
+    rval.setNull();
     return true;
 }
 
 #ifdef DEBUG
 void
 xpc_qsAssertContextOK(JSContext *cx)
 {
     XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
--- a/js/xpconnect/src/XPCQuickStubs.h
+++ b/js/xpconnect/src/XPCQuickStubs.h
@@ -137,26 +137,26 @@ xpc_qsGetterOnlyPropertyStub(JSContext *
                              bool strict, JS::MutableHandleValue vp);
 
 bool
 xpc_qsGetterOnlyNativeStub(JSContext *cx, unsigned argc, jsval *vp);
 
 /* Functions for converting values between COM and JS. */
 
 inline bool
-xpc_qsInt64ToJsval(JSContext *cx, int64_t i, jsval *rv)
+xpc_qsInt64ToJsval(JSContext *cx, int64_t i, JS::MutableHandleValue rv)
 {
-    *rv = JS_NumberValue(static_cast<double>(i));
+    rv.setNumber(static_cast<double>(i));
     return true;
 }
 
 inline bool
-xpc_qsUint64ToJsval(JSContext *cx, uint64_t u, jsval *rv)
+xpc_qsUint64ToJsval(JSContext *cx, uint64_t u, JS::MutableHandleValue rv)
 {
-    *rv = JS_NumberValue(static_cast<double>(u));
+    rv.setNumber(static_cast<double>(u));
     return true;
 }
 
 
 /* Classes for converting jsvals to string types. */
 
 template <class S, class T>
 class xpc_qsBasicString
@@ -230,48 +230,50 @@ protected:
      * If null is returned, then we either failed or fully initialized
      * |this|; in either case the caller should return immediately
      * without doing anything else. Otherwise, the JSString* created
      * from |v| will be returned.  It'll be rooted, as needed, in
      * *pval.  nullBehavior and undefinedBehavior control what happens
      * when |v| is JSVAL_IS_NULL and JSVAL_IS_VOID respectively.
      */
     template<class traits>
-    JSString* InitOrStringify(JSContext* cx, jsval v, jsval* pval,
+    JSString* InitOrStringify(JSContext* cx, jsval v,
+                              JS::MutableHandleValue pval,
+                              bool notpassed,
                               StringificationBehavior nullBehavior,
                               StringificationBehavior undefinedBehavior) {
         JSString *s;
         if (JSVAL_IS_STRING(v)) {
             s = JSVAL_TO_STRING(v);
         } else {
             StringificationBehavior behavior = eStringify;
             if (JSVAL_IS_NULL(v)) {
                 behavior = nullBehavior;
             } else if (JSVAL_IS_VOID(v)) {
                 behavior = undefinedBehavior;
             }
 
             // If pval is null, that means the argument was optional and
             // not passed; turn those into void strings if they're
             // supposed to be stringified.
-            if (behavior != eStringify || !pval) {
-                // Here behavior == eStringify implies !pval, so both eNull and
+            if (behavior != eStringify || notpassed) {
+                // Here behavior == eStringify implies notpassed, so both eNull and
                 // eStringify should end up with void strings.
                 (new(mBuf) implementation_type(traits::sEmptyBuffer, uint32_t(0)))->
                     SetIsVoid(behavior != eEmpty);
                 mValid = true;
                 return nullptr;
             }
 
             s = JS_ValueToString(cx, v);
             if (!s) {
                 mValid = false;
                 return nullptr;
             }
-            *pval = STRING_TO_JSVAL(s);  // Root the new string.
+            pval.setString(s);  // Root the new string.
         }
 
         return s;
     }
 };
 
 /**
  * Class for converting a jsval to DOMString.
@@ -285,53 +287,57 @@ protected:
  * The value in the jsval on entry is converted to a string. The constructor
  * may overwrite that jsval with a string value, to protect the characters of
  * the string from garbage collection. The caller must leave the jsval alone
  * for the lifetime of the xpc_qsDOMString.
  */
 class xpc_qsDOMString : public xpc_qsBasicString<nsAString, nsDependentString>
 {
 public:
-    xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
+    xpc_qsDOMString(JSContext *cx, JS::HandleValue v,
+                    JS::MutableHandleValue pval, bool notpassed,
                     StringificationBehavior nullBehavior,
                     StringificationBehavior undefinedBehavior);
 };
 
 /**
  * The same as xpc_qsDOMString, but with slightly different conversion behavior,
  * corresponding to the [astring] magic XPIDL annotation rather than [domstring].
  */
 class xpc_qsAString : public xpc_qsDOMString
 {
 public:
-    xpc_qsAString(JSContext *cx, jsval v, jsval *pval)
-        : xpc_qsDOMString(cx, v, pval, eNull, eNull)
+    xpc_qsAString(JSContext *cx, JS::HandleValue v,
+                  JS::MutableHandleValue pval, bool notpassed)
+        : xpc_qsDOMString(cx, v, pval, notpassed, eNull, eNull)
     {}
 };
 
 /**
  * Like xpc_qsDOMString and xpc_qsAString, but for XPIDL native types annotated
  * with [cstring] rather than [domstring] or [astring].
  */
 class xpc_qsACString : public xpc_qsBasicString<nsACString, nsCString>
 {
 public:
-    xpc_qsACString(JSContext *cx, jsval v, jsval *pval,
-                   StringificationBehavior nullBehavior = eNull,
-                   StringificationBehavior undefinedBehavior = eNull);
+    xpc_qsACString(JSContext *cx, JS::HandleValue v,
+                   JS::MutableHandleValue pval, bool notpassed,
+                   StringificationBehavior nullBehavior,
+                   StringificationBehavior undefinedBehavior);
 };
 
 /**
  * And similar for AUTF8String.
  */
 class xpc_qsAUTF8String :
   public xpc_qsBasicString<nsACString, NS_ConvertUTF16toUTF8>
 {
 public:
-  xpc_qsAUTF8String(JSContext* cx, jsval v, jsval *pval);
+  xpc_qsAUTF8String(JSContext* cx, JS::HandleValue v,
+                    JS::MutableHandleValue pval, bool notpassed);
 };
 
 struct xpc_qsSelfRef
 {
     xpc_qsSelfRef() : ptr(nullptr) {}
     explicit xpc_qsSelfRef(nsISupports *p) : ptr(p) {}
     ~xpc_qsSelfRef() { NS_IF_RELEASE(ptr); }
 
@@ -348,17 +354,17 @@ struct xpc_qsSelfRef
  * @param bytes
  *     Out. On success it receives the converted string unless v is null or
  *     undefinedin which case bytes->ptr() remains null.
  */
 bool
 xpc_qsJsvalToCharStr(JSContext *cx, jsval v, JSAutoByteString *bytes);
 
 bool
-xpc_qsJsvalToWcharStr(JSContext *cx, jsval v, jsval *pval, const PRUnichar **pstr);
+xpc_qsJsvalToWcharStr(JSContext *cx, jsval v, JS::MutableHandleValue pval, const PRUnichar **pstr);
 
 
 /** Convert an nsString to JSString, returning true on success. This will sometimes modify |str| to be empty. */
 bool
 xpc_qsStringToJsstring(JSContext *cx, nsString &str, JSString **rval);
 
 nsresult
 getWrapper(JSContext *cx,
@@ -370,17 +376,17 @@ getWrapper(JSContext *cx,
 nsresult
 castNative(JSContext *cx,
            XPCWrappedNative *wrapper,
            JSObject *cur,
            XPCWrappedNativeTearOff *tearoff,
            const nsIID &iid,
            void **ppThis,
            nsISupports **ppThisRef,
-           jsval *vp);
+           JS::MutableHandleValue vp);
 
 /**
  * Search @a obj and its prototype chain for an XPCOM object that implements
  * the interface T.
  *
  * If an object implementing T is found, store a reference to the wrapper
  * JSObject in @a *pThisVal, store a pointer to the T in @a *ppThis, and return
  * true. Otherwise, raise an exception on @a cx and return false.
@@ -394,17 +400,17 @@ castNative(JSContext *cx,
  * Requires a request on @a cx.
  */
 template <class T>
 inline bool
 xpc_qsUnwrapThis(JSContext *cx,
                  JS::HandleObject obj,
                  T **ppThis,
                  nsISupports **pThisRef,
-                 jsval *pThisVal,
+                 JS::MutableHandleValue pThisVal,
                  bool failureFatal = true)
 {
     XPCWrappedNative *wrapper;
     XPCWrappedNativeTearOff *tearoff;
     JS::RootedObject current(cx);
     nsresult rv = getWrapper(cx, obj, &wrapper, current.address(), &tearoff);
     if (NS_SUCCEEDED(rv))
         rv = castNative(cx, wrapper, current, tearoff, NS_GET_TEMPLATE_IID(T),
@@ -420,36 +426,36 @@ xpc_qsUnwrapThis(JSContext *cx,
 
 nsISupports*
 castNativeFromWrapper(JSContext *cx,
                       JSObject *obj,
                       uint32_t interfaceBit,
                       uint32_t protoID,
                       int32_t protoDepth,
                       nsISupports **pRef,
-                      jsval *pVal,
+                      JS::MutableHandleValue pVal,
                       nsresult *rv);
 
 bool
 xpc_qsUnwrapThisFromCcxImpl(XPCCallContext &ccx,
                             const nsIID &iid,
                             void **ppThis,
                             nsISupports **pThisRef,
-                            jsval *vp);
+                            JS::MutableHandleValue vp);
 
 /**
  * Alternate implementation of xpc_qsUnwrapThis using information already
  * present in the given XPCCallContext.
  */
 template <class T>
 inline bool
 xpc_qsUnwrapThisFromCcx(XPCCallContext &ccx,
                         T **ppThis,
                         nsISupports **pThisRef,
-                        jsval *pThisVal)
+                        JS::MutableHandleValue pThisVal)
 {
     return xpc_qsUnwrapThisFromCcxImpl(ccx,
                                        NS_GET_TEMPLATE_IID(T),
                                        reinterpret_cast<void **>(ppThis),
                                        pThisRef,
                                        pThisVal);
 }
 
@@ -467,41 +473,41 @@ xpc_qsUnwrapObj(jsval v, nsISupports **p
                : NS_ERROR_XPC_BAD_CONVERT_JS);
     }
 
     *ppArgRef = nullptr;
     return nullptr;
 }
 
 nsresult
-xpc_qsUnwrapArgImpl(JSContext *cx, jsval v, const nsIID &iid, void **ppArg,
-                    nsISupports **ppArgRef, jsval *vp);
+xpc_qsUnwrapArgImpl(JSContext *cx, JS::HandleValue v, const nsIID &iid, void **ppArg,
+                    nsISupports **ppArgRef, JS::MutableHandleValue vp);
 
 /** Convert a jsval to an XPCOM pointer. */
 template <class Interface, class StrongRefType>
 inline nsresult
-xpc_qsUnwrapArg(JSContext *cx, jsval v, Interface **ppArg,
-                StrongRefType **ppArgRef, jsval *vp)
+xpc_qsUnwrapArg(JSContext *cx, JS::HandleValue v, Interface **ppArg,
+                StrongRefType **ppArgRef, JS::MutableHandleValue vp)
 {
     nsISupports* argRef = *ppArgRef;
     nsresult rv = xpc_qsUnwrapArgImpl(cx, v, NS_GET_TEMPLATE_IID(Interface),
                                       reinterpret_cast<void **>(ppArg), &argRef,
                                       vp);
     *ppArgRef = static_cast<StrongRefType*>(argRef);
     return rv;
 }
 
 MOZ_ALWAYS_INLINE nsISupports*
 castNativeArgFromWrapper(JSContext *cx,
                          jsval v,
                          uint32_t bit,
                          uint32_t protoID,
                          int32_t protoDepth,
                          nsISupports **pArgRef,
-                         jsval *vp,
+                         JS::MutableHandleValue vp,
                          nsresult *rv)
 {
     JSObject *src = xpc_qsUnwrapObj(v, pArgRef, rv);
     if (!src)
         return nullptr;
 
     return castNativeFromWrapper(cx, src, bit, protoID, protoDepth, pArgRef, vp, rv);
 }
@@ -528,25 +534,25 @@ xpc_qsGetWrapperCache(void *p)
  * aIdentity is a performance optimization. Set it to true,
  * only if p is the identity pointer.
  */
 bool
 xpc_qsXPCOMObjectToJsval(JSContext *aCx,
                          qsObjectHelper &aHelper,
                          const nsIID *iid,
                          XPCNativeInterface **iface,
-                         jsval *rval);
+                         JS::MutableHandleValue rval);
 
 /**
  * Convert a variant to jsval. Return true on success.
  */
 bool
 xpc_qsVariantToJsval(JSContext *cx,
                      nsIVariant *p,
-                     jsval *rval);
+                     JS::MutableHandleValue rval);
 
 #ifdef DEBUG
 void
 xpc_qsAssertContextOK(JSContext *cx);
 
 inline bool
 xpc_qsSameResult(nsISupports *result1, nsISupports *result2)
 {
--- a/js/xpconnect/src/XPCString.cpp
+++ b/js/xpconnect/src/XPCString.cpp
@@ -66,17 +66,17 @@ XPCStringConvert::ReadableToJSVal(JSCont
 
     if (length == 0)
         return JS_GetEmptyStringValue(cx);
 
     nsStringBuffer *buf = nsStringBuffer::FromString(readable);
     if (buf) {
         JS::RootedValue val(cx);
         bool shared;
-        bool ok = StringBufferToJSVal(cx, buf, length, val.address(), &shared);
+        bool ok = StringBufferToJSVal(cx, buf, length, &val, &shared);
         if (!ok) {
             return JS::NullValue();
         }
 
         if (shared) {
             *sharedBuffer = buf;
         }
         return val;
--- a/js/xpconnect/src/XPCVariant.cpp
+++ b/js/xpconnect/src/XPCVariant.cpp
@@ -370,17 +370,17 @@ XPCVariant::GetAsJSVal(jsval* result)
   NS_PRECONDITION(result, "null result arg.");
   *result = GetJSVal();
   return NS_OK;
 }
 
 // static
 bool
 XPCVariant::VariantDataToJS(nsIVariant* variant,
-                            nsresult* pErr, jsval* pJSVal)
+                            nsresult* pErr, MutableHandleValue pJSVal)
 {
     // Get the type early because we might need to spoof it below.
     uint16_t type;
     if (NS_FAILED(variant->GetDataType(&type)))
         return false;
 
     AutoJSContext cx;
     RootedValue realVal(cx);
@@ -388,29 +388,29 @@ XPCVariant::VariantDataToJS(nsIVariant* 
 
     if (NS_SUCCEEDED(rv) &&
         (JSVAL_IS_PRIMITIVE(realVal) ||
          type == nsIDataType::VTYPE_ARRAY ||
          type == nsIDataType::VTYPE_EMPTY_ARRAY ||
          type == nsIDataType::VTYPE_ID)) {
         if (!JS_WrapValue(cx, realVal.address()))
             return false;
-        *pJSVal = realVal;
+        pJSVal.set(realVal);
         return true;
     }
 
     nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
     if (xpcvariant && xpcvariant->mReturnRawObject) {
         MOZ_ASSERT(type == nsIDataType::VTYPE_INTERFACE ||
                    type == nsIDataType::VTYPE_INTERFACE_IS,
                    "Weird variant");
 
         if (!JS_WrapValue(cx, realVal.address()))
             return false;
-        *pJSVal = realVal;
+        pJSVal.set(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.
 
     // We just fall through to the code below and let it do what it does.
 
@@ -431,25 +431,25 @@ XPCVariant::VariantDataToJS(nsIVariant* 
         case nsIDataType::VTYPE_UINT32:
         case nsIDataType::VTYPE_UINT64:
         case nsIDataType::VTYPE_FLOAT:
         case nsIDataType::VTYPE_DOUBLE:
         {
             double d;
             if (NS_FAILED(variant->GetAsDouble(&d)))
                 return false;
-            *pJSVal = JS_NumberValue(d);
+            pJSVal.setNumber(d);
             return true;
         }
         case nsIDataType::VTYPE_BOOL:
         {
             bool b;
             if (NS_FAILED(variant->GetAsBool(&b)))
                 return false;
-            *pJSVal = BOOLEAN_TO_JSVAL(b);
+            pJSVal.setBoolean(b);
             return true;
         }
         case nsIDataType::VTYPE_CHAR:
         {
             char c;
             if (NS_FAILED(variant->GetAsChar(&c)))
                 return false;
             return XPCConvert::NativeData2JS(pJSVal, (const void*)&c, TD_CHAR, &iid, pErr);
@@ -642,24 +642,24 @@ VARIANT_DONE:
             nsVariant::Cleanup(&du);
             return success;
         }
         case nsIDataType::VTYPE_EMPTY_ARRAY:
         {
             JSObject* array = JS_NewArrayObject(cx, 0, nullptr);
             if (!array)
                 return false;
-            *pJSVal = OBJECT_TO_JSVAL(array);
+            pJSVal.setObject(*array);
             return true;
         }
         case nsIDataType::VTYPE_VOID:
-            *pJSVal = JSVAL_VOID;
+            pJSVal.setUndefined();
             return true;
         case nsIDataType::VTYPE_EMPTY:
-            *pJSVal = JSVAL_NULL;
+            pJSVal.setNull();
             return true;
         default:
             NS_ERROR("bad type in variant!");
             return false;
     }
 }
 
 /***************************************************************************/
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -1225,17 +1225,17 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
                                                         getter_AddRefs(newThis)))) {
                                 goto pre_call_clean_up;
                             }
                             if (newThis) {
                                 RootedValue v(cx);
                                 xpcObjectHelper helper(newThis);
                                 bool ok =
                                   XPCConvert::NativeInterface2JSObject(
-                                      v.address(), nullptr, helper, nullptr,
+                                      &v, nullptr, helper, nullptr,
                                       nullptr, false, nullptr);
                                 if (!ok) {
                                     goto pre_call_clean_up;
                                 }
                                 thisObj = JSVAL_TO_OBJECT(v);
                                 if (!JS_WrapObject(cx, &thisObj))
                                     goto pre_call_clean_up;
                             }
@@ -1312,29 +1312,29 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
 
             if (isArray || isSizedString) {
                 if (!GetArraySizeFromParam(cx, info, param, methodIndex,
                                            i, nativeParams, &array_count))
                     goto pre_call_clean_up;
             }
 
             if (isArray) {
-                if (!XPCConvert::NativeArray2JS(val.address(),
+                if (!XPCConvert::NativeArray2JS(&val,
                                                 (const void**)&pv->val,
                                                 datum_type, &param_iid,
                                                 array_count, nullptr))
                     goto pre_call_clean_up;
             } else if (isSizedString) {
-                if (!XPCConvert::NativeStringWithSize2JS(val.address(),
+                if (!XPCConvert::NativeStringWithSize2JS(&val,
                                                          (const void*)&pv->val,
                                                          datum_type,
                                                          array_count, nullptr))
                     goto pre_call_clean_up;
             } else {
-                if (!XPCConvert::NativeData2JS(val.address(), &pv->val, type,
+                if (!XPCConvert::NativeData2JS(&val, &pv->val, type,
                                                &param_iid, nullptr))
                     goto pre_call_clean_up;
             }
         }
 
         if (param.IsOut() || param.IsDipper()) {
             // create an 'out' object
             RootedObject out_obj(cx, NewOutObject(cx, obj));
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -2313,33 +2313,33 @@ CallMethodHelper::GatherAndConvertResult
 
         nsID param_iid;
         if (datum_type.IsInterfacePointer() &&
             !GetInterfaceTypeFromParam(i, datum_type, &param_iid))
             return false;
 
         nsresult err;
         if (isArray) {
-            if (!XPCConvert::NativeArray2JS(v.address(), (const void**)&dp->val,
+            if (!XPCConvert::NativeArray2JS(&v, (const void**)&dp->val,
                                             datum_type, &param_iid,
                                             array_count, &err)) {
                 // XXX need exception scheme for arrays to indicate bad element
                 ThrowBadParam(err, i, mCallContext);
                 return false;
             }
         } else if (isSizedString) {
-            if (!XPCConvert::NativeStringWithSize2JS(v.address(),
+            if (!XPCConvert::NativeStringWithSize2JS(&v,
                                                      (const void*)&dp->val,
                                                      datum_type,
                                                      array_count, &err)) {
                 ThrowBadParam(err, i, mCallContext);
                 return false;
             }
         } else {
-            if (!XPCConvert::NativeData2JS(v.address(), &dp->val, datum_type,
+            if (!XPCConvert::NativeData2JS(&v, &dp->val, datum_type,
                                            &param_iid, &err)) {
                 ThrowBadParam(err, i, mCallContext);
                 return false;
             }
         }
 
         if (paramInfo.IsRetval()) {
             mCallContext.SetRetVal(v);
@@ -2392,17 +2392,17 @@ CallMethodHelper::QueryInterfaceFastPath
     if (NS_FAILED(invokeResult)) {
         ThrowBadResult(invokeResult, mCallContext);
         return false;
     }
 
     RootedValue v(mCallContext, NullValue());
     nsresult err;
     bool success =
-        XPCConvert::NativeData2JS(v.address(), &qiresult,
+        XPCConvert::NativeData2JS(&v, &qiresult,
                                   nsXPTType::T_INTERFACE_IS,
                                   iid, &err);
     NS_IF_RELEASE(qiresult);
 
     if (!success) {
         ThrowBadParam(err, 0, mCallContext);
         return false;
     }
--- a/js/xpconnect/src/XPCWrappedNativeInfo.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeInfo.cpp
@@ -60,18 +60,17 @@ XPCNativeMember::Resolve(XPCCallContext&
         // XXX Big Hack!
         nsXPTCVariant v;
         v.flags = 0;
         v.type = constant->GetType();
         memcpy(&v.val, &mv.val, sizeof(mv.val));
 
         RootedValue resultVal(ccx);
 
-        if (!XPCConvert::NativeData2JS(resultVal.address(), &v.val, v.type,
-                                       nullptr, nullptr))
+        if (!XPCConvert::NativeData2JS(&resultVal, &v.val, v.type, nullptr, nullptr))
             return false;
 
         *vp = resultVal;
 
         return true;
     }
     // else...
 
--- a/js/xpconnect/src/dictionary_helper_gen.py
+++ b/js/xpconnect/src/dictionary_helper_gen.py
@@ -304,29 +304,29 @@ def write_getter(a, iface, fd):
     elif realtype.count("double"):
         fd.write("    NS_ENSURE_STATE(JS_ValueToNumber(aCx, v, &aDict.%s));\n" % a.name)
     elif realtype.count("float"):
         fd.write("    double d;\n")
         fd.write("    NS_ENSURE_STATE(JS_ValueToNumber(aCx, v, &d));")
         fd.write("    aDict.%s = (float) d;\n" % a.name)
     elif realtype.count("nsAString"):
         if a.nullable:
-            fd.write("    xpc_qsDOMString d(aCx, v, v.address(), xpc_qsDOMString::eNull, xpc_qsDOMString::eNull);\n")
+            fd.write("    xpc_qsDOMString d(aCx, v, &v, false, xpc_qsDOMString::eNull, xpc_qsDOMString::eNull);\n")
         else:
-            fd.write("    xpc_qsDOMString d(aCx, v, v.address(), xpc_qsDOMString::eStringify, xpc_qsDOMString::eStringify);\n")
+            fd.write("    xpc_qsDOMString d(aCx, v, &v, false, xpc_qsDOMString::eStringify, xpc_qsDOMString::eStringify);\n")
         fd.write("    NS_ENSURE_STATE(d.IsValid());\n")
         fd.write("    aDict.%s = d;\n" % a.name)
     elif realtype.count("nsIVariant"):
         fd.write("    nsCOMPtr<nsIVariant> d(already_AddRefed<nsIVariant>(XPCVariant::newVariant(ccx, v)));\n")
         fd.write("    NS_ENSURE_STATE(d);\n")
         fd.write("    aDict.%s = d;\n" % a.name)
     elif realtype.endswith('*'):
         fd.write("    %s d;\n" % realtype)
         fd.write("    xpc_qsSelfRef ref;\n")
-        fd.write("    nsresult rv = xpc_qsUnwrapArg<%s>(aCx, v, &d, &ref.ptr, v.address());\n" % realtype.strip('* '))
+        fd.write("    nsresult rv = xpc_qsUnwrapArg<%s>(aCx, v, &d, &ref.ptr, &v);\n" % realtype.strip('* '))
         fd.write("    NS_ENSURE_SUCCESS(rv, rv);\n")
         fd.write("    aDict.%s = d;\n" % a.name)
     elif not realtype.count("JS::Value"):
         raise BaseException("Unsupported type %s found in dictionary %s" % (realtype, iface.name))
 
 def write_cpp(iface, fd):
     attributes = []
     for member in iface.members:
--- a/js/xpconnect/src/event_impl_gen.py
+++ b/js/xpconnect/src/event_impl_gen.py
@@ -310,17 +310,17 @@ def writeAttributeGetter(fd, classname, 
     fd.write("  return NS_OK;\n");
     fd.write("}\n\n");
     if a.realtype.nativeType('in').count("nsIVariant"):
         fd.write("JS::Value\n")
         fd.write("%s::Get%s(JSContext* aCx, ErrorResult& aRv)\n" % (classname, firstCap(a.name)))
         fd.write("{\n")
         fd.write("  JS::Rooted<JS::Value> retVal(aCx, JS::NullValue());\n");
         fd.write("  nsresult rv = NS_ERROR_UNEXPECTED;\n")
-        fd.write("  if (m%s && !XPCVariant::VariantDataToJS(m%s, &rv, retVal.address())) {\n" % (firstCap(a.name), firstCap(a.name)))
+        fd.write("  if (m%s && !XPCVariant::VariantDataToJS(m%s, &rv, &retVal)) {\n" % (firstCap(a.name), firstCap(a.name)))
         fd.write("    aRv.Throw(NS_ERROR_FAILURE);\n")
         fd.write("  }\n")
         fd.write("  return retVal;\n");
         fd.write("}\n\n")
 
 def writeAttributeParams(fd, a):
     if a.realtype.nativeType('in').endswith('*'):
         fd.write(", %s* a%s" % (a.realtype.nativeType('in').strip('* '), firstCap(a.name)))
--- a/js/xpconnect/src/nsDOMQS.h
+++ b/js/xpconnect/src/nsDOMQS.h
@@ -62,17 +62,17 @@ NEW_BINDING(nsDOMUIEvent, UIEvent);
 
 #define DEFINE_UNWRAP_CAST(_interface, _base, _bit)                           \
 template <>                                                                   \
 MOZ_ALWAYS_INLINE bool                                                        \
 xpc_qsUnwrapThis<_interface>(JSContext *cx,                                   \
                              JS::HandleObject obj,                            \
                              _interface **ppThis,                             \
                              nsISupports **pThisRef,                          \
-                             jsval *pThisVal,                                 \
+                             JS::MutableHandleValue pThisVal,                 \
                              bool failureFatal)                               \
 {                                                                             \
     nsresult rv;                                                              \
     nsISupports *native =                                                     \
         castNativeFromWrapper(cx, obj, _bit,                                  \
                               ProtoIDAndDepth<_interface>::PrototypeID,       \
                               ProtoIDAndDepth<_interface>::Depth,             \
                               pThisRef, pThisVal, &rv);                       \
@@ -81,67 +81,67 @@ xpc_qsUnwrapThis<_interface>(JSContext *
         return xpc_qsThrow(cx, rv);                                           \
     *ppThis = static_cast<_interface*>(static_cast<_base*>(native));          \
     return true;                                                              \
 }                                                                             \
                                                                               \
 template <>                                                                   \
 MOZ_ALWAYS_INLINE nsresult                                                    \
 xpc_qsUnwrapArg<_interface>(JSContext *cx,                                    \
-                            jsval v,                                          \
+                            JS::HandleValue v,                                \
                             _interface **ppArg,                               \
                             nsISupports **ppArgRef,                           \
-                            jsval *vp)                                        \
+                            JS::MutableHandleValue vp)                        \
 {                                                                             \
     nsresult rv;                                                              \
     nsISupports *native =                                                     \
         castNativeArgFromWrapper(cx, v, _bit,                                 \
                                  ProtoIDAndDepth<_interface>::PrototypeID,    \
                                  ProtoIDAndDepth<_interface>::Depth,          \
                                  ppArgRef, vp, &rv);                          \
     if (NS_SUCCEEDED(rv))                                                     \
         *ppArg = static_cast<_interface*>(static_cast<_base*>(native));       \
     return rv;                                                                \
 }                                                                             \
                                                                               \
 template <>                                                                   \
 inline nsresult                                                               \
 xpc_qsUnwrapArg<_interface>(JSContext *cx,                                    \
-                            jsval v,                                          \
+                            JS::HandleValue v,                                \
                             _interface **ppArg,                               \
                             _interface **ppArgRef,                            \
-                            jsval *vp)                                        \
+                            JS::MutableHandleValue vp)                        \
 {                                                                             \
     nsISupports* argRef = static_cast<_base*>(*ppArgRef);                     \
     nsresult rv = xpc_qsUnwrapArg<_interface>(cx, v, ppArg, &argRef, vp);     \
     *ppArgRef = static_cast<_interface*>(static_cast<_base*>(argRef));        \
     return rv;                                                                \
 }                                                                             \
                                                                               \
 namespace mozilla {                                                           \
 namespace dom {                                                               \
                                                                               \
 template <>                                                                   \
 MOZ_ALWAYS_INLINE nsresult                                                    \
 UnwrapArg<_interface>(JSContext *cx,                                          \
-                      jsval v,                                                \
+                      JS::HandleValue v,                                      \
                       _interface **ppArg,                                     \
                       nsISupports **ppArgRef,                                 \
-                      jsval *vp)                                              \
+                      JS::MutableHandleValue vp)                              \
 {                                                                             \
   return xpc_qsUnwrapArg<_interface>(cx, v, ppArg, ppArgRef, vp);             \
 }                                                                             \
                                                                               \
 template <>                                                                   \
 inline nsresult                                                               \
 UnwrapArg<_interface>(JSContext *cx,                                          \
-                      jsval v,                                                \
+                      JS::HandleValue v,                                      \
                       _interface **ppArg,                                     \
                       _interface **ppArgRef,                                  \
-                      jsval *vp)                                              \
+                      JS::MutableHandleValue vp)                              \
 {                                                                             \
   return xpc_qsUnwrapArg<_interface>(cx, v, ppArg, ppArgRef, vp);             \
 }                                                                             \
                                                                               \
 } /* namespace dom */                                                         \
 } /* namespace mozilla */
 
 #undef DOMCI_CASTABLE_INTERFACE
@@ -151,83 +151,83 @@ UnwrapArg<_interface>(JSContext *cx,    
   DEFINE_UNWRAP_CAST(_interface, _base, _bit)
 
 DOMCI_CASTABLE_INTERFACES(unused)
 
 #undef DOMCI_CASTABLE_INTERFACE
 
 inline nsresult
 xpc_qsUnwrapArg_HTMLElement(JSContext *cx,
-                            jsval v,
+                            JS::HandleValue v,
                             nsIAtom *aTag,
                             nsIContent **ppArg,
                             nsISupports **ppArgRef,
-                            jsval *vp)
+                            JS::MutableHandleValue vp)
 {
     nsGenericHTMLElement *elem;
-    jsval val;
+    JS::RootedValue val(cx);
     nsresult rv =
         xpc_qsUnwrapArg<nsGenericHTMLElement>(cx, v, &elem, ppArgRef, &val);
     if (NS_SUCCEEDED(rv)) {
         if (elem->IsHTML(aTag)) {
             *ppArg = elem;
-            *vp = val;
+            vp.set(val);
         } else {
             rv = NS_ERROR_XPC_BAD_CONVERT_JS;
         }
     }
     return rv;
 }
 
 #define DEFINE_UNWRAP_CAST_HTML(_tag, _clazz)                                 \
 template <>                                                                   \
 inline nsresult                                                               \
 xpc_qsUnwrapArg<_clazz>(JSContext *cx,                                        \
-                        jsval v,                                              \
+                        JS::HandleValue v,                                    \
                         _clazz **ppArg,                                       \
                         nsISupports **ppArgRef,                               \
-                        jsval *vp)                                            \
+                        JS::MutableHandleValue vp)                            \
 {                                                                             \
     nsIContent *elem;                                                         \
     nsresult rv = xpc_qsUnwrapArg_HTMLElement(cx, v, nsGkAtoms::_tag, &elem,  \
                                               ppArgRef, vp);                  \
     if (NS_SUCCEEDED(rv))                                                     \
         *ppArg = static_cast<_clazz*>(elem);                                  \
     return rv;                                                                \
 }                                                                             \
                                                                               \
 template <>                                                                   \
 inline nsresult                                                               \
-xpc_qsUnwrapArg<_clazz>(JSContext *cx, jsval v, _clazz **ppArg,               \
-                        _clazz **ppArgRef, jsval *vp)                         \
+xpc_qsUnwrapArg<_clazz>(JSContext *cx, JS::HandleValue v, _clazz **ppArg,     \
+                        _clazz **ppArgRef, JS::MutableHandleValue vp)         \
 {                                                                             \
     nsISupports* argRef = static_cast<nsIContent*>(*ppArgRef);                \
     nsresult rv = xpc_qsUnwrapArg<_clazz>(cx, v, ppArg, &argRef, vp);         \
     *ppArgRef = static_cast<_clazz*>(static_cast<nsIContent*>(argRef));       \
     return rv;                                                                \
 }                                                                             \
                                                                               \
 namespace mozilla {                                                           \
 namespace dom {                                                               \
                                                                               \
 template <>                                                                   \
 inline nsresult                                                               \
 UnwrapArg<_clazz>(JSContext *cx,                                              \
-                  jsval v,                                                    \
+                  JS::HandleValue v,                                          \
                   _clazz **ppArg,                                             \
                   nsISupports **ppArgRef,                                     \
-                  jsval *vp)                                                  \
+                  JS::MutableHandleValue vp)                                  \
 {                                                                             \
     return xpc_qsUnwrapArg<_clazz>(cx, v, ppArg, ppArgRef, vp);               \
 }                                                                             \
                                                                               \
 template <>                                                                   \
 inline nsresult                                                               \
-UnwrapArg<_clazz>(JSContext *cx, jsval v, _clazz **ppArg,                     \
-                  _clazz **ppArgRef, jsval *vp)                               \
+UnwrapArg<_clazz>(JSContext *cx, JS::HandleValue v, _clazz **ppArg,           \
+                  _clazz **ppArgRef, JS::MutableHandleValue vp)               \
 {                                                                             \
     return xpc_qsUnwrapArg<_clazz>(cx, v, ppArg, ppArgRef, vp);               \
 }                                                                             \
                                                                               \
 } /* namespace dom */                                                         \
 } /* namespace mozilla */
 
 DEFINE_UNWRAP_CAST_HTML(canvas, mozilla::dom::HTMLCanvasElement)
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -547,29 +547,29 @@ nsXPConnect::InitClassesWithNewWrappedGl
 }
 
 static nsresult
 NativeInterface2JSObject(HandleObject aScope,
                          nsISupports *aCOMObj,
                          nsWrapperCache *aCache,
                          const nsIID * aIID,
                          bool aAllowWrapping,
-                         jsval *aVal,
+                         MutableHandleValue aVal,
                          nsIXPConnectJSObjectHolder **aHolder)
 {
     AutoJSContext cx;
     JSAutoCompartment ac(cx, aScope);
 
     nsresult rv;
     xpcObjectHelper helper(aCOMObj, aCache);
     if (!XPCConvert::NativeInterface2JSObject(aVal, aHolder, helper, aIID,
                                               nullptr, aAllowWrapping, &rv))
         return rv;
 
-    MOZ_ASSERT(aAllowWrapping || !xpc::WrapperFactory::IsXrayWrapper(JSVAL_TO_OBJECT(*aVal)),
+    MOZ_ASSERT(aAllowWrapping || !xpc::WrapperFactory::IsXrayWrapper(&aVal.toObject()),
                "Shouldn't be returning a xray wrapper here");
 
     return NS_OK;
 }
 
 /* nsIXPConnectJSObjectHolder wrapNative (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */
 NS_IMETHODIMP
 nsXPConnect::WrapNative(JSContext * aJSContext,
@@ -581,17 +581,17 @@ nsXPConnect::WrapNative(JSContext * aJSC
     MOZ_ASSERT(aHolder, "bad param");
     MOZ_ASSERT(aJSContext, "bad param");
     MOZ_ASSERT(aScopeArg, "bad param");
     MOZ_ASSERT(aCOMObj, "bad param");
 
     RootedObject aScope(aJSContext, aScopeArg);
     RootedValue v(aJSContext);
     return NativeInterface2JSObject(aScope, aCOMObj, nullptr, &aIID,
-                                    false, v.address(), aHolder);
+                                    false, &v, aHolder);
 }
 
 /* void wrapNativeToJSVal (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDPtr aIID, out jsval aVal, out nsIXPConnectJSObjectHolder aHolder); */
 NS_IMETHODIMP
 nsXPConnect::WrapNativeToJSVal(JSContext * aJSContext,
                                JSObject * aScopeArg,
                                nsISupports *aCOMObj,
                                nsWrapperCache *aCache,
@@ -604,18 +604,21 @@ nsXPConnect::WrapNativeToJSVal(JSContext
     MOZ_ASSERT(aScopeArg, "bad param");
     MOZ_ASSERT(aCOMObj, "bad param");
 
     if (aHolder)
         *aHolder = nullptr;
 
     RootedObject aScope(aJSContext, aScopeArg);
 
-    return NativeInterface2JSObject(aScope, aCOMObj, aCache, aIID,
-                                    aAllowWrapping, aVal, aHolder);
+    RootedValue rval(aJSContext);
+    nsresult rv = NativeInterface2JSObject(aScope, aCOMObj, aCache, aIID,
+                                           aAllowWrapping, &rval, aHolder);
+    *aVal = rval;
+    return rv;
 }
 
 /* void wrapJS (in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
 NS_IMETHODIMP
 nsXPConnect::WrapJS(JSContext * aJSContext,
                     JSObject * aJSObjArg,
                     const nsIID & aIID,
                     void * *result)
@@ -1094,23 +1097,25 @@ nsXPConnect::VariantToJS(JSContext* ctx,
     NS_PRECONDITION(scopeArg, "bad param");
     NS_PRECONDITION(value, "bad param");
     NS_PRECONDITION(_retval, "bad param");
 
     RootedObject scope(ctx, scopeArg);
     MOZ_ASSERT(js::IsObjectInContextCompartment(scope, ctx));
 
     nsresult rv = NS_OK;
-    if (!XPCVariant::VariantDataToJS(value, &rv, _retval)) {
+    RootedValue rval(ctx);
+    if (!XPCVariant::VariantDataToJS(value, &rv, &rval)) {
         if (NS_FAILED(rv))
             return rv;
 
         return NS_ERROR_FAILURE;
     }
 
+    *_retval = rval;
     return NS_OK;
 }
 
 /* nsIVariant JSToVariant (in JSContextPtr ctx, in jsval value); */
 NS_IMETHODIMP
 nsXPConnect::JSToVariant(JSContext* ctx, const jsval &value, nsIVariant** _retval)
 {
     NS_PRECONDITION(ctx, "bad param");
@@ -1363,17 +1368,18 @@ namespace xpc {
 
 NS_EXPORT_(bool)
 Base64Encode(JSContext *cx, JS::Value val, JS::Value *out)
 {
     MOZ_ASSERT(cx);
     MOZ_ASSERT(out);
 
     JS::RootedValue root(cx, val);
-    xpc_qsACString encodedString(cx, root, root.address(), xpc_qsACString::eNull,
+    xpc_qsACString encodedString(cx, root, &root, false,
+                                 xpc_qsACString::eNull,
                                  xpc_qsACString::eStringify);
     if (!encodedString.IsValid())
         return false;
 
     nsAutoCString result;
     if (NS_FAILED(mozilla::Base64Encode(encodedString, result))) {
         JS_ReportError(cx, "Failed to encode base64 data!");
         return false;
@@ -1389,17 +1395,18 @@ Base64Encode(JSContext *cx, JS::Value va
 
 NS_EXPORT_(bool)
 Base64Decode(JSContext *cx, JS::Value val, JS::Value *out)
 {
     MOZ_ASSERT(cx);
     MOZ_ASSERT(out);
 
     JS::RootedValue root(cx, val);
-    xpc_qsACString encodedString(cx, root, root.address(), xpc_qsACString::eNull,
+    xpc_qsACString encodedString(cx, root, &root, false,
+                                 xpc_qsACString::eNull,
                                  xpc_qsACString::eNull);
     if (!encodedString.IsValid())
         return false;
 
     nsAutoCString result;
     if (NS_FAILED(mozilla::Base64Decode(encodedString, result))) {
         JS_ReportError(cx, "Failed to decode base64 string!");
         return false;
--- a/js/xpconnect/src/qsgen.py
+++ b/js/xpconnect/src/qsgen.py
@@ -432,22 +432,23 @@ argumentUnboxingTemplates = {
         "    if (!JS_ValueToNumber(cx, ${argVal}, &${name}))\n"
         "        return false;\n",
 
     'boolean':
         "    bool ${name};\n"
         "    JS_ValueToBoolean(cx, ${argVal}, &${name});\n",
 
     '[astring]':
-        "    xpc_qsAString ${name}(cx, ${argVal}, ${argPtr});\n"
+        "    xpc_qsAString ${name}(cx, ${argVal}, ${argPtr}, ${notPassed});\n"
         "    if (!${name}.IsValid())\n"
         "        return false;\n",
 
     '[domstring]':
-        "    xpc_qsDOMString ${name}(cx, ${argVal}, ${argPtr},\n"
+        "    xpc_qsDOMString ${name}(cx, ${argVal},\n"
+        "                            ${argPtr}, ${notPassed},\n"
         "                            xpc_qsDOMString::e${nullBehavior},\n"
         "                            xpc_qsDOMString::e${undefinedBehavior});\n"
         "    if (!${name}.IsValid())\n"
         "        return false;\n",
 
     'string':
         "    JSAutoByteString ${name}_bytes;\n"
         "    if (!xpc_qsJsvalToCharStr(cx, ${argVal}, &${name}_bytes))\n"
@@ -455,22 +456,22 @@ argumentUnboxingTemplates = {
         "    char *${name} = ${name}_bytes.ptr();\n",
 
     'wstring':
         "    const PRUnichar *${name};\n"
         "    if (!xpc_qsJsvalToWcharStr(cx, ${argVal}, ${argPtr}, &${name}))\n"
         "        return false;\n",
 
     '[cstring]':
-        "    xpc_qsACString ${name}(cx, ${argVal}, ${argPtr});\n"
+        "    xpc_qsACString ${name}(cx, ${argVal}, ${argPtr}, ${notPassed});\n"
         "    if (!${name}.IsValid())\n"
         "        return false;\n",
 
     '[utf8string]':
-        "    xpc_qsAUTF8String ${name}(cx, ${argVal}, ${argPtr});\n"
+        "    xpc_qsAUTF8String ${name}(cx, ${argVal}, ${argPtr}, ${notPassed});\n"
         "    if (!${name}.IsValid())\n"
         "        return false;\n",
 
     '[jsval]':
         "    JS::RootedValue ${name}(cx, ${argVal});\n"
     }
 
 # From JSData2Native.
@@ -479,51 +480,64 @@ argumentUnboxingTemplates = {
 # `null`; this behavior is from XPCWrappedNative::CallMethod. The 'jsval' type,
 # however, defaults to 'undefined'.
 #
 def writeArgumentUnboxing(f, i, name, type, optional, rvdeclared,
                           nullBehavior, undefinedBehavior,
                           propIndex=None):
     # f - file to write to
     # i - int or None - Indicates the source jsval.  If i is an int, the source
-    #     jsval is argv[i]; otherwise it is argv[0].  But if Python i >= C++ argc,
+    #     jsval is args[i]; otherwise it is args[0].  But if Python i >= C++ argc,
     #     which can only happen if optional is True, the argument is missing;
     #     use JSVAL_NULL as the source jsval instead.
     # name - str - name of the native C++ variable to create.
     # type - xpidl.{Interface,Native,Builtin} - IDL type of argument
     # optional - bool - True if the parameter is optional.
     # rvdeclared - bool - False if no |nsresult rv| has been declared earlier.
 
     typeName = getBuiltinOrNativeTypeName(type)
 
     isSetter = (i is None)
 
+    notPassed = "false"
     if isSetter:
-        argPtr = "argv[0].address()"
-        argVal = "argv[0]"
+        argPtr = "args[0]"
+        argVal = "args[0]"
     elif optional:
         if typeName == "[jsval]":
             val = "JS::UndefinedHandleValue"
         else:
             val = "JS::NullHandleValue"
-        argVal = "(%d < argc ? argv[%d] : %s)" % (i, i, val)
+        argVal = "(%d < argc ? args[%d] : %s)" % (i, i, val)
         if typeName == "[jsval]":
             # This should use the rooted argument,
             # however we probably won't ever need to support that.
             argPtr = None
+            notPassed = None
         else:
-            argPtr = "(%d < argc ? argv[%d].address() : NULL)" % (i, i)
+            # Need a MutableHandleValue to pass into eg the xpc_qsAString
+            # constructor, but the corresponding argument may not have been
+            # passed in at all. In that case, point the MutableHandleValue at a
+            # dummy variable, and pass in a boolean saying that the argument
+            # wasn't passed (previously, this used a NULL ptr sentinel value.)
+            f.write("    JS::RootedValue {name}_dummy(cx);\n".format(name=name))
+            f.write("    JS::MutableHandleValue {name}_mhv({i} < argc ? args[{i}] : &{name}_dummy);\n".format(name=name, i=i))
+            f.write("    (void) {name}_mhv;\n".format(name=name, i=i))
+
+            argPtr = "{name}_mhv".format(name=name)
+            notPassed = "argc < {i}".format(i=i)
     else:
-        argVal = "argv[%d]" % i
-        argPtr = argVal + ".address()"
+        argVal = "args[%d]" % i
+        argPtr = "args[%d]" % i
 
     params = {
         'name': name,
         'argVal': argVal,
         'argPtr': argPtr,
+        'notPassed': notPassed,
         'nullBehavior': nullBehavior or 'DefaultNullBehavior',
         'undefinedBehavior': undefinedBehavior or 'DefaultUndefinedBehavior'
         }
 
     if typeName is not None:
         template = argumentUnboxingTemplates.get(typeName)
         if template is not None:
             f.write(substitute(template, params))
@@ -560,19 +574,19 @@ def writeArgumentUnboxing(f, i, name, ty
             else:
                 f.write("        xpc_qsThrowBadArg(cx, rv, vp, %d);\n" % i)
             f.write("        return false;\n"
                     "    }\n")
             return True
 
     warn("Unable to unbox argument of type %s (native type %s)" % (type.name, typeName))
     if i is None:
-        src = 'argv[0]'
+        src = 'args[0]'
     else:
-        src = 'argv[%d]' % i
+        src = 'args[%d]' % i
     f.write("    !; // TODO - Unbox argument %s = %s\n" % (name, src))
     return rvdeclared
 
 def writeResultDecl(f, type, varname):
     if isVoidType(type):
         return  # nothing to declare
 
     t = unaliasType(type)
@@ -659,18 +673,18 @@ resultConvTemplates = {
 
     '[astring]':
         "    return xpc::StringToJsval(cx, result, ${jsvalPtr});\n",
 
     '[domstring]':
         "    return xpc::StringToJsval(cx, result, ${jsvalPtr});\n",
 
     '[jsval]':
-        "    ${jsvalRef} = result;\n"
-        "    return JS_WrapValue(cx, ${jsvalPtr});\n"
+        "    ${jsvalPtr}.set(result);\n"
+        "    return JS_WrapValue(cx, ${jsvalPtr}.address());\n"
     }
 
 def isVariantType(t):
     return isSpecificInterfaceType(t, 'nsIVariant')
 
 def writeResultConv(f, type, jsvalPtr, jsvalRef):
     """ Emit code to convert the C++ variable `result` to a jsval.
 
@@ -689,17 +703,17 @@ def writeResultConv(f, type, jsvalPtr, j
         # else fall through; this type isn't supported yet
     elif isInterfaceType(type):
         if isVariantType(type):
             f.write("    return xpc_qsVariantToJsval(cx, result, %s);\n"
                     % jsvalPtr)
             return
         else:
             f.write("    if (!result) {\n"
-                    "      *%s = JSVAL_NULL;\n"
+                    "      %s.setNull();\n"
                     "      return true;\n"
                     "    }\n"
                     "    nsWrapperCache* cache = xpc_qsGetWrapperCache(result);\n"
                     "    if (xpc_FastGetCachedWrapper(cache, obj, %s)) {\n"
                     "      return true;\n"
                     "    }\n"
                     "    // After this point do not use 'result'!\n"
                     "    qsObjectHelper helper(result, cache);\n"
@@ -827,42 +841,46 @@ def writeQuickStub(f, customMethodCalls,
     else:
         additionalArguments = " %s," % customMethodCall['additionalArguments']
     if disableOptimizationForMSVC:
         setOptimizationForMSVC(f, False)
     f.write(signature % (stubName, additionalArguments))
     f.write("{\n")
     f.write("    XPC_QS_ASSERT_CONTEXT_OK(cx);\n")
 
+    # Compute "args".
+    f.write("    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n")
+    f.write("    (void) args;\n")
+
     # Compute "this".
     f.write("    JS::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));\n"
             "    if (!obj)\n"
             "        return false;\n")
 
     # Get the 'self' pointer.
     if customMethodCall is None or not 'thisType' in customMethodCall:
         f.write("    %s *self;\n" % member.iface.name)
     else:
         f.write("    %s *self;\n" % customMethodCall['thisType'])
     f.write("    xpc_qsSelfRef selfref;\n")
-    pthisval = '&vp[1]' # as above, ok to overwrite vp[1]
+    pthisval = 'JS::MutableHandleValue::fromMarkedLocation(&vp[1])' # as above, ok to overwrite vp[1]
 
     if unwrapThisFailureFatal:
         unwrapFatalArg = "true"
     else:
         unwrapFatalArg = "false"
 
     f.write("    if (!xpc_qsUnwrapThis(cx, obj, &self, "
             "&selfref.ptr, %s, %s))\n" % (pthisval, unwrapFatalArg))
     f.write("        return false;\n")
 
     if not unwrapThisFailureFatal:
         f.write("      if (!self) {\n")
         if (isGetter):
-            f.write("        *vp = JSVAL_NULL;\n")
+            f.write("        args.rval().setNull();\n")
         f.write("        return true;\n")
         f.write("    }\n");
 
     if isMethod:
         # If there are any required arguments, check argc.
         requiredArgs = len(member.params)
         while requiredArgs and member.params[requiredArgs-1].optional:
             requiredArgs -= 1
@@ -873,18 +891,16 @@ def writeQuickStub(f, customMethodCalls,
     if requiredArgs:
         f.write("    if (argc < %d)\n" % requiredArgs)
         f.write("        return xpc_qsThrow(cx, "
                 "NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n")
 
     # Convert in-parameters.
     rvdeclared = False
     if isMethod:
-        if len(member.params) > 0:
-            f.write("    JS::CallArgs argv = JS::CallArgsFromVp(argc, vp);\n")
         for i, param in enumerate(member.params):
             argName = 'arg%d' % i
             argTypeKey = argName + 'Type'
             if customMethodCall is None or not argTypeKey in customMethodCall:
                 validateParam(member, param)
                 realtype = param.realtype
             else:
                 realtype = xpidl.Forward(name=customMethodCall[argTypeKey],
@@ -892,17 +908,16 @@ def writeQuickStub(f, customMethodCalls,
             # Emit code to convert this argument from jsval.
             rvdeclared = writeArgumentUnboxing(
                 f, i, argName, realtype,
                 optional=param.optional,
                 rvdeclared=rvdeclared,
                 nullBehavior=param.null,
                 undefinedBehavior=param.undefined)
     elif isSetter:
-        f.write("    JS::CallArgs argv = JS::CallArgsFromVp(argc, vp);\n")
         rvdeclared = writeArgumentUnboxing(f, None, 'arg0', member.realtype,
                                            optional=False,
                                            rvdeclared=rvdeclared,
                                            nullBehavior=member.null,
                                            undefinedBehavior=member.undefined,
                                            propIndex=stringtable.stringIndex(member.name))
 
     canFail = customMethodCall is None or customMethodCall.get('canFail', True)
@@ -977,17 +992,17 @@ def writeQuickStub(f, customMethodCalls,
                     "cx, rv, vp);\n")
         else:
             f.write("        return xpc_qsThrowGetterSetterFailed(cx, rv, " +
                     "JSVAL_TO_OBJECT(vp[1]), (uint16_t)%d);\n" %
                     stringtable.stringIndex(member.name))
 
     # Convert the return value.
     if isMethod or isGetter:
-        writeResultConv(f, member.realtype, 'vp', '*vp')
+        writeResultConv(f, member.realtype, 'args.rval()', '*vp')
     else:
         f.write("    return true;\n")
 
     # Epilog.
     f.write("}\n")
     if disableOptimizationForMSVC:
         setOptimizationForMSVC(f, True)
     f.write("\n")
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2812,17 +2812,17 @@ public:
      * @param s the native object we're working with
      * @param type the type of object that s is
      * @param iid the interface of s that we want
      * @param scope the default scope to put on the new JSObject's parent
      *        chain
      * @param pErr [out] relevant error code, if any.
      */
 
-    static bool NativeData2JS(jsval* d,
+    static bool NativeData2JS(JS::MutableHandleValue d,
                               const void* s, const nsXPTType& type,
                               const nsID* iid, nsresult* pErr);
 
     static bool JSData2Native(void* d, JS::HandleValue s,
                               const nsXPTType& type,
                               bool useAllocator, const nsID* iid,
                               nsresult* pErr);
 
@@ -2836,17 +2836,17 @@ public:
      * @param cache the wrapper cache for src (may be null, in which case src
      *              will be QI'ed to get the cache)
      * @param allowNativeWrapper if true, this method may wrap the resulting
      *        JSObject in an XPCNativeWrapper and return that, as needed.
      * @param pErr [out] relevant error code, if any.
      * @param src_is_identity optional performance hint. Set to true only
      *                        if src is the identity pointer.
      */
-    static bool NativeInterface2JSObject(jsval* d,
+    static bool NativeInterface2JSObject(JS::MutableHandleValue d,
                                          nsIXPConnectJSObjectHolder** dest,
                                          xpcObjectHelper& aHelper,
                                          const nsID* iid,
                                          XPCNativeInterface** Interface,
                                          bool allowNativeWrapper,
                                          nsresult* pErr);
 
     static bool GetNativeInterfaceFromJSObject(void** dest, JSObject* src,
@@ -2864,31 +2864,31 @@ public:
      * @param d [out] the resulting jsval
      * @param s the native array we're working with
      * @param type the type of objects in the array
      * @param iid the interface of each object in the array that we want
      * @param count the number of items in the array
      * @param scope the default scope to put on the new JSObjects' parent chain
      * @param pErr [out] relevant error code, if any.
      */
-    static bool NativeArray2JS(jsval* d, const void** s,
+    static bool NativeArray2JS(JS::MutableHandleValue d, const void** s,
                                const nsXPTType& type, const nsID* iid,
                                uint32_t count, nsresult* pErr);
 
     static bool JSArray2Native(void** d, JS::HandleValue s,
                                uint32_t count, const nsXPTType& type,
                                const nsID* iid, nsresult* pErr);
 
     static bool JSTypedArray2Native(void** d,
                                     JSObject* jsarray,
                                     uint32_t count,
                                     const nsXPTType& type,
                                     nsresult* pErr);
 
-    static bool NativeStringWithSize2JS(jsval* d, const void* s,
+    static bool NativeStringWithSize2JS(JS::MutableHandleValue d, const void* s,
                                         const nsXPTType& type,
                                         uint32_t count,
                                         nsresult* pErr);
 
     static bool JSStringWithSize2Native(void* d, JS::HandleValue s,
                                         uint32_t count, const nsXPTType& type,
                                         nsresult* pErr);
 
@@ -3497,17 +3497,17 @@ public:
      *
      * @param ccx the context for the whole procedure
      * @param variant the variant to convert
      * @param scope the default scope to put on the new JSObject's parent chain
      * @param pErr [out] relevant error code, if any.
      * @param pJSVal [out] the resulting jsval.
      */
     static bool VariantDataToJS(nsIVariant* variant,
-                                nsresult* pErr, jsval* pJSVal);
+                                nsresult* pErr, JS::MutableHandleValue pJSVal);
 
     bool IsPurple()
     {
         return mRefCnt.IsPurple();
     }
 
     void RemovePurple()
     {
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -97,25 +97,25 @@ static inline bool IS_WN_REFLECTOR(JSObj
 {
     return IS_WN_CLASS(js::GetObjectClass(obj));
 }
 
 extern bool
 xpc_OkToHandOutWrapper(nsWrapperCache *cache);
 
 inline JSObject*
-xpc_FastGetCachedWrapper(nsWrapperCache *cache, JSObject *scope, jsval *vp)
+xpc_FastGetCachedWrapper(nsWrapperCache *cache, JSObject *scope, JS::MutableHandleValue vp)
 {
     if (cache) {
         JSObject* wrapper = cache->GetWrapper();
         if (wrapper &&
             js::GetObjectCompartment(wrapper) == js::GetObjectCompartment(scope) &&
             (cache->IsDOMBinding() ? !cache->HasSystemOnlyWrapper() :
                                      xpc_OkToHandOutWrapper(cache))) {
-            *vp = OBJECT_TO_JSVAL(wrapper);
+            vp.setObject(*wrapper);
             return wrapper;
         }
     }
 
     return nullptr;
 }
 
 // The JS GC marks objects gray that are held alive directly or
@@ -169,33 +169,33 @@ public:
     // get assigned to *sharedBuffer.  Otherwise null will be
     // assigned.
     static jsval ReadableToJSVal(JSContext *cx, const nsAString &readable,
                                  nsStringBuffer** sharedBuffer);
 
     // Convert the given stringbuffer/length pair to a jsval
     static MOZ_ALWAYS_INLINE bool
     StringBufferToJSVal(JSContext* cx, nsStringBuffer* buf, uint32_t length,
-                        JS::Value* rval, bool* sharedBuffer)
+                        JS::MutableHandleValue rval, bool* sharedBuffer)
     {
         if (buf == sCachedBuffer &&
             JS::GetGCThingZone(sCachedString) == js::GetContextZone(cx))
         {
-            *rval = JS::StringValue(sCachedString);
+            rval.set(JS::StringValue(sCachedString));
             *sharedBuffer = false;
             return true;
         }
 
         JSString *str = JS_NewExternalString(cx,
                                              static_cast<jschar*>(buf->Data()),
                                              length, &sDOMStringFinalizer);
         if (!str) {
             return false;
         }
-        *rval = JS::StringValue(str);
+        rval.setString(str);
         sCachedString = str;
         sCachedBuffer = buf;
         *sharedBuffer = true;
         return true;
     }
 
     static void ClearCache();
 
@@ -215,56 +215,56 @@ namespace xpc {
 NS_EXPORT_(bool) Base64Encode(JSContext *cx, JS::Value val, JS::Value *out);
 NS_EXPORT_(bool) Base64Decode(JSContext *cx, JS::Value val, JS::Value *out);
 
 /**
  * Convert an nsString to jsval, returning true on success.
  * Note, the ownership of the string buffer may be moved from str to rval.
  * If that happens, str will point to an empty string after this call.
  */
-bool NonVoidStringToJsval(JSContext *cx, nsAString &str, JS::Value *rval);
-inline bool StringToJsval(JSContext *cx, nsAString &str, JS::Value *rval)
+bool NonVoidStringToJsval(JSContext *cx, nsAString &str, JS::MutableHandleValue rval);
+inline bool StringToJsval(JSContext *cx, nsAString &str, JS::MutableHandleValue rval)
 {
     // From the T_DOMSTRING case in XPCConvert::NativeData2JS.
     if (str.IsVoid()) {
-        *rval = JSVAL_NULL;
+        rval.setNull();
         return true;
     }
     return NonVoidStringToJsval(cx, str, rval);
 }
 
 inline bool
-NonVoidStringToJsval(JSContext* cx, const nsAString& str, JS::Value *rval)
+NonVoidStringToJsval(JSContext* cx, const nsAString& str, JS::MutableHandleValue rval)
 {
     nsString mutableCopy(str);
     return NonVoidStringToJsval(cx, mutableCopy, rval);
 }
 
 inline bool
-StringToJsval(JSContext* cx, const nsAString& str, JS::Value *rval)
+StringToJsval(JSContext* cx, const nsAString& str, JS::MutableHandleValue rval)
 {
     nsString mutableCopy(str);
     return StringToJsval(cx, mutableCopy, rval);
 }
 
 /**
  * As above, but for mozilla::dom::DOMString.
  */
 MOZ_ALWAYS_INLINE
 bool NonVoidStringToJsval(JSContext* cx, mozilla::dom::DOMString& str,
-                          JS::Value *rval)
+                          JS::MutableHandleValue rval)
 {
     if (!str.HasStringBuffer()) {
         // It's an actual XPCOM string
         return NonVoidStringToJsval(cx, str.AsAString(), rval);
     }
 
     uint32_t length = str.StringBufferLength();
     if (length == 0) {
-        *rval = JS_GetEmptyStringValue(cx);
+        rval.set(JS_GetEmptyStringValue(cx));
         return true;
     }
 
     nsStringBuffer* buf = str.StringBuffer();
     bool shared;
     if (!XPCStringConvert::StringBufferToJSVal(cx, buf, length, rval,
                                                &shared)) {
         return false;
@@ -273,20 +273,20 @@ bool NonVoidStringToJsval(JSContext* cx,
         // JS now needs to hold a reference to the buffer
         buf->AddRef();
     }
     return true;
 }
 
 MOZ_ALWAYS_INLINE
 bool StringToJsval(JSContext* cx, mozilla::dom::DOMString& str,
-                   JS::Value *rval)
+                   JS::MutableHandleValue rval)
 {
     if (str.IsNull()) {
-        *rval = JS::NullValue();
+        rval.setNull();
         return true;
     }
     return NonVoidStringToJsval(cx, str, rval);
 }
 
 nsIPrincipal *GetCompartmentPrincipal(JSCompartment *compartment);
 nsIPrincipal *GetObjectPrincipal(JSObject *obj);
 
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1403,18 +1403,20 @@ XrayWrapper<Base, Traits>::getPropertyDe
         return false;
 
     // We need to handle named access on the Window somewhere other than
     // Traits::resolveOwnProperty, because per spec it happens on the Global
     // Scope Polluter and thus the resulting properties are non-|own|. However,
     // we're set up (above) to cache (on the holder) anything that comes out of
     // resolveNativeProperty, which we don't want for something dynamic like
     // named access. So we just handle it separately here.
-    nsGlobalWindow *win;
-    if (!desc.object() && Traits::Type == XrayForWrappedNative && JSID_IS_STRING(id) &&
+    nsGlobalWindow *win = nullptr;
+    if (!desc.object() &&
+        (Traits::Type == XrayForWrappedNative) &&
+        JSID_IS_STRING(id) &&
         (win = static_cast<nsGlobalWindow*>(As<nsPIDOMWindow>(wrapper))))
     {
         nsDependentJSString name(id);
         nsCOMPtr<nsIDOMWindow> childDOMWin = win->GetChildWindow(name);
         if (childDOMWin) {
             nsGlobalWindow *cwin = static_cast<nsGlobalWindow*>(childDOMWin.get());
             JSObject *childObj = cwin->FastGetGlobalJSObject();
             if (MOZ_UNLIKELY(!childObj))