Bug 866450 Part 1: Fix rooting hazards under content/ and dom/ r=bz
authorDavid Zbarsky <dzbarsky@gmail.com>
Thu, 02 May 2013 05:12:45 -0400
changeset 130664 27f8c1c2e09e9e0bb77c59fcf211efbb9df037cf
parent 130663 b036d96c4c87c6c2c718c336431ea258594f4dd3
child 130665 173a6deb4792d76e315e649bd7db1f9ce24a55f5
push id1579
push userphilringnalda@gmail.com
push dateSat, 04 May 2013 04:38:04 +0000
treeherderfx-team@a56432a42a41 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs866450
milestone23.0a1
Bug 866450 Part 1: Fix rooting hazards under content/ and dom/ r=bz
content/base/src/nsContentList.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsObjectLoadingContent.cpp
content/base/src/nsObjectLoadingContent.h
content/base/src/nsXMLHttpRequest.cpp
content/canvas/src/CanvasRenderingContext2D.cpp
content/canvas/src/CanvasUtils.h
content/events/src/nsDOMMessageEvent.cpp
content/events/src/nsDOMMessageEvent.h
content/html/content/src/HTMLMediaElement.cpp
content/html/content/src/HTMLObjectElement.cpp
content/html/content/src/HTMLSharedObjectElement.cpp
content/html/content/src/HTMLUnknownElement.cpp
content/svg/document/src/SVGDocument.cpp
content/xbl/src/nsXBLProtoImpl.cpp
content/xml/document/src/XMLDocument.cpp
content/xul/document/src/XULDocument.cpp
content/xul/document/src/nsXULPrototypeDocument.cpp
content/xul/templates/src/nsXULTemplateBuilder.cpp
dom/bindings/BindingUtils.h
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -527,17 +527,17 @@ nsContentList::Item(uint32_t aIndex, boo
 
   return mElements.SafeElementAt(aIndex);
 }
 
 nsIContent *
 nsContentList::NamedItem(const nsAString& aName, bool aDoFlush)
 {
   BringSelfUpToDate(aDoFlush);
-    
+
   uint32_t i, count = mElements.Length();
 
   // Typically IDs and names are atomized
   nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
   NS_ENSURE_TRUE(name, nullptr);
 
   for (i = 0; i < count; i++) {
     nsIContent *content = mElements[i];
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -651,17 +651,18 @@ nsFrameMessageManager::ReceiveMessage(ns
         }
         nsCxPusher pusher;
         pusher.Push(ctx);
 
         JSAutoRequest ar(ctx);
         JSAutoCompartment ac(ctx, object);
 
         // The parameter for the listener function.
-        JSObject* param = JS_NewObject(ctx, nullptr, nullptr, nullptr);
+        JS::Rooted<JSObject*> param(ctx,
+          JS_NewObject(ctx, nullptr, nullptr, nullptr));
         NS_ENSURE_TRUE(param, NS_ERROR_OUT_OF_MEMORY);
 
         JS::Value targetv;
         nsContentUtils::WrapNative(ctx,
                                    JS_GetGlobalForObject(ctx, object),
                                    aTarget, &targetv, nullptr, true);
 
         // To keep compatibility with e10s message manager,
@@ -694,50 +695,50 @@ nsFrameMessageManager::ReceiveMessage(ns
         JS_DefineProperty(ctx, param, "name",
                           STRING_TO_JSVAL(jsMessage), nullptr, nullptr, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "sync",
                           BOOLEAN_TO_JSVAL(aSync), nullptr, nullptr, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "json", json, nullptr, nullptr, JSPROP_ENUMERATE); // deprecated
         JS_DefineProperty(ctx, param, "data", json, nullptr, nullptr, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "objects", objectsv, nullptr, nullptr, JSPROP_ENUMERATE);
 
-        JS::Value thisValue = JSVAL_VOID;
+        JS::Rooted<JS::Value> thisValue(ctx, JSVAL_VOID);
 
         JS::Value funval;
         if (JS_ObjectIsCallable(ctx, object)) {
           // If the listener is a JS function:
           funval.setObject(*object);
 
           // A small hack to get 'this' value right on content side where
           // messageManager is wrapped in TabChildGlobal.
           nsCOMPtr<nsISupports> defaultThisValue;
           if (mChrome) {
             defaultThisValue = do_QueryObject(this);
           } else {
             defaultThisValue = aTarget;
           }
-          nsContentUtils::WrapNative(ctx,
-                                     JS_GetGlobalForObject(ctx, object),
-                                     defaultThisValue, &thisValue, nullptr, true);
+          nsContentUtils::WrapNative(ctx, JS_GetGlobalForObject(ctx, object),
+                                     defaultThisValue, thisValue.address(),
+                                     nullptr, true);
         } else {
           // If the listener is a JS object which has receiveMessage function:
           if (!JS_GetProperty(ctx, object, "receiveMessage", &funval) ||
               !funval.isObject())
             return NS_ERROR_UNEXPECTED;
 
           // Check if the object is even callable.
           NS_ENSURE_STATE(JS_ObjectIsCallable(ctx, &funval.toObject()));
           thisValue.setObject(*object);
         }
 
         JS::Rooted<JS::Value> rval(ctx, JSVAL_VOID);
         JS::Rooted<JS::Value> argv(ctx, JS::ObjectValue(*param));
 
         {
-          JSObject* thisObject = JSVAL_TO_OBJECT(thisValue);
+          JS::Rooted<JSObject*> thisObject(ctx, thisValue.toObjectOrNull());
 
           JSAutoCompartment tac(ctx, thisObject);
           if (!JS_WrapValue(ctx, argv.address()))
             return NS_ERROR_UNEXPECTED;
 
           JS_CallFunctionValue(ctx, thisObject,
                                funval, 1, argv.address(), rval.address());
           if (aJSONRetVal) {
@@ -1068,18 +1069,19 @@ nsFrameScriptExecutor::TryCacheLoadAndCo
       mGlobal->GetJSObject(&global);
       if (global) {
         JSAutoCompartment ac(mCx, global);
         JS::CompileOptions options(mCx);
         options.setNoScriptRval(true)
                .setFileAndLine(url.get(), 1)
                .setPrincipals(nsJSPrincipals::get(mPrincipal));
         JS::RootedObject empty(mCx, nullptr);
-        JSScript* script = JS::Compile(mCx, empty, options,
-                                       dataString.get(), dataString.Length());
+        JS::Rooted<JSScript*> script(mCx,
+          JS::Compile(mCx, empty, options, dataString.get(),
+                      dataString.Length()));
 
         if (script) {
           nsAutoCString scheme;
           uri->GetScheme(scheme);
           // We don't cache data: scripts!
           if (!scheme.EqualsLiteral("data")) {
             nsFrameJSScriptExecutorHolder* holder =
               new nsFrameJSScriptExecutorHolder(script);
@@ -1095,18 +1097,18 @@ nsFrameScriptExecutor::TryCacheLoadAndCo
     }
   }
 }
 
 bool
 nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope,
                                                   const nsACString& aID)
 {
-  
-  nsCOMPtr<nsIJSRuntimeService> runtimeSvc = 
+
+  nsCOMPtr<nsIJSRuntimeService> runtimeSvc =
     do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
   NS_ENSURE_TRUE(runtimeSvc, false);
 
   JSRuntime* rt = nullptr;
   runtimeSvc->GetRuntime(&rt);
   NS_ENSURE_TRUE(rt, false);
 
   JSContext* cx = JS_NewContext(rt, 8192);
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -2646,17 +2646,17 @@ nsObjectLoadingContent::NotifyContentObj
   nsIScriptContext *scx = sgo->GetContext();
   if (!scx)
     return;
 
   JSContext *cx = scx->GetNativeContext();
   nsCxPusher pusher;
   pusher.Push(cx);
 
-  JSObject *obj = thisContent->GetWrapper();
+  JS::Rooted<JSObject*> obj(cx, thisContent->GetWrapper());
   if (!obj) {
     // Nothing to do here if there's no wrapper for mContent. The proto
     // chain will be fixed appropriately when the wrapper is created.
     return;
   }
 
   SetupProtoChain(cx, obj);
 }
@@ -2844,24 +2844,24 @@ nsObjectLoadingContent::GetContentDocume
 JS::Value
 nsObjectLoadingContent::LegacyCall(JSContext* aCx,
                                    JS::Value aThisVal,
                                    const Sequence<JS::Value>& aArguments,
                                    ErrorResult& aRv)
 {
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
-  JSObject* obj = thisContent->GetWrapper();
+  JS::Rooted<JSObject*> obj(aCx, thisContent->GetWrapper());
   MOZ_ASSERT(obj, "How did we get called?");
 
   // Make sure we're not dealing with an Xray.  Our DoCall code can't handle
   // random cross-compartment wrappers, so we're going to have to wrap
   // everything up into our compartment, but that means we need to check that
   // this is not an Xray situation by hand.
-  if (!JS_WrapObject(aCx, &obj)) {
+  if (!JS_WrapObject(aCx, obj.address())) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return JS::UndefinedValue();
   }
 
   if (nsDOMClassInfo::ObjectIsNativeWrapper(aCx, obj)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return JS::UndefinedValue();
   }
@@ -2919,17 +2919,18 @@ nsObjectLoadingContent::LegacyCall(JSCon
     return JS::UndefinedValue();
   }
 
   Telemetry::Accumulate(Telemetry::PLUGIN_CALLED_DIRECTLY, true);
   return retval;
 }
 
 void
-nsObjectLoadingContent::SetupProtoChain(JSContext* aCx, JSObject* aObject)
+nsObjectLoadingContent::SetupProtoChain(JSContext* aCx,
+                                        JS::Handle<JSObject*> aObject)
 {
   MOZ_ASSERT(nsCOMPtr<nsIContent>(do_QueryInterface(
     static_cast<nsIObjectLoadingContent*>(this)))->IsDOMBinding());
 
   if (mType != eType_Plugin) {
     return;
   }
 
@@ -3081,22 +3082,23 @@ void
 nsObjectLoadingContent::TeardownProtoChain()
 {
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
   // Use the safe JSContext here as we're not always able to find the
   // JSContext associated with the NPP any more.
   JSContext *cx = nsContentUtils::GetSafeJSContext();
-  JSObject *obj = thisContent->GetWrapper();
+  JS::Rooted<JSObject*> obj(cx, thisContent->GetWrapper());
   NS_ENSURE_TRUE(obj, /* void */);
 
+  JSAutoRequest ar(cx);
+  JSAutoCompartment ac(cx, obj);
+
   JSObject *proto;
-  JSAutoRequest ar(cx);
-  JSAutoCompartment ac(cx, obj);
 
   // Loop over the DOM element's JS object prototype chain and remove
   // all JS objects of the class sNPObjectJSWrapperClass
   bool removed = false;
   while (obj) {
     if (!::JS_GetPrototype(cx, obj, &proto)) {
       return;
     }
@@ -3153,17 +3155,17 @@ nsObjectLoadingContent::SetupProtoChainR
   // like we could just always use the safe context....
   nsCxPusher pusher;
   JSContext* cx = mContext ? mContext->GetNativeContext()
                            : nsContentUtils::GetSafeJSContext();
   pusher.Push(cx);
 
   nsCOMPtr<nsIContent> content;
   CallQueryInterface(mContent.get(), getter_AddRefs(content));
-  JSObject* obj = content->GetWrapper();
+  JS::Rooted<JSObject*> obj(cx, content->GetWrapper());
   if (!obj) {
     // No need to set up our proto chain if we don't even have an object
     return NS_OK;
   }
   nsObjectLoadingContent* objectLoadingContent =
     static_cast<nsObjectLoadingContent*>(mContent.get());
   objectLoadingContent->SetupProtoChain(cx, obj);
   return NS_OK;
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -139,17 +139,17 @@ class nsObjectLoadingContent : public ns
      * SetupProtoChain handles actually inserting the plug-in
      * scriptable object into the proto chain if needed.
      *
      * DoNewResolve is a hook that allows us to find out when the web
      * page is looking up a property name on our object and make sure
      * that our plug-in, if any, is instantiated.
      */
     // Helper for WebIDL node wrapping
-    void SetupProtoChain(JSContext* aCx, JSObject* aObject);
+    void SetupProtoChain(JSContext* aCx, JS::Handle<JSObject*> aObject);
 
     // Remove plugin from protochain
     void TeardownProtoChain();
 
     // Helper for WebIDL newResolve
     bool DoNewResolve(JSContext* aCx, JSHandleObject aObject, JSHandleId aId,
                       unsigned aFlags, JS::MutableHandle<JSObject*> aObjp);
 
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -3629,17 +3629,17 @@ JS::Value
 nsXMLHttpRequest::GetInterface(JSContext* aCx, nsIJSID* aIID, ErrorResult& aRv)
 {
   const nsID* iid = aIID->GetID();
   nsCOMPtr<nsISupports> result;
   JS::Value v = JSVAL_NULL;
   aRv = GetInterface(*iid, getter_AddRefs(result));
   NS_ENSURE_FALSE(aRv.Failed(), JSVAL_NULL);
 
-  JSObject* wrapper = GetWrapper();
+  JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
   JSAutoCompartment ac(aCx, wrapper);
   JSObject* global = JS_GetGlobalForObject(aCx, wrapper);
   aRv = nsContentUtils::WrapNative(aCx, global, result, iid, &v);
   return aRv.Failed() ? JSVAL_NULL : v;
 }
 
 nsXMLHttpRequestUpload*
 nsXMLHttpRequest::Upload()
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -2806,19 +2806,17 @@ CanvasRenderingContext2D::SetMozDash(JSC
       state.dashOffset = 0;
     }
   }
 }
 
 JS::Value
 CanvasRenderingContext2D::GetMozDash(JSContext* cx, ErrorResult& error)
 {
-  JS::Value mozDash;
-  error = DashArrayToJSVal(CurrentState().dash, cx, &mozDash);
-  return mozDash;
+  return DashArrayToJSVal(CurrentState().dash, cx, error);
 }
 
 void
 CanvasRenderingContext2D::SetMozDashOffset(double mozDashOffset)
 {
   ContextState& state = CurrentState();
   if (!state.dash.IsEmpty()) {
     state.dashOffset = mozDashOffset;
@@ -3419,17 +3417,17 @@ CanvasRenderingContext2D::GetImageDataAr
     if (snapshot) {
       readback = snapshot->GetDataSurface();
     }
     if (!readback || !readback->GetData()) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
-  JSObject* darray = JS_NewUint8ClampedArray(aCx, len.value());
+  JS::Rooted<JSObject*> darray(aCx, JS_NewUint8ClampedArray(aCx, len.value()));
   if (!darray) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (mZero) {
     *aRetval = darray;
     return NS_OK;
   }
--- a/content/canvas/src/CanvasUtils.h
+++ b/content/canvas/src/CanvasUtils.h
@@ -86,31 +86,31 @@ inline bool FloatValidate (double f1, do
 #undef VALIDATE
 
 template<typename T>
 nsresult
 JSValToDashArray(JSContext* cx, const JS::Value& val,
                  FallibleTArray<T>& dashArray);
 
 template<typename T>
-nsresult
+JS::Value
 DashArrayToJSVal(FallibleTArray<T>& dashArray,
-                 JSContext* cx, JS::Value* val);
+                 JSContext* cx, mozilla::ErrorResult& rv);
 
 template<typename T>
 nsresult
 JSValToDashArray(JSContext* cx, const JS::Value& patternArray,
                  FallibleTArray<T>& dashes)
 {
     // The cap is pretty arbitrary.  16k should be enough for
     // anybody...
     static const uint32_t MAX_NUM_DASHES = 1 << 14;
 
     if (!JSVAL_IS_PRIMITIVE(patternArray)) {
-        JSObject* obj = JSVAL_TO_OBJECT(patternArray);
+        JS::Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(patternArray));
         uint32_t length;
         if (!JS_GetArrayLength(cx, obj, &length)) {
             // Not an array-like thing
             return NS_ERROR_INVALID_ARG;
         } else if (length > MAX_NUM_DASHES) {
             // Too many dashes in the pattern
             return NS_ERROR_ILLEGAL_VALUE;
         }
@@ -144,35 +144,36 @@ JSValToDashArray(JSContext* cx, const JS
         // random garbage is a type error.
         return NS_ERROR_INVALID_ARG;
     }
 
     return NS_OK;
 }
 
 template<typename T>
-nsresult
+JS::Value
 DashArrayToJSVal(FallibleTArray<T>& dashes,
-                 JSContext* cx, JS::Value* val)
+                 JSContext* cx, mozilla::ErrorResult& rv)
 {
     if (dashes.IsEmpty()) {
-        *val = JSVAL_NULL;
-    } else {
-        JSObject* obj = JS_NewArrayObject(cx, dashes.Length(), nullptr);
-        if (!obj) {
-            return NS_ERROR_OUT_OF_MEMORY;
+        return JSVAL_NULL;
+    }
+    JS::Rooted<JSObject*> obj(cx,
+        JS_NewArrayObject(cx, dashes.Length(), nullptr));
+    if (!obj) {
+        rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+        return JSVAL_NULL;
+    }
+    for (uint32_t i = 0; i < dashes.Length(); ++i) {
+        double d = dashes[i];
+        JS::Value elt = DOUBLE_TO_JSVAL(d);
+        if (!JS_SetElement(cx, obj, i, &elt)) {
+            rv.Throw(NS_ERROR_FAILURE);
+            return JSVAL_NULL;
         }
-        for (uint32_t i = 0; i < dashes.Length(); ++i) {
-            double d = dashes[i];
-            JS::Value elt = DOUBLE_TO_JSVAL(d);
-            if (!JS_SetElement(cx, obj, i, &elt)) {
-                return NS_ERROR_FAILURE;
-            }
-        }
-        *val = OBJECT_TO_JSVAL(obj);
     }
-    return NS_OK;
+    return OBJECT_TO_JSVAL(obj);
 }
 
 }
 }
 
 #endif /* _CANVASUTILS_H_ */
--- a/content/events/src/nsDOMMessageEvent.cpp
+++ b/content/events/src/nsDOMMessageEvent.cpp
@@ -3,16 +3,19 @@
  * 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 "nsDOMMessageEvent.h"
 #include "nsContentUtils.h"
 #include "jsapi.h"
 #include "nsDOMClassInfoID.h"
 
+using namespace mozilla;
+using namespace mozilla::dom;
+
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
   tmp->mData = JSVAL_VOID;
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSource)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -44,20 +47,29 @@ nsDOMMessageEvent::~nsDOMMessageEvent()
 {
   mData = JSVAL_VOID;
   NS_DROP_JS_OBJECTS(this, nsDOMMessageEvent);
 }
 
 NS_IMETHODIMP
 nsDOMMessageEvent::GetData(JSContext* aCx, JS::Value* aData)
 {
-  *aData = mData;
-  if (!JS_WrapValue(aCx, aData))
-    return NS_ERROR_FAILURE;
-  return NS_OK;
+  ErrorResult rv;
+  *aData = GetData(aCx, rv);
+  return rv.ErrorCode();
+}
+
+JS::Value
+nsDOMMessageEvent::GetData(JSContext* aCx, ErrorResult& aRv)
+{
+  JS::Value data = mData;
+  if (!JS_WrapValue(aCx, &data)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+  }
+  return data;
 }
 
 NS_IMETHODIMP
 nsDOMMessageEvent::GetOrigin(nsAString& aOrigin)
 {
   aOrigin = mOrigin;
   return NS_OK;
 }
--- a/content/events/src/nsDOMMessageEvent.h
+++ b/content/events/src/nsDOMMessageEvent.h
@@ -21,38 +21,33 @@
  */
 class nsDOMMessageEvent : public nsDOMEvent,
                           public nsIDOMMessageEvent
 {
 public:
   nsDOMMessageEvent(mozilla::dom::EventTarget* aOwner,
                     nsPresContext* aPresContext, nsEvent* aEvent);
   ~nsDOMMessageEvent();
-                     
+
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMMessageEvent,
                                                          nsDOMEvent)
 
   NS_DECL_NSIDOMMESSAGEEVENT
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMEVENT
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
   {
     return mozilla::dom::MessageEventBinding::Wrap(aCx, aScope, this);
   }
 
-  JS::Value GetData(JSContext* aCx, mozilla::ErrorResult& aRv)
-  {
-    JS::Value data;
-    aRv = GetData(aCx, &data);
-    return data;
-  }
+  JS::Value GetData(JSContext* aCx, mozilla::ErrorResult& aRv);
 
   already_AddRefed<nsIDOMWindow> GetSource()
   {
     nsCOMPtr<nsIDOMWindow> ret = mSource;
     return ret.forget();
   }
 
   void InitMessageEvent(JSContext* aCx,
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -1594,17 +1594,17 @@ HTMLMediaElement::BuildObjectFromTags(ns
 JSObject*
 HTMLMediaElement::MozGetMetadata(JSContext* cx, ErrorResult& aRv)
 {
   if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
-  JSObject* tags = JS_NewObject(cx, nullptr, nullptr, nullptr);
+  JS::Rooted<JSObject*> tags(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));
   if (!tags) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   if (mTags) {
     MetadataIterCx iter = {cx, tags, false};
     mTags->EnumerateRead(BuildObjectFromTags, static_cast<void*>(&iter));
     if (iter.error) {
--- a/content/html/content/src/HTMLObjectElement.cpp
+++ b/content/html/content/src/HTMLObjectElement.cpp
@@ -450,17 +450,18 @@ HTMLObjectElement::CopyInnerTo(Element* 
   }
 
   return rv;
 }
 
 JSObject*
 HTMLObjectElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
-  JSObject* obj = HTMLObjectElementBinding::Wrap(aCx, aScope, this);
+  JS::Rooted<JSObject*> obj(aCx,
+    HTMLObjectElementBinding::Wrap(aCx, aScope, this));
   if (!obj) {
     return nullptr;
   }
   SetupProtoChain(aCx, obj);
   return obj;
 }
 
 } // namespace dom
--- a/content/html/content/src/HTMLSharedObjectElement.cpp
+++ b/content/html/content/src/HTMLSharedObjectElement.cpp
@@ -357,14 +357,15 @@ HTMLSharedObjectElement::WrapNode(JSCont
     obj = HTMLAppletElementBinding::Wrap(aCx, aScope, this);
   } else {
     MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::embed));
     obj = HTMLEmbedElementBinding::Wrap(aCx, aScope, this);
   }
   if (!obj) {
     return nullptr;
   }
-  SetupProtoChain(aCx, obj);
-  return obj;
+  JS::Rooted<JSObject*> rootedObj(aCx, obj);
+  SetupProtoChain(aCx, rootedObj);
+  return rootedObj;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/html/content/src/HTMLUnknownElement.cpp
+++ b/content/html/content/src/HTMLUnknownElement.cpp
@@ -13,25 +13,26 @@ namespace mozilla {
 namespace dom {
 
 NS_IMPL_ADDREF_INHERITED(HTMLUnknownElement, Element)
 NS_IMPL_RELEASE_INHERITED(HTMLUnknownElement, Element)
 
 JSObject*
 HTMLUnknownElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JSObject* obj =
-    HTMLUnknownElementBinding::Wrap(aCx, aScope, this);
+  JS::Rooted<JSObject*> obj(aCx,
+    HTMLUnknownElementBinding::Wrap(aCx, aScope, this));
   if (obj && Substring(NodeName(), 0, 2).LowerCaseEqualsLiteral("x-")) {
     // If we have a registered x-tag then we fix the prototype.
     JSAutoCompartment ac(aCx, obj);
     nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
-    JSObject* prototype = document->GetCustomPrototype(LocalName());
+    JS::Rooted<JSObject*> prototype(aCx,
+      document->GetCustomPrototype(LocalName()));
     if (prototype) {
-      NS_ENSURE_TRUE(JS_WrapObject(aCx, &prototype), nullptr);
+      NS_ENSURE_TRUE(JS_WrapObject(aCx, prototype.address()), nullptr);
       NS_ENSURE_TRUE(JS_SetPrototype(aCx, obj, prototype), nullptr);
     }
   }
   return obj;
 }
 
 // QueryInterface implementation for HTMLUnknownElement
 NS_INTERFACE_TABLE_HEAD(HTMLUnknownElement)
--- a/content/svg/document/src/SVGDocument.cpp
+++ b/content/svg/document/src/SVGDocument.cpp
@@ -99,17 +99,17 @@ SVGDocument::Clone(nsINodeInfo *aNodeInf
   NS_ENSURE_SUCCESS(rv, rv);
 
   return CallQueryInterface(clone.get(), aResult);
 }
 
 JSObject*
 SVGDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JSObject* obj = SVGDocumentBinding::Wrap(aCx, aScope, this);
+  JS::Rooted<JSObject*> obj(aCx, SVGDocumentBinding::Wrap(aCx, aScope, this));
   if (obj && !PostCreateWrapper(aCx, obj)) {
     return nullptr;
   }
   return obj;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/xbl/src/nsXBLProtoImpl.cpp
+++ b/content/xbl/src/nsXBLProtoImpl.cpp
@@ -95,26 +95,27 @@ nsXBLProtoImpl::InstallImplementation(ns
   for (nsXBLProtoImplMember* curr = mMembers;
        curr;
        curr = curr->GetNext())
     curr->InstallMember(cx, targetClassObject);
 
   // If we're using a separate XBL scope, make a safe copy of the target class
   // object in the XBL scope that we can use for Xray lookups. We don't need
   // the field accessors, so do this before installing them.
-  JSObject* globalObject = JS_GetGlobalForObject(cx, targetClassObject);
-  JSObject* scopeObject = xpc::GetXBLScope(cx, globalObject);
+  JS::Rooted<JSObject*> globalObject(cx,
+    JS_GetGlobalForObject(cx, targetClassObject));
+  JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScope(cx, globalObject));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
   if (scopeObject != globalObject) {
     JSAutoCompartment ac2(cx, scopeObject);
 
     // Create the object. This is just a property holder, so it doesn't need
     // any special JSClass.
-    JSObject *shadowProto = JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
-                                                       scopeObject);
+    JS::Rooted<JSObject*> shadowProto(cx,
+      JS_NewObjectWithGivenProto(cx, nullptr, nullptr, scopeObject));
     NS_ENSURE_TRUE(shadowProto, NS_ERROR_OUT_OF_MEMORY);
 
     // Define it as a property on the scopeObject, using the same name used on
     // the content side.
     bool ok = JS_DefineProperty(cx, scopeObject,
                                 js::GetObjectClass(targetClassObject)->name,
                                 JS::ObjectValue(*shadowProto), JS_PropertyStub,
                                 JS_StrictPropertyStub,
--- a/content/xml/document/src/XMLDocument.cpp
+++ b/content/xml/document/src/XMLDocument.cpp
@@ -624,17 +624,17 @@ XMLDocument::Clone(nsINodeInfo *aNodeInf
   clone->mAsync = mAsync;
 
   return CallQueryInterface(clone.get(), aResult);
 }
 
 JSObject*
 XMLDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JSObject* obj = XMLDocumentBinding::Wrap(aCx, aScope, this);
+  JS::Rooted<JSObject*> obj(aCx, XMLDocumentBinding::Wrap(aCx, aScope, this));
   if (obj && !PostCreateWrapper(aCx, obj)) {
     return nullptr;
   }
   return obj;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -4757,17 +4757,17 @@ XULDocument::GetBoxObjectFor(nsIDOMEleme
     nsCOMPtr<Element> el = do_QueryInterface(aElement);
     *aResult = GetBoxObjectFor(el, rv).get();
     return rv.ErrorCode();
 }
 
 JSObject*
 XULDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JSObject* obj = XULDocumentBinding::Wrap(aCx, aScope, this);
+  JS::Rooted<JSObject*> obj(aCx, XULDocumentBinding::Wrap(aCx, aScope, this));
   if (obj && !PostCreateWrapper(aCx, obj)) {
     return nullptr;
   }
   return obj;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -758,19 +758,19 @@ nsXULPDGlobalObject::EnsureScriptEnviron
 
   // We have to setup a special global object.  We do this then
   // attach it as the global for this context.  Then, we
   // will re-fetch the global and set it up in our language globals array.
   {
     AutoPushJSContext cx(ctxNew->GetNativeContext());
     JSAutoRequest ar(cx);
 
-    JSObject *newGlob = JS_NewGlobalObject(cx, &gSharedGlobalClass,
-                                           nsJSPrincipals::get(GetPrincipal()),
-                                           JS::SystemZone);
+    JS::Rooted<JSObject*> newGlob(cx,
+      JS_NewGlobalObject(cx, &gSharedGlobalClass,
+                         nsJSPrincipals::get(GetPrincipal()), JS::SystemZone));
     if (!newGlob)
         return NS_OK;
 
     ::JS_SetGlobalObject(cx, newGlob);
 
     // Add an owning reference from JS back to us. This'll be
     // released when the JSObject is finalized.
     ::JS_SetPrivate(newGlob, this);
--- a/content/xul/templates/src/nsXULTemplateBuilder.cpp
+++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp
@@ -1388,17 +1388,17 @@ nsXULTemplateBuilder::InitHTMLTemplateRo
     JSAutoRequest ar(jscontext);
 
     JS::Value v;
     nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
     rv = nsContentUtils::WrapNative(jscontext, scope, mRoot, mRoot, &v,
                                     getter_AddRefs(wrapper));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JSObject* jselement = JSVAL_TO_OBJECT(v);
+    JS::Rooted<JSObject*> jselement(jscontext, JSVAL_TO_OBJECT(v));
 
     if (mDB) {
         // database
         JS::Value jsdatabase;
         rv = nsContentUtils::WrapNative(jscontext, scope, mDB,
                                         &NS_GET_IID(nsIRDFCompositeDataSource),
                                         &jsdatabase, getter_AddRefs(wrapper));
         NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1173,28 +1173,28 @@ JSObject* GetJSObjectFromCallback(void* 
 
 template<typename T>
 static inline JSObject*
 WrapCallThisObject(JSContext* cx, JS::Handle<JSObject*> scope, const T& p)
 {
   // Callbacks are nsISupports, so WrapNativeParent will just happily wrap them
   // up as an nsISupports XPCWrappedNative... which is not at all what we want.
   // So we need to special-case them.
-  JSObject* obj = GetJSObjectFromCallback(p);
+  JS::Rooted<JSObject*> obj(cx, GetJSObjectFromCallback(p));
   if (!obj) {
     // WrapNativeParent is a bit of a Swiss army knife that will
     // wrap anything for us.
     obj = WrapNativeParent(cx, scope, p);
     if (!obj) {
       return nullptr;
     }
   }
 
   // But all that won't necessarily put things in the compartment of cx.
-  if (!JS_WrapObject(cx, &obj)) {
+  if (!JS_WrapObject(cx, obj.address())) {
     return nullptr;
   }
 
   return obj;
 }
 
 // Helper for calling WrapNewBindingObject with smart pointers
 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.