Bug 865969 part 6. Fix rooting hazards in BindingUtils.cpp. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 03 May 2013 19:29:08 -0400
changeset 141759 35c6ad8bb2e4aeac66cb6c80eac2216b96fbc43f
parent 141758 f7dbbff05f4890493d8ad2f5075147e49687b18f
child 141760 53c579eac0dee334b576e285a2f6db94b12cdfae
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs865969
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 865969 part 6. Fix rooting hazards in BindingUtils.cpp. r=smaug
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/DOMJSClass.h
dom/bindings/DOMJSProxyHandler.cpp
dom/bindings/DOMJSProxyHandler.h
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -185,33 +185,34 @@ Define(JSContext* cx, JSObject* obj, con
 }
 static inline bool
 Define(JSContext* cx, JSObject* obj, const ConstantSpec* spec) {
   return DefineConstants(cx, obj, spec);
 }
 
 template<typename T>
 bool
-DefinePrefable(JSContext* cx, JSObject* obj, const Prefable<T>* props)
+DefinePrefable(JSContext* cx, JS::Handle<JSObject*> obj,
+               const Prefable<T>* props)
 {
   MOZ_ASSERT(props);
   MOZ_ASSERT(props->specs);
   do {
     // Define if enabled
     if (props->isEnabled(cx, obj)) {
       if (!Define(cx, obj, props->specs)) {
         return false;
       }
     }
   } while ((++props)->specs);
   return true;
 }
 
 bool
-DefineUnforgeableAttributes(JSContext* cx, JSObject* obj,
+DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
                             const Prefable<const JSPropertySpec>* props)
 {
   return DefinePrefable(cx, obj, props);
 }
 
 
 // We should use JSFunction objects for interface objects, but we need a custom
 // hasInstance hook because we have new interface objects on prototype chains of
@@ -222,19 +223,19 @@ DefineUnforgeableAttributes(JSContext* c
 enum {
   TOSTRING_CLASS_RESERVED_SLOT = 0,
   TOSTRING_NAME_RESERVED_SLOT = 1
 };
 
 JSBool
 InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
 {
-  JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
+  JS::Rooted<JSObject*> callee(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
 
-  JSObject* obj = JS_THIS_OBJECT(cx, vp);
+  JS::Rooted<JSObject*> obj(cx, JS_THIS_OBJECT(cx, vp));
   if (!obj) {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
                          "null", "object");
     return false;
   }
 
   JS::Value v = js::GetFunctionNativeReserved(callee,
                                               TOSTRING_CLASS_RESERVED_SLOT);
@@ -427,17 +428,19 @@ CreateInterfaceObject(JSContext* cx, JS:
       ++namedConstructors;
     }
   }
 
   return constructor;
 }
 
 bool
-DefineWebIDLBindingPropertiesOnXPCProto(JSContext* cx, JSObject* proto, const NativeProperties* properties)
+DefineWebIDLBindingPropertiesOnXPCProto(JSContext* cx,
+                                        JS::Handle<JSObject*> proto,
+                                        const NativeProperties* properties)
 {
   if (properties->methods &&
       !DefinePrefable(cx, proto, properties->methods)) {
     return false;
   }
 
   if (properties->attributes &&
       !DefinePrefable(cx, proto, properties->attributes)) {
@@ -661,17 +664,17 @@ VariantToJsval(JSContext* aCx, JS::Handl
   }
 
   return true;
 }
 
 JSBool
 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
 {
-  JS::Value thisv = JS_THIS(cx, vp);
+  JS::Rooted<JS::Value> thisv(cx, JS_THIS(cx, vp));
   if (thisv.isNull())
     return false;
 
   // Get the object. It might be a security wrapper, in which case we do a checked
   // unwrap.
   JS::Rooted<JSObject*> origObj(cx, &thisv.toObject());
   JSObject* obj = js::CheckedUnwrap(origObj);
   if (!obj) {
@@ -723,17 +726,18 @@ QueryInterface(JSContext* cx, unsigned a
 
 JSBool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
 {
   return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
 }
 
 inline const NativePropertyHooks*
-GetNativePropertyHooks(JSContext *cx, JSObject *obj, DOMObjectType& type)
+GetNativePropertyHooks(JSContext *cx, JS::Handle<JSObject*> obj,
+                       DOMObjectType& type)
 {
   const DOMClass* domClass = GetDOMClass(obj);
   if (domClass) {
     type = eInstance;
     return domClass->mNativeHooks;
   }
 
   if (JS_ObjectIsFunction(cx, obj)) {
@@ -750,49 +754,52 @@ GetNativePropertyHooks(JSContext *cx, JS
   MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));
   const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
     DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
   type = ifaceAndProtoJSClass->mType;
   return ifaceAndProtoJSClass->mNativeHooks;
 }
 
 bool
-XrayResolveOwnProperty(JSContext* cx, JSObject* wrapper, JSObject* obj, jsid id,
+XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                       JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                        JSPropertyDescriptor* desc, unsigned flags)
 {
   DOMObjectType type;
   const NativePropertyHooks *nativePropertyHooks =
     GetNativePropertyHooks(cx, obj, type);
 
   return type != eInstance || !nativePropertyHooks->mResolveOwnProperty ||
          nativePropertyHooks->mResolveOwnProperty(cx, wrapper, obj, id, desc,
                                                   flags);
 }
 
 static bool
-XrayResolveAttribute(JSContext* cx, JSObject* wrapper, JSObject* obj, jsid id,
+XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                     JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                      const Prefable<const JSPropertySpec>* attributes, jsid* attributeIds,
                      const JSPropertySpec* attributeSpecs, JSPropertyDescriptor* desc)
 {
   for (; attributes->specs; ++attributes) {
     if (attributes->isEnabled(cx, obj)) {
       // Set i to be the index into our full list of ids/specs that we're
       // looking at now.
       size_t i = attributes->specs - attributeSpecs;
       for ( ; attributeIds[i] != JSID_VOID; ++i) {
         if (id == attributeIds[i]) {
           const JSPropertySpec& attrSpec = attributeSpecs[i];
           // Because of centralization, we need to make sure we fault in the
           // JitInfos as well. At present, until the JSAPI changes, the easiest
           // way to do this is wrap them up as functions ourselves.
           desc->attrs = attrSpec.flags & ~JSPROP_NATIVE_ACCESSORS;
           // They all have getters, so we can just make it.
-          JSObject *global = JS_GetGlobalForObject(cx, wrapper);
-          JSFunction *fun = JS_NewFunction(cx, (JSNative)attrSpec.getter.op,
-                                           0, 0, global, nullptr);
+          JS::Rooted<JSObject*> global(cx, JS_GetGlobalForObject(cx, wrapper));
+          JS::Rooted<JSFunction*> fun(cx,
+                                      JS_NewFunction(cx, (JSNative)attrSpec.getter.op,
+                                                     0, 0, global, nullptr));
           if (!fun)
             return false;
           SET_JITINFO(fun, attrSpec.getter.info);
           JSObject *funobj = JS_GetFunctionObject(fun);
           desc->getter = js::CastAsJSPropertyOp(funobj);
           desc->attrs |= JSPROP_GETTER;
           if (attrSpec.setter.op) {
             // We have a setter! Make it.
@@ -812,17 +819,18 @@ XrayResolveAttribute(JSContext* cx, JSOb
         }
       }
     }
   }
   return true;
 }
 
 static bool
-XrayResolveProperty(JSContext* cx, JSObject* wrapper, JSObject* obj, jsid id,
+XrayResolveProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                    JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                     JSPropertyDescriptor* desc, DOMObjectType type,
                     const NativeProperties* nativeProperties)
 {
   const Prefable<const JSFunctionSpec>* methods;
   jsid* methodIds;
   const JSFunctionSpec* methodsSpecs;
   if (type == eInterface) {
     methods = nativeProperties->staticMethods;
@@ -919,21 +927,22 @@ XrayResolveProperty(JSContext* cx, JSObj
       }
     }
   }
 
   return true;
 }
 
 static bool
-ResolvePrototypeOrConstructor(JSContext* cx, JSObject* wrapper, JSObject* obj,
+ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                              JS::Handle<JSObject*> obj,
                               size_t protoAndIfaceArrayIndex, unsigned attrs,
                               JSPropertyDescriptor* desc)
 {
-  JSObject* global = js::GetGlobalForObjectCrossCompartment(obj);
+  JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
   {
     JSAutoCompartment ac(cx, global);
     JSObject** protoAndIfaceArray = GetProtoAndIfaceArray(global);
     JSObject* protoOrIface = protoAndIfaceArray[protoAndIfaceArrayIndex];
     if (!protoOrIface) {
       return false;
     }
     desc->obj = wrapper;
@@ -942,19 +951,20 @@ ResolvePrototypeOrConstructor(JSContext*
     desc->getter = JS_PropertyStub;
     desc->setter = JS_StrictPropertyStub;
     desc->value = JS::ObjectValue(*protoOrIface);
   }
   return JS_WrapPropertyDescriptor(cx, desc);
 }
 
 bool
-XrayResolveNativeProperty(JSContext* cx, JSObject* wrapper,
+XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                           const NativePropertyHooks* nativePropertyHooks,
-                          DOMObjectType type, JSObject* obj, jsid id,
+                          DOMObjectType type, JS::Handle<JSObject*> obj,
+                          JS::Handle<jsid> id,
                           JSPropertyDescriptor* desc)
 {
   if (type == eInterface && IdEquals(id, "prototype")) {
     return nativePropertyHooks->mPrototypeID == prototypes::id::_ID_Count ||
            ResolvePrototypeOrConstructor(cx, wrapper, obj,
                                          nativePropertyHooks->mPrototypeID,
                                          JSPROP_PERMANENT | JSPROP_READONLY,
                                          desc);
@@ -983,18 +993,19 @@ XrayResolveNativeProperty(JSContext* cx,
                            nativeProperties.chromeOnly)) {
     return false;
   }
 
   return true;
 }
 
 bool
-XrayResolveNativeProperty(JSContext* cx, JSObject* wrapper, JSObject* obj,
-                          jsid id, JSPropertyDescriptor* desc)
+XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                          JS::Handle<JSObject*> obj,
+                          JS::Handle<jsid> id, JSPropertyDescriptor* desc)
 {
   DOMObjectType type;
   const NativePropertyHooks* nativePropertyHooks =
     GetNativePropertyHooks(cx, obj, type);
 
   if (type == eInstance) {
     // Force the type to be eInterfacePrototype, since we need to walk the
     // prototype chain.
@@ -1016,17 +1027,18 @@ XrayResolveNativeProperty(JSContext* cx,
     return true;
   }
 
   return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type, obj,
                                    id, desc);
 }
 
 bool
-XrayEnumerateAttributes(JSContext* cx, JSObject* wrapper, JSObject* obj,
+XrayEnumerateAttributes(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                        JS::Handle<JSObject*> obj,
                         const Prefable<const JSPropertySpec>* attributes,
                         jsid* attributeIds, const JSPropertySpec* attributeSpecs,
                         unsigned flags, JS::AutoIdVector& props)
 {
   for (; attributes->specs; ++attributes) {
     if (attributes->isEnabled(cx, obj)) {
       // Set i to be the index into our full list of ids/specs that we're
       // looking at now.
@@ -1039,17 +1051,18 @@ XrayEnumerateAttributes(JSContext* cx, J
         }
       }
     }
   }
   return true;
 }
 
 bool
-XrayEnumerateProperties(JSContext* cx, JSObject* wrapper, JSObject* obj,
+XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                        JS::Handle<JSObject*> obj,
                         unsigned flags, JS::AutoIdVector& props,
                         DOMObjectType type,
                         const NativeProperties* nativeProperties)
 {
   const Prefable<const JSFunctionSpec>* methods;
   jsid* methodIds;
   const JSFunctionSpec* methodsSpecs;
   if (type == eInterface) {
@@ -1122,19 +1135,19 @@ XrayEnumerateProperties(JSContext* cx, J
       }
     }
   }
 
   return true;
 }
 
 bool
-XrayEnumerateNativeProperties(JSContext* cx, JSObject* wrapper,
+XrayEnumerateNativeProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
                               const NativePropertyHooks* nativePropertyHooks,
-                              DOMObjectType type, JSObject* obj,
+                              DOMObjectType type, JS::Handle<JSObject*> obj,
                               unsigned flags, JS::AutoIdVector& props)
 {
   if (type == eInterface &&
       nativePropertyHooks->mPrototypeID != prototypes::id::_ID_Count &&
       !AddStringToIDVector(cx, props, "prototype")) {
     return false;
   }
 
@@ -1160,17 +1173,18 @@ XrayEnumerateNativeProperties(JSContext*
                                nativeProperties.chromeOnly)) {
     return false;
   }
 
   return true;
 }
 
 bool
-XrayEnumerateProperties(JSContext* cx, JSObject* wrapper, JSObject* obj,
+XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                        JS::Handle<JSObject*> obj,
                         unsigned flags, JS::AutoIdVector& props)
 {
   DOMObjectType type;
   const NativePropertyHooks* nativePropertyHooks =
     GetNativePropertyHooks(cx, obj, type);
 
   if (type == eInstance) {
     if (nativePropertyHooks->mEnumerateOwnProperties &&
@@ -1215,21 +1229,22 @@ NativePropertyHooks sWorkerNativePropert
     nullptr
   },
   prototypes::id::_ID_Count,
   constructors::id::_ID_Count,
   nullptr
 };
 
 bool
-GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
+GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
+                       JS::Handle<jsid> id, bool* found,
                        JS::Value* vp)
 {
-  JSObject* proto;
-  if (!js::GetObjectProto(cx, proxy, &proto)) {
+  JS::Rooted<JSObject*> proto(cx);
+  if (!js::GetObjectProto(cx, proxy, proto.address())) {
     return false;
   }
   if (!proto) {
     *found = false;
     return true;
   }
 
   JSBool hasProp;
@@ -1241,29 +1256,31 @@ GetPropertyOnPrototype(JSContext* cx, JS
   if (!hasProp || !vp) {
     return true;
   }
 
   return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
 }
 
 bool
-HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler,
-                       jsid id)
+HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
+                       DOMProxyHandler* handler,
+                       JS::Handle<jsid> id)
 {
+  JS::Rooted<JSObject*> obj(cx, proxy);
   Maybe<JSAutoCompartment> ac;
-  if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
-    proxy = js::UncheckedUnwrap(proxy);
-    ac.construct(cx, proxy);
+  if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
+    obj = js::UncheckedUnwrap(obj);
+    ac.construct(cx, obj);
   }
-  MOZ_ASSERT(js::IsProxy(proxy) && js::GetProxyHandler(proxy) == handler);
+  MOZ_ASSERT(js::IsProxy(obj) && js::GetProxyHandler(obj) == handler);
 
   bool found;
   // We ignore an error from GetPropertyOnPrototype.
-  return !GetPropertyOnPrototype(cx, proxy, id, &found, NULL) || found;
+  return !GetPropertyOnPrototype(cx, obj, id, &found, NULL) || found;
 }
 
 JSObject*
 GetXrayExpandoChain(JSObject* obj)
 {
   js::Class* clasp = js::GetObjectClass(obj);
   JS::Value v;
   if (IsDOMClass(clasp) || IsDOMIfaceAndProtoClass(clasp)) {
@@ -1296,17 +1313,17 @@ SetXrayExpandoChain(JSObject* obj, JSObj
 
 JSContext*
 MainThreadDictionaryBase::ParseJSON(const nsAString& aJSON,
                                     Maybe<JSAutoRequest>& aAr,
                                     Maybe<JSAutoCompartment>& aAc,
                                     Maybe< JS::Rooted<JS::Value> >& aVal)
 {
   SafeAutoJSContext cx;
-  JSObject* global = JS_GetGlobalObject(cx);
+  JS::Rooted<JSObject*> global(cx, JS_GetGlobalObject(cx));
   aAr.construct(static_cast<JSContext*>(cx));
   aAc.construct(static_cast<JSContext*>(cx), global);
   aVal.construct(static_cast<JSContext*>(cx), JS::UndefinedValue());
   if (aJSON.IsEmpty()) {
     return cx;
   }
   if (!JS_ParseJSON(cx,
                     static_cast<const jschar*>(PromiseFlatString(aJSON).get()),
@@ -1318,61 +1335,61 @@ MainThreadDictionaryBase::ParseJSON(cons
 
 static JSString*
 ConcatJSString(JSContext* cx, const char* pre, JSString* str, const char* post)
 {
   if (!str) {
     return nullptr;
   }
 
-  JSString* preString = JS_NewStringCopyN(cx, pre, strlen(pre));
-  JSString* postString = JS_NewStringCopyN(cx, post, strlen(post));
+  JS::Rooted<JSString*> preString(cx, JS_NewStringCopyN(cx, pre, strlen(pre)));
+  JS::Rooted<JSString*> postString(cx, JS_NewStringCopyN(cx, post, strlen(post)));
   if (!preString || !postString) {
     return nullptr;
   }
 
   str = JS_ConcatStrings(cx, preString, str);
   if (!str) {
     return nullptr;
   }
 
   return JS_ConcatStrings(cx, str, postString);
 }
 
 bool
-NativeToString(JSContext* cx, JSObject* wrapper, JSObject* object, const char* pre,
+NativeToString(JSContext* cx, JS::Handle<JSObject*> wrapper,
+               JS::Handle<JSObject*> obj, const char* pre,
                const char* post, JS::Value* v)
 {
-  JS::Rooted<JSObject*> obj(cx, object);
-
-  JSPropertyDescriptor toStringDesc;
-  toStringDesc.obj = nullptr;
-  toStringDesc.attrs = 0;
-  toStringDesc.shortid = 0;
-  toStringDesc.getter = nullptr;
-  toStringDesc.setter = nullptr;
-  toStringDesc.value = JS::UndefinedValue();
-  if (!XrayResolveNativeProperty(cx, wrapper, obj,
-                                 nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING),
-                                 &toStringDesc)) {
+  JS::Rooted<JSPropertyDescriptor> toStringDesc(cx);
+  toStringDesc.object().set(nullptr);
+  toStringDesc.setAttributes(0);
+  toStringDesc.setShortId(0);
+  toStringDesc.setGetter(nullptr);
+  toStringDesc.setSetter(nullptr);
+  toStringDesc.value().set(JS::UndefinedValue());
+  JS::Rooted<jsid> id(cx,
+    nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING));
+  if (!XrayResolveNativeProperty(cx, wrapper, obj, id,
+                                 toStringDesc.address())) {
     return false;
   }
 
-  JSString* str;
+  JS::Rooted<JSString*> str(cx);
   {
     JSAutoCompartment ac(cx, obj);
-    if (toStringDesc.obj) {
-      JS::Value toString = toStringDesc.value;
-      if (!JS_WrapValue(cx, &toString)) {
+    if (toStringDesc.object()) {
+      JS::Rooted<JS::Value> toString(cx, toStringDesc.value());
+      if (!JS_WrapValue(cx, toString.address())) {
         return false;
       }
       MOZ_ASSERT(JS_ObjectIsCallable(cx, &toString.toObject()));
-      JS::Value toStringResult;
+      JS::Rooted<JS::Value> toStringResult(cx);
       if (JS_CallFunctionValue(cx, obj, toString, 0, nullptr,
-                               &toStringResult)) {
+                               toStringResult.address())) {
         str = toStringResult.toString();
       } else {
         str = nullptr;
       }
     } else {
       if (IsDOMProxy(obj)) {
         str = JS_BasicObjectToString(cx, obj);
       } else {
@@ -1400,45 +1417,45 @@ NativeToString(JSContext* cx, JSObject* 
   v->setString(str);
   return JS_WrapValue(cx, v);
 }
 
 // Dynamically ensure that two objects don't end up with the same reserved slot.
 class MOZ_STACK_CLASS AutoCloneDOMObjectSlotGuard
 {
 public:
-  AutoCloneDOMObjectSlotGuard(JSObject* aOld, JSObject* aNew)
-    : mOldReflector(aOld), mNewReflector(aNew)
+  AutoCloneDOMObjectSlotGuard(JSContext* aCx, JSObject* aOld, JSObject* aNew)
+    : mOldReflector(aCx, aOld), mNewReflector(aCx, aNew)
   {
     MOZ_ASSERT(js::GetReservedSlot(aOld, DOM_OBJECT_SLOT) ==
                  js::GetReservedSlot(aNew, DOM_OBJECT_SLOT));
   }
 
   ~AutoCloneDOMObjectSlotGuard()
   {
     if (js::GetReservedSlot(mOldReflector, DOM_OBJECT_SLOT).toPrivate()) {
       js::SetReservedSlot(mNewReflector, DOM_OBJECT_SLOT,
                           JS::PrivateValue(nullptr));
     }
   }
 
 private:
-  JSObject* mOldReflector;
-  JSObject* mNewReflector;
+  JS::Rooted<JSObject*> mOldReflector;
+  JS::Rooted<JSObject*> mNewReflector;
 };
 
 nsresult
 ReparentWrapper(JSContext* aCx, JS::HandleObject aObjArg)
 {
   // aObj is assigned to below, so needs to be re-rooted.
   JS::RootedObject aObj(aCx, aObjArg);
   const DOMClass* domClass = GetDOMClass(aObj);
 
-  JSObject* oldParent = JS_GetParent(aObj);
-  JSObject* newParent = domClass->mGetParent(aCx, aObj);
+  JS::Rooted<JSObject*> oldParent(aCx, JS_GetParent(aObj));
+  JS::Rooted<JSObject*> newParent(aCx, domClass->mGetParent(aCx, aObj));
 
   JSAutoCompartment oldAc(aCx, oldParent);
 
   if (js::GetObjectCompartment(oldParent) ==
       js::GetObjectCompartment(newParent)) {
     if (!JS_SetParent(aCx, aObj, newParent)) {
       MOZ_CRASH();
     }
@@ -1448,23 +1465,24 @@ ReparentWrapper(JSContext* aCx, JS::Hand
   nsISupports* native;
   if (!UnwrapDOMObjectToISupports(aObj, native)) {
     return NS_OK;
   }
 
   // Before proceeding, eagerly create any same-compartment security wrappers
   // that the object might have. This forces us to take the 'WithWrapper' path
   // while transplanting that handles this stuff correctly.
-  JSObject* ww = xpc::WrapperFactory::WrapForSameCompartment(aCx, aObj);
+  JS::Rooted<JSObject*> ww(aCx,
+                           xpc::WrapperFactory::WrapForSameCompartment(aCx, aObj));
   if (!ww) {
     return NS_ERROR_FAILURE;
   }
 
   bool isProxy = js::IsProxy(aObj);
-  JSObject* expandoObject;
+  JS::Rooted<JSObject*> expandoObject(aCx);
   if (isProxy) {
     expandoObject = DOMProxyHandler::GetAndClearExpandoObject(aObj);
   }
 
   JSAutoCompartment newAc(aCx, newParent);
 
   // First we clone the reflector. We get a copy of its properties and clone its
   // expando chain. The only part that is dangerous here is that if we have to
@@ -1473,35 +1491,35 @@ ReparentWrapper(JSContext* aCx, JS::Hand
 
   JS::Rooted<JSObject*> global(aCx,
                                js::GetGlobalForObjectCrossCompartment(newParent));
   JS::Handle<JSObject*> proto = (domClass->mGetProto)(aCx, global);
   if (!proto) {
     return NS_ERROR_FAILURE;
   }
 
-  JSObject *newobj = JS_CloneObject(aCx, aObj, proto, newParent);
+  JS::Rooted<JSObject*> newobj(aCx, JS_CloneObject(aCx, aObj, proto, newParent));
   if (!newobj) {
     return NS_ERROR_FAILURE;
   }
 
   js::SetReservedSlot(newobj, DOM_OBJECT_SLOT,
                       js::GetReservedSlot(aObj, DOM_OBJECT_SLOT));
 
   // At this point, both |aObj| and |newobj| point to the same native
   // which is bad, because one of them will end up being finalized with a
   // native it does not own. |cloneGuard| ensures that if we exit before
   // clearing |aObj|'s reserved slot the reserved slot of |newobj| will be
   // set to null. |aObj| will go away soon, because we swap it with
   // another object during the transplant and let that object die.
-  JSObject* propertyHolder;
+  JS::Rooted<JSObject*> propertyHolder(aCx);
   {
-    AutoCloneDOMObjectSlotGuard cloneGuard(aObj, newobj);
+    AutoCloneDOMObjectSlotGuard cloneGuard(aCx, aObj, newobj);
 
-    JSObject* copyFrom = isProxy ? expandoObject : aObj;
+    JS::Rooted<JSObject*> copyFrom(aCx, isProxy ? expandoObject : aObj);
     if (copyFrom) {
       propertyHolder = JS_NewObjectWithGivenProto(aCx, nullptr, nullptr,
                                                   newParent);
       if (!propertyHolder) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       if (!JS_CopyPropertiesFrom(aCx, propertyHolder, copyFrom)) {
@@ -1597,26 +1615,27 @@ ReparentWrapper(JSContext* aCx, JS::Hand
   return NS_OK;
 }
 
 template<bool mainThread>
 inline JSObject*
 GetGlobalObject(JSContext* aCx, JSObject* aObject,
                 Maybe<JSAutoCompartment>& aAutoCompartment)
 {
-  if (js::IsWrapper(aObject)) {
-    aObject = js::CheckedUnwrap(aObject, /* stopAtOuter = */ false);
-    if (!aObject) {
+  JS::Rooted<JSObject*> obj(aCx, aObject);
+  if (js::IsWrapper(obj)) {
+    obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
+    if (!obj) {
       Throw<mainThread>(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
       return nullptr;
     }
-    aAutoCompartment.construct(aCx, aObject);
+    aAutoCompartment.construct(aCx, obj);
   }
 
-  return JS_GetGlobalForObject(aCx, aObject);
+  return JS_GetGlobalForObject(aCx, obj);
 }
 
 GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject)
   : mGlobalJSObject(aCx)
 {
   Maybe<JSAutoCompartment> ac;
   mGlobalJSObject = GetGlobalObject<true>(aCx, aObject, ac);
   if (!mGlobalJSObject) {
@@ -1641,17 +1660,18 @@ WorkerGlobalObject::WorkerGlobalObject(J
   : mGlobalJSObject(aCx),
     mCx(aCx)
 {
   Maybe<JSAutoCompartment> ac;
   mGlobalJSObject = GetGlobalObject<false>(aCx, aObject, ac);
 }
 
 JSBool
-InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSObject* instance,
+InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
+                     JS::Handle<JSObject*> instance,
                      JSBool* bp)
 {
   const DOMIfaceAndProtoJSClass* clasp =
     DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
 
   const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
 
   MOZ_ASSERT(!domClass || clasp->mPrototypeID != prototypes::id::_ID_Count,
@@ -1659,36 +1679,36 @@ InterfaceHasInstance(JSContext* cx, JSHa
              "ID?");
 
   if (domClass &&
       domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
     *bp = true;
     return true;
   }
 
-  jsval protov;
-  DebugOnly<bool> ok = JS_GetProperty(cx, obj, "prototype", &protov);
+  JS::Rooted<JS::Value> protov(cx);
+  DebugOnly<bool> ok = JS_GetProperty(cx, obj, "prototype", protov.address());
   MOZ_ASSERT(ok, "Someone messed with our prototype property?");
 
-  JSObject *interfacePrototype = &protov.toObject();
+  JS::Rooted<JSObject*> interfacePrototype(cx, &protov.toObject());
   MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(interfacePrototype)),
              "Someone messed with our prototype property?");
 
-  JSObject* proto;
-  if (!JS_GetPrototype(cx, instance, &proto)) {
+  JS::Rooted<JSObject*> proto(cx);
+  if (!JS_GetPrototype(cx, instance, proto.address())) {
     return false;
   }
 
   while (proto) {
     if (proto == interfacePrototype) {
       *bp = true;
       return true;
     }
 
-    if (!JS_GetPrototype(cx, proto, &proto)) {
+    if (!JS_GetPrototype(cx, proto, proto.address())) {
       return false;
     }
   }
 
   *bp = false;
   return true;
 }
 
@@ -1696,17 +1716,18 @@ JSBool
 InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue vp,
                      JSBool* bp)
 {
   if (!vp.isObject()) {
     *bp = false;
     return true;
   }
 
-  return InterfaceHasInstance(cx, obj, &vp.toObject(), bp);
+  JS::Rooted<JSObject*> instanceObject(cx, &vp.toObject());
+  return InterfaceHasInstance(cx, obj, instanceObject, bp);
 }
 
 void
 ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle<JSObject*> obj)
 {
   GlobalObject global(cx, obj);
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.Get());
   if (window && window->GetDoc()) {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -342,21 +342,23 @@ CreateInterfaceObjects(JSContext* cx, JS
                        const NativeProperties* regularProperties,
                        const NativeProperties* chromeOnlyProperties,
                        const char* name);
 
 /*
  * Define the unforgeable attributes on an object.
  */
 bool
-DefineUnforgeableAttributes(JSContext* cx, JSObject* obj,
+DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
                             const Prefable<const JSPropertySpec>* props);
 
 bool
-DefineWebIDLBindingPropertiesOnXPCProto(JSContext* cx, JSObject* proto, const NativeProperties* properties);
+DefineWebIDLBindingPropertiesOnXPCProto(JSContext* cx,
+                                        JS::Handle<JSObject*> proto,
+                                        const NativeProperties* properties);
 
 #ifdef _MSC_VER
 #define HAS_MEMBER_CHECK(_name)                                           \
   template<typename V> static yes& Check(char (*)[(&V::_name == 0) + 1])
 #else
 #define HAS_MEMBER_CHECK(_name)                                           \
   template<typename V> static yes& Check(char (*)[sizeof(&V::_name) + 1])
 #endif
@@ -1298,22 +1300,24 @@ InitIds(JSContext* cx, const Prefable<Sp
 }
 
 JSBool
 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
 JSBool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool
-GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
+GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
+                       JS::Handle<jsid> id, bool* found,
                        JS::Value* vp);
 
 bool
-HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler,
-                       jsid id);
+HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
+                       DOMProxyHandler* handler,
+                       JS::Handle<jsid> id);
 
 template<class T>
 class NonNull
 {
 public:
   NonNull()
 #ifdef DEBUG
     : inited(false)
@@ -1601,41 +1605,45 @@ AddStringToIDVector(JSContext* cx, JS::A
 /**
  * This resolves indexed or named properties of obj.
  *
  * wrapper is the Xray JS object.
  * obj is the target object of the Xray, a binding's instance object or a
  *     interface or interface prototype object.
  */
 bool
-XrayResolveOwnProperty(JSContext* cx, JSObject* wrapper, JSObject* obj,
-                       jsid id, JSPropertyDescriptor* desc, unsigned flags);
+XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                       JS::Handle<JSObject*> obj,
+                       JS::Handle<jsid> id,
+                       JSPropertyDescriptor* desc, unsigned flags);
 
 /**
  * This resolves operations, attributes and constants of the interfaces for obj.
  *
  * wrapper is the Xray JS object.
  * obj is the target object of the Xray, a binding's instance object or a
  *     interface or interface prototype object.
  */
 bool
-XrayResolveNativeProperty(JSContext* cx, JSObject* wrapper, JSObject* obj,
-                          jsid id, JSPropertyDescriptor* desc);
+XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                          JS::Handle<JSObject*> obj,
+                          JS::Handle<jsid> id, JSPropertyDescriptor* desc);
 
 /**
  * This enumerates indexed or named properties of obj and operations, attributes
  * and constants of the interfaces for obj.
  *
  * wrapper is the Xray JS object.
  * obj is the target object of the Xray, a binding's instance object or a
  *     interface or interface prototype object.
  * flags are JSITER_* flags.
  */
 bool
-XrayEnumerateProperties(JSContext* cx, JSObject* wrapper, JSObject* obj,
+XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                        JS::Handle<JSObject*> obj,
                         unsigned flags, JS::AutoIdVector& props);
 
 extern NativePropertyHooks sWorkerNativePropertyHooks;
 
 // We use one constructor JSNative to represent all DOM interface objects (so
 // we can easily detect when we need to wrap them in an Xray wrapper). We store
 // the real JSNative in the mNative member of a JSNativeHolder in the
 // CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
@@ -1708,17 +1716,18 @@ void SetXrayExpandoChain(JSObject *obj, 
  * wrapper is the Xray JS object.
  * obj is the target object of the Xray, a binding's instance object or a
  *     interface or interface prototype object.
  * pre is a string that should be prefixed to the value.
  * post is a string that should be prefixed to the value.
  * v contains the JSString for the value if the function returns true.
  */
 bool
-NativeToString(JSContext* cx, JSObject* wrapper, JSObject* obj, const char* pre,
+NativeToString(JSContext* cx, JS::Handle<JSObject*> wrapper,
+               JS::Handle<JSObject*> obj, const char* pre,
                const char* post, JS::Value* v);
 
 HAS_MEMBER(JSBindingFinalized)
 
 template<class T, bool hasCallback=HasJSBindingFinalizedMember<T>::Value>
 struct JSBindingFinalized
 {
   static void Finalized(T* self)
@@ -1748,17 +1757,18 @@ nsresult
 ReparentWrapper(JSContext* aCx, JS::HandleObject aObj);
 
 /**
  * Used to implement the hasInstance hook of an interface object.
  *
  * instance should not be a security wrapper.
  */
 JSBool
-InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSObject* instance,
+InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
+                     JS::Handle<JSObject*> instance,
                      JSBool* bp);
 JSBool
 InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue vp,
                      JSBool* bp);
 
 // Helper for lenient getters/setters to report to console
 void
 ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle<JSObject*> obj);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1751,17 +1751,18 @@ class CGCreateInterfaceObjectsMethod(CGA
                                   pre=("static bool sPrefCachesInited = false;\n"
                                        "if (!sPrefCachesInited) {\n"
                                        "  sPrefCachesInited = true;\n"),
                                   post="\n}")
         else:
             prefCache = None
             
         if UseHolderForUnforgeable(self.descriptor):
-            createUnforgeableHolder = CGGeneric("""JSObject* unforgeableHolder = JS_NewObjectWithGivenProto(aCx, nullptr, nullptr, nullptr);
+            createUnforgeableHolder = CGGeneric("""JS::Rooted<JSObject*> unforgeableHolder(aCx,
+  JS_NewObjectWithGivenProto(aCx, nullptr, nullptr, nullptr));
 if (!unforgeableHolder) {
   return;
 }""")
             defineUnforgeables = InitUnforgeablePropertiesOnObject(self.descriptor,
                                                                    "unforgeableHolder",
                                                                    self.properties)
             createUnforgeableHolder = CGList([createUnforgeableHolder,
                                               defineUnforgeables],
@@ -1983,33 +1984,44 @@ class CGIsMethod(CGAbstractMethod):
         args = [Argument('JSObject*', 'obj')]
         CGAbstractMethod.__init__(self, descriptor, 'Is', 'bool', args)
 
     def definition_body(self):
         # Non-proxy implementation would check
         #   js::GetObjectJSClass(obj) == &Class.mBase
         return """  return IsProxy(obj);"""
 
-def CreateBindingJSObject(descriptor, parent):
+def CreateBindingJSObject(descriptor, properties, parent):
+    # When we have unforgeable properties, we're going to define them
+    # on our object, so we have to root it when we create it, so it
+    # won't suddenly die while defining the unforgeables.
+    needRoot = (properties.unforgeableAttrs.hasNonChromeOnly() or
+                properties.unforgeableAttrs.hasChromeOnly())
+    if needRoot:
+        objDecl = "  JS::Rooted<JSObject*> obj(aCx);\n"
+    else:
+        objDecl = "  JSObject *obj;\n"
     if descriptor.proxy:
-        create = """  JSObject *obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(),
-                                 JS::PrivateValue(aObject), proto, %s);
+        create = """  obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(),
+                       JS::PrivateValue(aObject), proto, %s);
   if (!obj) {
     return NULL;
   }
 
 """
     else:
-        create = """  JSObject* obj = JS_NewObject(aCx, &Class.mBase, proto, %s);
+        create = """  obj = JS_NewObject(aCx, &Class.mBase, proto, %s);
   if (!obj) {
     return NULL;
   }
 
   js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
 """
+    create = objDecl + create
+
     if descriptor.nativeOwnership in ['refcounted', 'nsisupports']:
         create += """  NS_ADDREF(aObject);
 """
     else:
         assert descriptor.nativeOwnership == 'owned'
         create += """  // Make sure the native objects inherit from NonRefcountedDOMObject so that we
   // log their ctor and dtor.
   MustInheritFromNonRefcountedDOMObject(aObject);
@@ -2144,17 +2156,18 @@ class CGWrapWithCacheMethod(CGAbstractMe
   }
 
 %s
 %s
   aCache->SetWrapper(obj);
 
   return obj;""" % (AssertInheritanceChain(self.descriptor),
                     assertISupportsInheritance,
-                    CreateBindingJSObject(self.descriptor, "parent"),
+                    CreateBindingJSObject(self.descriptor, self.properties,
+                                          "parent"),
                     InitUnforgeableProperties(self.descriptor, self.properties))
 
 class CGWrapMethod(CGAbstractMethod):
     def __init__(self, descriptor):
         # XXX can we wrap if we don't have an interface prototype object?
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'),
                 Argument('JS::Handle<JSObject*>', 'aScope'),
@@ -2188,17 +2201,18 @@ class CGWrapNonWrapperCacheMethod(CGAbst
   JS::Handle<JSObject*> proto = GetProtoObject(aCx, global);
   if (!proto) {
     return NULL;
   }
 
 %s
 %s
   return obj;""" % (AssertInheritanceChain(self.descriptor),
-                    CreateBindingJSObject(self.descriptor, "global"),
+                    CreateBindingJSObject(self.descriptor, self.properties,
+                                          "global"),
                     InitUnforgeableProperties(self.descriptor, self.properties))
 
 builtinNames = {
     IDLType.Tags.bool: 'bool',
     IDLType.Tags.int8: 'int8_t',
     IDLType.Tags.int16: 'int16_t',
     IDLType.Tags.int32: 'int32_t',
     IDLType.Tags.int64: 'int64_t',
@@ -6207,39 +6221,39 @@ class CGClass(CGThing):
         for (memberList, separator) in order:
             (memberString, itemCount) = defineMembers(self, memberList,
                                                       itemCount, separator)
             result = result + memberString
         return result
 
 class CGResolveOwnProperty(CGAbstractMethod):
     def __init__(self, descriptor):
-        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper_'),
-                Argument('JSObject*', 'obj'), Argument('jsid', 'id_'),
+        args = [Argument('JSContext*', 'cx'),
+                Argument('JS::Handle<JSObject*>', 'wrapper'),
+                Argument('JS::Handle<JSObject*>', 'obj'),
+                Argument('JS::Handle<jsid>', 'id'),
                 Argument('JSPropertyDescriptor*', 'desc'), Argument('unsigned', 'flags'),
                 ]
         CGAbstractMethod.__init__(self, descriptor, "ResolveOwnProperty", "bool", args)
     def definition_body(self):
         return """  // We rely on getOwnPropertyDescriptor not shadowing prototype properties by named
   // properties. If that changes we'll need to filter here.
-  js::RootedObject wrapper(cx, wrapper_);
-  js::RootedId id(cx, id_);
   return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc, flags);
 """
 
 class CGEnumerateOwnProperties(CGAbstractMethod):
     def __init__(self, descriptor):
-        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper_'),
-                Argument('JSObject*', 'obj'),
+        args = [Argument('JSContext*', 'cx'),
+                Argument('JS::Handle<JSObject*>', 'wrapper'),
+                Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::AutoIdVector&', 'props')]
         CGAbstractMethod.__init__(self, descriptor, "EnumerateOwnProperties", "bool", args)
     def definition_body(self):
         return """  // We rely on getOwnPropertyNames not shadowing prototype properties by named
   // properties. If that changes we'll need to filter here.
-  JS::Rooted<JSObject*> wrapper(cx, wrapper_);
   return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);
 """
 
 class CGPrototypeTraitsClass(CGClass):
     def __init__(self, descriptor, indent=''):
         templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
         templateSpecialization = ['prototypes::id::' + descriptor.name]
         enums = [ClassEnum('', ['Depth'],
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -53,21 +53,23 @@ class nsCycleCollectionParticipant;
 MOZ_STATIC_ASSERT(DOM_PROTO_INSTANCE_CLASS_SLOT != DOM_XRAY_EXPANDO_SLOT,
                   "Interface prototype object use both of these, so they must "
                   "not be the same slot.");
 
 namespace mozilla {
 namespace dom {
 
 typedef bool
-(* ResolveOwnProperty)(JSContext* cx, JSObject* wrapper, JSObject* obj, jsid id,
+(* ResolveOwnProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                       JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                        JSPropertyDescriptor* desc, unsigned flags);
 
 typedef bool
-(* EnumerateOwnProperties)(JSContext* cx, JSObject* wrapper, JSObject* obj,
+(* EnumerateOwnProperties)(JSContext* cx, JS::Handle<JSObject*> wrapper,
+                           JS::Handle<JSObject*> obj,
                            JS::AutoIdVector& props);
 
 struct ConstantSpec
 {
   const char* name;
   JS::Value value;
 };
 
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -201,28 +201,29 @@ DOMProxyHandler::has(JSContext* cx, JS::
   bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
   if (ok) {
     *bp = protoHasProp;
   }
   return ok;
 }
 
 bool
-DOMProxyHandler::AppendNamedPropertyIds(JSContext* cx, JSObject* proxy,
+DOMProxyHandler::AppendNamedPropertyIds(JSContext* cx,
+                                        JS::Handle<JSObject*> proxy,
                                         nsTArray<nsString>& names,
                                         JS::AutoIdVector& props)
 {
   for (uint32_t i = 0; i < names.Length(); ++i) {
     JS::Value v;
     if (!xpc::NonVoidStringToJsval(cx, names[i], &v)) {
       return false;
     }
 
-    jsid id;
-    if (!JS_ValueToId(cx, v, &id)) {
+    JS::Rooted<jsid> id(cx);
+    if (!JS_ValueToId(cx, v, id.address())) {
       return false;
     }
 
     if (!HasPropertyOnPrototype(cx, proxy, this, id)) {
       if (!props.append(id)) {
         return false;
       }
     }
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -56,17 +56,17 @@ public:
   static JSObject* GetAndClearExpandoObject(JSObject* obj);
   static JSObject* EnsureExpandoObject(JSContext* cx, JSObject* obj);
 
   const DOMClass& mClass;
 
 protected:
   // Append the property names in "names" that don't live on our proto
   // chain to "props"
-  bool AppendNamedPropertyIds(JSContext* cx, JSObject* proxy,
+  bool AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
                               nsTArray<nsString>& names,
                               JS::AutoIdVector& props);
 };
 
 extern jsid s_length_id;
 
 int32_t IdToInt32(JSContext* cx, jsid id);
 
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1236,18 +1236,18 @@ DOMXrayTraits::defineProperty(JSContext 
     *defined = true;
     return js::GetProxyHandler(obj)->defineProperty(cx, wrapper, id, desc);
 }
 
 bool
 DOMXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags,
                               AutoIdVector &props)
 {
-    return XrayEnumerateProperties(cx, wrapper, getTargetObject(wrapper),
-                                   flags, props);
+    JS::Rooted<JSObject*> obj(cx, getTargetObject(wrapper));
+    return XrayEnumerateProperties(cx, wrapper, obj, flags, props);
 }
 
 bool
 DOMXrayTraits::call(JSContext *cx, HandleObject wrapper,
                     const JS::CallArgs &args, js::Wrapper& baseInstance)
 {
     RootedObject obj(cx, getTargetObject(wrapper));
     js::Class* clasp = js::GetObjectClass(obj);