Bug 873735 part 1. Fix the more or less mechanical browser rooting hazards. r=terrence
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 20 May 2013 08:40:06 -0400
changeset 139514 6bc3ac8a681e5644b986cf68cc7a9fd03b155ac1
parent 139513 d6ee8d80627cb264fed411cc56ef3ba7e1d88a30
child 139515 908f7d92b2acf71556567dad0b7ad6351f6b7b2b
push id3911
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 20:17:26 +0000
treeherdermozilla-aurora@7e26ca8db92b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs873735
milestone24.0a1
Bug 873735 part 1. Fix the more or less mechanical browser rooting hazards. r=terrence
caps/include/nsScriptSecurityManager.h
caps/src/nsScriptSecurityManager.cpp
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsFrameMessageManager.h
content/base/src/nsInProcessTabChildGlobal.cpp
content/xbl/src/nsXBLProtoImplMethod.cpp
content/xbl/src/nsXBLProtoImplProperty.cpp
content/xbl/src/nsXBLSerialize.cpp
content/xbl/src/nsXBLSerialize.h
content/xul/content/src/nsXULElement.cpp
content/xul/content/src/nsXULElement.h
content/xul/document/src/XULDocument.cpp
content/xul/document/src/XULDocument.h
content/xul/document/src/nsXULPrototypeCache.cpp
content/xul/document/src/nsXULPrototypeCache.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/TabChild.cpp
dom/ipc/TabParent.cpp
js/xpconnect/public/nsTArrayHelpers.h
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -378,20 +378,21 @@ private:
                       JSMutableHandleValue vp);
     
     // Decides, based on CSP, whether or not eval() and stuff can be executed.
     static JSBool
     ContentSecurityPolicyPermitsJSAction(JSContext *cx);
 
     // Returns null if a principal cannot be found; generally callers
     // should error out at that point.
-    static nsIPrincipal* doGetObjectPrincipal(JSObject *obj);
+    static nsIPrincipal* doGetObjectPrincipal(JS::Handle<JSObject*> obj);
 #ifdef DEBUG
     static nsIPrincipal*
-    old_doGetObjectPrincipal(JSObject *obj, bool aAllowShortCircuit = true);
+    old_doGetObjectPrincipal(JS::Handle<JSObject*> obj,
+                             bool aAllowShortCircuit = true);
 #endif
 
     // Returns null if a principal cannot be found.  Note that rv can be NS_OK
     // when this happens -- this means that there was no JS running.
     nsIPrincipal*
     doGetSubjectPrincipal(nsresult* rv);
     
     nsresult
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -1628,17 +1628,17 @@ nsScriptSecurityManager::CheckFunctionAc
     if (!aTargetObj) {
         // We're done here
         return NS_OK;
     }
 
     /*
     ** Get origin of subject and object and compare.
     */
-    JSObject* obj = (JSObject*)aTargetObj;
+    JS::Rooted<JSObject*> obj(aCx, (JSObject*)aTargetObj);
     nsIPrincipal* object = doGetObjectPrincipal(obj);
 
     if (!object)
         return NS_ERROR_FAILURE;
 
     bool subsumes;
     rv = subject->Subsumes(object, &subsumes);
     if (NS_SUCCEEDED(rv) && !subsumes) {
@@ -2018,26 +2018,27 @@ nsScriptSecurityManager::GetSubjectPrinc
     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
     return nsJSPrincipals::get(principals);
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
                                             nsIPrincipal **result)
 {
-    *result = doGetObjectPrincipal(aObj);
+    JS::Rooted<JSObject*> obj(aCx, aObj);
+    *result = doGetObjectPrincipal(obj);
     if (!*result)
         return NS_ERROR_FAILURE;
     NS_ADDREF(*result);
     return NS_OK;
 }
 
 // static
 nsIPrincipal*
-nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
+nsScriptSecurityManager::doGetObjectPrincipal(JS::Handle<JSObject*> aObj)
 {
     JSCompartment *compartment = js::GetObjectCompartment(aObj);
     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
     nsIPrincipal *principal = nsJSPrincipals::get(principals);
 
     // We leave the old code in for a little while to make sure that pulling
     // object principals directly off the compartment always gives an equivalent
     // result (from a security perspective).
@@ -2047,24 +2048,25 @@ nsScriptSecurityManager::doGetObjectPrin
 #endif
 
     return principal;
 }
 
 #ifdef DEBUG
 // static
 nsIPrincipal*
-nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj,
+nsScriptSecurityManager::old_doGetObjectPrincipal(JS::Handle<JSObject*> aObj,
                                                   bool aAllowShortCircuit)
 {
     NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!");
     nsIPrincipal* result = nullptr;
 
-    JS::RootedObject obj(sXPConnect->GetCurrentJSContext(), aObj);
-    JSObject* origObj = obj;
+    JSContext* cx = sXPConnect->GetCurrentJSContext();
+    JS::RootedObject obj(cx, aObj);
+    JS::RootedObject origObj(cx, obj);
     js::Class *jsClass = js::GetObjectClass(obj);
 
     // A common case seen in this code is that we enter this function
     // with obj being a Function object, whose parent is a Call
     // object. Neither of those have object principals, so we can skip
     // those objects here before we enter the below loop. That way we
     // avoid wasting time checking properties of their classes etc in
     // the loop.
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -2199,17 +2199,17 @@ public:
 
       StructuredCloneData data;
       data.mData = mData.data();
       data.mDataLength = mData.nbytes();
       data.mClosure = mClosure;
 
       nsRefPtr<nsFrameMessageManager> mm = tabChild->GetInnerManager();
       mm->ReceiveMessage(static_cast<EventTarget*>(tabChild), mMessage,
-                         false, &data, nullptr, nullptr, nullptr);
+                         false, &data, JS::NullPtr(), nullptr, nullptr);
     }
     return NS_OK;
   }
   nsRefPtr<nsFrameLoader> mFrameLoader;
   nsString mMessage;
   JSAutoStructuredCloneBuffer mData;
   StructuredCloneClosure mClosure;
 };
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -621,17 +621,17 @@ public:
 
 // nsIMessageListener
 
 nsresult
 nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
                                       const nsAString& aMessage,
                                       bool aSync,
                                       const StructuredCloneData* aCloneData,
-                                      JSObject* aObjectsArray,
+                                      JS::Handle<JSObject*> aObjectsArray,
                                       InfallibleTArray<nsString>* aJSONRetVal,
                                       JSContext* aContext)
 {
   JSContext *cxToUse = mContext ? mContext
                                 : (aContext ? aContext
                                             : nsContentUtils::GetSafeJSContext());
   JS::Rooted<JSObject*> objectsArray(cxToUse, aObjectsArray);
   AutoPushJSContext ctx(cxToUse);
@@ -1201,17 +1201,17 @@ public:
     if (nsFrameMessageManager::sChildProcessManager) {
       StructuredCloneData data;
       data.mData = mData.data();
       data.mDataLength = mData.nbytes();
       data.mClosure = mClosure;
 
       nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sChildProcessManager;
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage,
-                          false, &data, nullptr, nullptr, nullptr);
+                          false, &data, JS::NullPtr(), nullptr, nullptr);
     }
     return NS_OK;
   }
   nsString mMessage;
   JSAutoStructuredCloneBuffer mData;
   StructuredCloneClosure mClosure;
 };
 
@@ -1331,17 +1331,17 @@ public:
       StructuredCloneData data;
       data.mData = mData.data();
       data.mDataLength = mData.nbytes();
       data.mClosure = mClosure;
 
       nsRefPtr<nsFrameMessageManager> ppm =
         nsFrameMessageManager::sSameProcessParentManager;
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
-                          mMessage, false, &data, nullptr, nullptr, nullptr);
+                          mMessage, false, &data, JS::NullPtr(), nullptr, nullptr);
      }
      return NS_OK;
   }
   nsString mMessage;
   JSAutoStructuredCloneBuffer mData;
   StructuredCloneClosure mClosure;
 };
 
@@ -1371,17 +1371,17 @@ public:
       for (uint32_t i = 0; i < len; ++i) {
         nsCOMPtr<nsIRunnable> async = asyncMessages[i];
         async->Run();
       }
     }
     if (nsFrameMessageManager::sSameProcessParentManager) {
       nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
-                          true, &aData, nullptr, aJSONRetVal);
+                          true, &aData, JS::NullPtr(), aJSONRetVal);
     }
     return true;
   }
 
   virtual bool DoSendAsyncMessage(const nsAString& aMessage,
                                   const mozilla::dom::StructuredCloneData& aData)
   {
     if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -177,17 +177,17 @@ public:
   NS_DECL_NSIFRAMESCRIPTLOADER
   NS_DECL_NSIPROCESSCHECKER
 
   static nsFrameMessageManager*
   NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
 
   nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
                           bool aSync, const StructuredCloneData* aCloneData,
-                          JSObject* aObjectsArray,
+                          JS::Handle<JSObject*> aObjectsArray,
                           InfallibleTArray<nsString>* aJSONRetVal,
                           JSContext* aContext = nullptr);
 
   void AddChildManager(nsFrameMessageManager* aManager,
                        bool aLoadScripts = true);
   void RemoveChildManager(nsFrameMessageManager* aManager)
   {
     mChildManagers.RemoveObject(aManager);
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -33,17 +33,18 @@ nsInProcessTabChildGlobal::DoSendSyncMes
   asyncMessages.SwapElements(mASyncMessages);
   uint32_t len = asyncMessages.Length();
   for (uint32_t i = 0; i < len; ++i) {
     nsCOMPtr<nsIRunnable> async = asyncMessages[i];
     async->Run();
   }
   if (mChromeMessageManager) {
     nsRefPtr<nsFrameMessageManager> mm = mChromeMessageManager;
-    mm->ReceiveMessage(mOwner, aMessage, true, &aData, nullptr, aJSONRetVal);
+    mm->ReceiveMessage(mOwner, aMessage, true, &aData, JS::NullPtr(),
+                       aJSONRetVal);
   }
   return true;
 }
 
 class nsAsyncMessageToParent : public nsRunnable
 {
 public:
   nsAsyncMessageToParent(nsInProcessTabChildGlobal* aTabChild,
@@ -68,17 +69,17 @@ public:
     if (mTabChild->mChromeMessageManager) {
       StructuredCloneData data;
       data.mData = mData.data();
       data.mDataLength = mData.nbytes();
       data.mClosure = mClosure;
 
       nsRefPtr<nsFrameMessageManager> mm = mTabChild->mChromeMessageManager;
       mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data,
-                         nullptr, nullptr, nullptr);
+                         JS::NullPtr(), nullptr, nullptr);
     }
     return NS_OK;
   }
   nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
   nsString mMessage;
   JSAutoStructuredCloneBuffer mData;
   StructuredCloneClosure mClosure;
   // True if this runnable has already been called. This can happen if DoSendSyncMessage
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -259,17 +259,18 @@ nsXBLProtoImplMethod::Write(nsIScriptCon
 {
   if (mJSMethodObject) {
     nsresult rv = aStream->Write8(XBLBinding_Serialize_Method);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = aStream->WriteWStringZ(mName);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    return XBL_SerializeFunction(aContext, aStream, mJSMethodObject);
+    return XBL_SerializeFunction(aContext, aStream,
+                                 JS::Handle<JSObject*>::fromMarkedLocation(&mJSMethodObject));
   }
 
   return NS_OK;
 }
 
 nsresult
 nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
 {
@@ -364,14 +365,15 @@ nsresult
 nsXBLProtoImplAnonymousMethod::Write(nsIScriptContext* aContext,
                                      nsIObjectOutputStream* aStream,
                                      XBLBindingSerializeDetails aType)
 {
   if (mJSMethodObject) {
     nsresult rv = aStream->Write8(aType);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = XBL_SerializeFunction(aContext, aStream, mJSMethodObject);
+    rv = XBL_SerializeFunction(aContext, aStream,
+                               JS::Handle<JSObject*>::fromMarkedLocation(&mJSMethodObject));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
--- a/content/xbl/src/nsXBLProtoImplProperty.cpp
+++ b/content/xbl/src/nsXBLProtoImplProperty.cpp
@@ -368,19 +368,21 @@ nsXBLProtoImplProperty::Write(nsIScriptC
   }
 
   nsresult rv = aStream->Write8(type);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->WriteWStringZ(mName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mJSAttributes & JSPROP_GETTER) {
-    rv = XBL_SerializeFunction(aContext, aStream, mJSGetterObject);
+    rv = XBL_SerializeFunction(aContext, aStream,
+      JS::Handle<JSObject*>::fromMarkedLocation(&mJSGetterObject));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (mJSAttributes & JSPROP_SETTER) {
-    rv = XBL_SerializeFunction(aContext, aStream, mJSSetterObject);
+    rv = XBL_SerializeFunction(aContext, aStream,
+      JS::Handle<JSObject*>::fromMarkedLocation(&mJSSetterObject));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
--- a/content/xbl/src/nsXBLSerialize.cpp
+++ b/content/xbl/src/nsXBLSerialize.cpp
@@ -8,21 +8,20 @@
 #include "nsContentUtils.h"
 #include "jsdbgapi.h"
 
 using namespace mozilla;
 
 nsresult
 XBL_SerializeFunction(nsIScriptContext* aContext,
                       nsIObjectOutputStream* aStream,
-                      JSObject* aFunctionObject)
+                      JS::Handle<JSObject*> aFunction)
 {
   AutoPushJSContext cx(aContext->GetNativeContext());
-  JS::RootedObject function(cx, aFunctionObject);
-  return nsContentUtils::XPConnect()->WriteFunction(aStream, cx, function);
+  return nsContentUtils::XPConnect()->WriteFunction(aStream, cx, aFunction);
 }
 
 nsresult
 XBL_DeserializeFunction(nsIScriptContext* aContext,
                         nsIObjectInputStream* aStream,
                         JS::MutableHandle<JSObject*> aFunctionObjectp)
 {
   AutoPushJSContext cx(aContext->GetNativeContext());
--- a/content/xbl/src/nsXBLSerialize.h
+++ b/content/xbl/src/nsXBLSerialize.h
@@ -74,16 +74,16 @@ typedef uint8_t XBLBindingSerializeDetai
 // are no more attributes.
 #define XBLBinding_Serialize_NoMoreAttributes 0xFF
 
 PR_STATIC_ASSERT(XBLBinding_Serialize_CustomNamespace >= kNameSpaceID_LastBuiltin);
 
 nsresult
 XBL_SerializeFunction(nsIScriptContext* aContext,
                       nsIObjectOutputStream* aStream,
-                      JSObject* aFunctionObject);
+                      JS::Handle<JSObject*> aFunctionObject);
 
 nsresult
 XBL_DeserializeFunction(nsIScriptContext* aContext,
                         nsIObjectInputStream* aStream,
                         JS::MutableHandle<JSObject*> aFunctionObject);
 
 #endif // nsXBLSerialize_h__
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -2521,17 +2521,17 @@ nsXULPrototypeScript::DeserializeOutOfLi
             if (NS_SUCCEEDED(rv))
                 rv = Deserialize(objectInput, aGlobal, nullptr, nullptr);
 
             if (NS_SUCCEEDED(rv)) {
                 if (useXULCache && mSrcURI) {
                     bool isChrome = false;
                     mSrcURI->SchemeIs("chrome", &isChrome);
                     if (isChrome)
-                        cache->PutScript(mSrcURI, mScriptObject);
+                        cache->PutScript(mSrcURI, GetScriptObject());
                 }
                 cache->FinishInputStream(mSrcURI);
             } else {
                 // If mSrcURI is not in the cache,
                 // rv will be NS_ERROR_NOT_AVAILABLE and we'll try to
                 // update the cache file to hold a serialization of
                 // this script, once it has finished loading.
                 if (rv != NS_ERROR_NOT_AVAILABLE)
@@ -2623,19 +2623,19 @@ void
 nsXULPrototypeScript::Set(JSScript* aObject)
 {
     MOZ_ASSERT(!mScriptObject, "Leaking script object.");
     if (!aObject) {
         mScriptObject = nullptr;
         return;
     }
 
+    mScriptObject = aObject;
     nsContentUtils::HoldJSObjects(
         this, NS_CYCLE_COLLECTION_PARTICIPANT(nsXULPrototypeNode));
-    mScriptObject = aObject;
 }
 
 //----------------------------------------------------------------------
 //
 // nsXULPrototypeText
 //
 
 nsresult
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -231,19 +231,23 @@ public:
                      nsIURI* aURI, uint32_t aLineNo,
                      nsIDocument* aDocument,
                      nsIScriptGlobalObjectOwner* aGlobalOwner);
 
     void UnlinkJSObjects();
 
     void Set(JSScript* aObject);
 
-    JSScript *GetScriptObject()
+    // It's safe to return a handle because we trace mScriptObject, no one ever
+    // uses the handle (or the script object) past the point at which the
+    // nsXULPrototypeScript dies, and we can't get memmoved so the
+    // &mScriptObject pointer can't go stale.
+    JS::Handle<JSScript*> GetScriptObject()
     {
-        return mScriptObject;
+        return JS::Handle<JSScript*>::fromMarkedLocation(&mScriptObject);
     }
 
     void TraceScriptObject(JSTracer* aTrc)
     {
         if (mScriptObject) {
             JS_CallScriptTracer(aTrc, &mScriptObject, "active window XUL prototype script");
         }
     }
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -3639,28 +3639,28 @@ XULDocument::OnStreamComplete(nsIStreamL
         NS_RELEASE(doc);
     }
 
     return rv;
 }
 
 
 nsresult
-XULDocument::ExecuteScript(nsIScriptContext * aContext, JSScript* aScriptObject)
+XULDocument::ExecuteScript(nsIScriptContext * aContext,
+                           JS::Handle<JSScript*> aScriptObject)
 {
     NS_PRECONDITION(aScriptObject != nullptr && aContext != nullptr, "null ptr");
     if (! aScriptObject || ! aContext)
         return NS_ERROR_NULL_POINTER;
 
     NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED);
 
     // Execute the precompiled script with the given version
-    JS::Rooted<JSScript*> script(aContext->GetNativeContext(), aScriptObject);
     JSObject* global = mScriptGlobalObject->GetGlobalJSObject();
-    return aContext->ExecuteScript(script, global);
+    return aContext->ExecuteScript(aScriptObject, global);
 }
 
 nsresult
 XULDocument::ExecuteScript(nsXULPrototypeScript *aScript)
 {
     NS_PRECONDITION(aScript != nullptr, "null ptr");
     NS_ENSURE_TRUE(aScript, NS_ERROR_NULL_POINTER);
     NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED);
--- a/content/xul/document/src/XULDocument.h
+++ b/content/xul/document/src/XULDocument.h
@@ -398,17 +398,18 @@ protected:
      * completed, aBlock will be set to true.
      */
     nsresult LoadScript(nsXULPrototypeScript *aScriptProto, bool* aBlock);
 
     /**
      * Execute the precompiled script object scoped by this XUL document's
      * containing window object, and using its associated script context.
      */
-    nsresult ExecuteScript(nsIScriptContext *aContext, JSScript* aScriptObject);
+    nsresult ExecuteScript(nsIScriptContext *aContext,
+                           JS::Handle<JSScript*> aScriptObject);
 
     /**
      * Helper method for the above that uses aScript to find the appropriate
      * script context and object.
      */
     nsresult ExecuteScript(nsXULPrototypeScript *aScript);
 
     /**
--- a/content/xul/document/src/nsXULPrototypeCache.cpp
+++ b/content/xul/document/src/nsXULPrototypeCache.cpp
@@ -200,17 +200,18 @@ nsXULPrototypeCache::GetScript(nsIURI* a
     CacheScriptEntry entry;
     if (!mScriptTable.Get(aURI, &entry)) {
         return nullptr;
     }
     return entry.mScriptObject;
 }
 
 nsresult
-nsXULPrototypeCache::PutScript(nsIURI* aURI, JSScript* aScriptObject)
+nsXULPrototypeCache::PutScript(nsIURI* aURI,
+                               JS::Handle<JSScript*> aScriptObject)
 {
     CacheScriptEntry existingEntry;
     if (mScriptTable.Get(aURI, &existingEntry)) {
 #ifdef DEBUG
         nsAutoCString scriptName;
         aURI->GetSpec(scriptName);
         nsAutoCString message("Loaded script ");
         message += scriptName;
--- a/content/xul/document/src/nsXULPrototypeCache.h
+++ b/content/xul/document/src/nsXULPrototypeCache.h
@@ -64,17 +64,17 @@ public:
 
     // The following methods are used to put and retrive various items into and
     // from the cache.
 
     nsXULPrototypeDocument* GetPrototype(nsIURI* aURI);
     nsresult PutPrototype(nsXULPrototypeDocument* aDocument);
 
     JSScript* GetScript(nsIURI* aURI);
-    nsresult PutScript(nsIURI* aURI, JSScript* aScriptObject);
+    nsresult PutScript(nsIURI* aURI, JS::Handle<JSScript*> aScriptObject);
 
     nsXBLDocumentInfo* GetXBLDocumentInfo(nsIURI* aURL) {
         return mXBLDocTable.GetWeak(aURL);
     }
     nsresult PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo);
 
     /**
      * Get a style sheet by URI. If the style sheet is not in the cache,
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1021,17 +1021,17 @@ ContentChild::RecvNotifyVisited(const UR
 bool
 ContentChild::RecvAsyncMessage(const nsString& aMsg,
                                      const ClonedMessageData& aData)
 {
   nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
   if (cpm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
     cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
-                        aMsg, false, &cloneData, nullptr, nullptr);
+                        aMsg, false, &cloneData, JS::NullPtr(), nullptr);
   }
   return true;
 }
 
 bool
 ContentChild::RecvGeolocationUpdate(const GeoPosition& somewhere)
 {
   nsCOMPtr<nsIGeolocationUpdate> gs = do_GetService("@mozilla.org/geolocation/service;1");
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -861,17 +861,17 @@ ContentParent::ActorDestroy(ActorDestroy
         mForceKillTask->Cancel();
         mForceKillTask = nullptr;
     }
 
     nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
     if (ppm) {
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
                           CHILD_PROCESS_SHUTDOWN_MESSAGE, false,
-                          nullptr, nullptr, nullptr);
+                          nullptr, JS::NullPtr(), nullptr);
     }
     nsCOMPtr<nsIThreadObserver>
         kungFuDeathGrip(static_cast<nsIThreadObserver*>(this));
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "xpcom-shutdown");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "memory-pressure");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-memory-reporter-request");
@@ -2326,30 +2326,30 @@ bool
 ContentParent::RecvSyncMessage(const nsString& aMsg,
                                const ClonedMessageData& aData,
                                InfallibleTArray<nsString>* aRetvals)
 {
   nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
-                        aMsg, true, &cloneData, nullptr, aRetvals);
+                        aMsg, true, &cloneData, JS::NullPtr(), aRetvals);
   }
   return true;
 }
 
 bool
 ContentParent::RecvAsyncMessage(const nsString& aMsg,
                                       const ClonedMessageData& aData)
 {
   nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
-                        aMsg, false, &cloneData, nullptr, nullptr);
+                        aMsg, false, &cloneData, JS::NullPtr(), nullptr);
   }
   return true;
 }
 
 bool
 ContentParent::RecvFilePathUpdateNotify(const nsString& aType,
                                         const nsString& aStorageName,
                                         const nsString& aFilePath,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1431,17 +1431,17 @@ TabChild::DispatchMessageManagerMessage(
     }
 
     nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
     // Let the BrowserElementScrolling helper (if it exists) for this
     // content manipulate the frame state.
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
     mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
-                       aMessageName, false, &cloneData, nullptr, nullptr);
+                       aMessageName, false, &cloneData, JS::NullPtr(), nullptr);
 }
 
 static void
 ScrollWindowTo(nsIDOMWindow* aWindow, const mozilla::gfx::Point& aPoint)
 {
     nsGlobalWindow* window = static_cast<nsGlobalWindow*>(aWindow);
     nsIScrollableFrame* sf = window->GetScrollFrame();
 
@@ -1969,17 +1969,17 @@ TabChild::RecvAsyncMessage(const nsStrin
                            const ClonedMessageData& aData)
 {
   if (mTabChildGlobal) {
     nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
     StructuredCloneData cloneData = UnpackClonedMessageDataForChild(aData);
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
     mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
-                       aMessage, false, &cloneData, nullptr, nullptr);
+                       aMessage, false, &cloneData, JS::NullPtr(), nullptr);
   }
   return true;
 }
 
 class UnloadScriptEvent : public nsRunnable
 {
 public:
   UnloadScriptEvent(TabChild* aTabChild, TabChildGlobal* aTabChildGlobal)
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1097,17 +1097,17 @@ TabParent::ReceiveMessage(const nsString
   if (frameLoader && frameLoader->GetFrameMessageManager()) {
     nsRefPtr<nsFrameMessageManager> manager =
       frameLoader->GetFrameMessageManager();
     JSContext* ctx = manager->GetJSContext();
     JSAutoRequest ar(ctx);
     uint32_t len = 0; //TODO: obtain a real value in bug 572685
     // Because we want JS messages to have always the same properties,
     // create array even if len == 0.
-    JSObject* objectsArray = JS_NewArrayObject(ctx, len, NULL);
+    JS::Rooted<JSObject*> objectsArray(ctx, JS_NewArrayObject(ctx, len, NULL));
     if (!objectsArray) {
       return false;
     }
 
     manager->ReceiveMessage(mFrameElement,
                             aMessage,
                             aSync,
                             aCloneData,
--- a/js/xpconnect/public/nsTArrayHelpers.h
+++ b/js/xpconnect/public/nsTArrayHelpers.h
@@ -8,35 +8,37 @@
 template <class T>
 inline nsresult
 nsTArrayToJSArray(JSContext* aCx, const nsTArray<T>& aSourceArray,
                   JSObject** aResultArray)
 {
   MOZ_ASSERT(aCx);
   JSAutoRequest ar(aCx);
 
-  JSObject* arrayObj = JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr);
+  JS::Rooted<JSObject*> arrayObj(aCx,
+    JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr));
   if (!arrayObj) {
     NS_WARNING("JS_NewArrayObject failed!");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(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);
 
-    jsval wrappedVal;
-    rv = nsContentUtils::WrapNative(aCx, global, obj, &wrappedVal, nullptr, true);
+    JS::Rooted<JS::Value> wrappedVal(aCx);
+    rv = nsContentUtils::WrapNative(aCx, global, obj, wrappedVal.address(),
+                                    nullptr, true);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    if (!JS_SetElement(aCx, arrayObj, index, &wrappedVal)) {
+    if (!JS_SetElement(aCx, arrayObj, index, wrappedVal.address())) {
       NS_WARNING("JS_SetElement failed!");
       return NS_ERROR_FAILURE;
     }
   }
 
   if (!JS_FreezeObject(aCx, arrayObj)) {
     NS_WARNING("JS_FreezeObject failed!");
     return NS_ERROR_FAILURE;
@@ -50,34 +52,35 @@ template <>
 inline nsresult
 nsTArrayToJSArray<nsString>(JSContext* aCx,
                             const nsTArray<nsString>& aSourceArray,
                             JSObject** aResultArray)
 {
   MOZ_ASSERT(aCx);
   JSAutoRequest ar(aCx);
 
-  JSObject* arrayObj = JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr);
+  JS::Rooted<JSObject*> arrayObj(aCx,
+    JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr));
   if (!arrayObj) {
     NS_WARNING("JS_NewArrayObject failed!");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   for (uint32_t index = 0; index < aSourceArray.Length(); index++) {
     JSString* s = JS_NewUCStringCopyN(aCx, aSourceArray[index].BeginReading(),
                                       aSourceArray[index].Length());
 
     if(!s) {
       NS_WARNING("Memory allocation error!");
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    jsval wrappedVal = STRING_TO_JSVAL(s);
+    JS::Rooted<JS::Value> wrappedVal(aCx, STRING_TO_JSVAL(s));
 
-    if (!JS_SetElement(aCx, arrayObj, index, &wrappedVal)) {
+    if (!JS_SetElement(aCx, arrayObj, index, wrappedVal.address())) {
       NS_WARNING("JS_SetElement failed!");
       return NS_ERROR_FAILURE;
     }
   }
 
   if (!JS_FreezeObject(aCx, arrayObj)) {
     NS_WARNING("JS_FreezeObject failed!");
     return NS_ERROR_FAILURE;