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 143887 6bc3ac8a681e5644b986cf68cc7a9fd03b155ac1
parent 143886 d6ee8d80627cb264fed411cc56ef3ba7e1d88a30
child 143888 908f7d92b2acf71556567dad0b7ad6351f6b7b2b
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs873735
milestone24.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 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;