Bug 877762 - GC: Post-barrier cycle collector participants - 7 Convert most JSObect to use Heap<T> (ex. XBL) r=bz
authorJon Coppeard <jcoppeard@mozilla.com>
Tue, 18 Jun 2013 11:00:38 +0100
changeset 147812 f6d53e1cde69f62305640e59440aabc4a643bc17
parent 147811 9fba4a49aa71ba00f5b557be53a4d30e634fc236
child 147813 047741328e5a5c47cd6d8be22e2eb9325a836812
push id368
push userbbajaj@mozilla.com
push dateMon, 09 Sep 2013 22:57:58 +0000
treeherdermozilla-release@5a4f47ae1217 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs877762
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 877762 - GC: Post-barrier cycle collector participants - 7 Convert most JSObect to use Heap<T> (ex. XBL) r=bz
content/base/src/nsDOMFileReader.h
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/base/src/nsXMLHttpRequest.h
content/canvas/src/ImageData.h
content/events/src/nsDOMNotifyAudioAvailableEvent.h
content/html/document/src/nsHTMLDocument.h
content/media/webaudio/AudioBuffer.cpp
content/media/webaudio/AudioBuffer.h
content/media/webaudio/WaveShaperNode.h
dom/base/moz.build
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsIJSEventListener.h
dom/base/nsWrapperCache.h
dom/base/nsWrapperCacheInlines.h
dom/bindings/CallbackObject.h
dom/bluetooth/BluetoothAdapter.cpp
dom/bluetooth/BluetoothAdapter.h
dom/bluetooth/BluetoothDevice.cpp
dom/bluetooth/BluetoothDevice.h
dom/indexedDB/IDBCursor.h
dom/indexedDB/IDBFactory.h
dom/indexedDB/IDBWrapperCache.h
dom/telephony/Telephony.h
js/xpconnect/src/XPCJSRuntime.cpp
xpcom/glue/nsCycleCollectionParticipant.cpp
xpcom/glue/nsCycleCollectionParticipant.h
--- a/content/base/src/nsDOMFileReader.h
+++ b/content/base/src/nsDOMFileReader.h
@@ -140,12 +140,12 @@ protected:
   nsCString mCharset;
   uint32_t mDataLen;
 
   eDataFormat mDataFormat;
 
   nsString mResult;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   
-  JSObject* mResultArrayBuffer;
+  JS::Heap<JSObject*> mResultArrayBuffer;
 };
 
 #endif
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1781,17 +1781,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 struct CustomPrototypeTraceArgs {
   const TraceCallbacks& callbacks;
   void* closure;
 };
 
 
 static PLDHashOperator
-CustomPrototypeTrace(const nsAString& aName, JSObject*& aObject, void *aArg)
+CustomPrototypeTrace(const nsAString& aName, JS::Heap<JSObject*>& aObject, void *aArg)
 {
   CustomPrototypeTraceArgs* traceArgs = static_cast<CustomPrototypeTraceArgs*>(aArg);
   MOZ_ASSERT(aObject, "Protocol object value must not be null");
   traceArgs->callbacks.Trace(&aObject, "mCustomPrototypes entry", traceArgs->closure);
   return PL_DHASH_NEXT;
 }
 
 
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -26,16 +26,17 @@
 #include "nsIContent.h"
 #include "nsEventListenerManager.h"
 #include "nsIDOMNodeSelector.h"
 #include "nsIPrincipal.h"
 #include "nsIParser.h"
 #include "nsBindingManager.h"
 #include "nsINodeInfo.h"
 #include "nsInterfaceHashtable.h"
+#include "nsJSThingHashtable.h"
 #include "nsIBoxObject.h"
 #include "nsPIBoxObject.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIURI.h"
 #include "nsScriptLoader.h"
 #include "nsIRadioGroupContainer.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIRequest.h"
@@ -1198,17 +1199,17 @@ protected:
   nsTArray<nsWeakPtr> mFullScreenStack;
 
   // The root of the doc tree in which this document is in. This is only
   // non-null when this document is in fullscreen mode.
   nsWeakPtr mFullscreenRoot;
 
   // Hashtable for custom element prototypes in web components.
   // Custom prototypes are in the document's compartment.
-  nsDataHashtable<nsStringHashKey, JSObject*> mCustomPrototypes;
+  nsJSThingHashtable<nsStringHashKey, JSObject*> mCustomPrototypes;
 
   nsRefPtr<nsEventListenerManager> mListenerManager;
   nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
   nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
   nsRefPtr<nsScriptLoader> mScriptLoader;
   nsDocHeaderData* mHeaderData;
   /* mIdentifierMap works as follows for IDs:
    * 1) Attribute changes affect the table immediately (removing and adding
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -659,17 +659,17 @@ protected:
   bool mInLoadProgressEvent;
 
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
   nsCOMPtr<nsIChannel> mNewRedirectChannel;
 
   JS::Heap<JS::Value> mResultJSON;
 
   js::ArrayBufferBuilder mArrayBufferBuilder;
-  JSObject* mResultArrayBuffer;
+  JS::Heap<JSObject*> mResultArrayBuffer;
 
   void ResetResponse();
 
   struct RequestHeader
   {
     nsCString header;
     nsCString value;
   };
--- a/content/canvas/src/ImageData.h
+++ b/content/canvas/src/ImageData.h
@@ -64,15 +64,15 @@ public:
 
 private:
   void HoldData();
   void DropData();
 
   ImageData() MOZ_DELETE;
 
   uint32_t mWidth, mHeight;
-  JSObject* mData;
+  JS::Heap<JSObject*> mData;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ImageData_h
--- a/content/events/src/nsDOMNotifyAudioAvailableEvent.h
+++ b/content/events/src/nsDOMNotifyAudioAvailableEvent.h
@@ -65,13 +65,13 @@ public:
                                uint32_t aFrameBufferLength,
                                float aTime,
                                bool aAllowAudioData,
                                mozilla::ErrorResult& aRv);
 private:
   nsAutoArrayPtr<float> mFrameBuffer;
   uint32_t mFrameBufferLength;
   float mTime;
-  JSObject* mCachedArray;
+  JS::Heap<JSObject*> mCachedArray;
   bool mAllowAudioData;
 };
 
 #endif // nsDOMNotifyAudioAvailableEvent_h_
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -292,17 +292,17 @@ protected:
   nsRefPtr<nsContentList> mApplets;
   nsRefPtr<nsContentList> mEmbeds;
   nsRefPtr<nsContentList> mLinks;
   nsRefPtr<nsContentList> mAnchors;
   nsRefPtr<nsContentList> mScripts;
   nsRefPtr<nsContentList> mForms;
   nsRefPtr<nsContentList> mFormControls;
 
-  JSObject* mAll;
+  JS::Heap<JSObject*> mAll;
 
   /** # of forms in the document, synchronously set */
   int32_t mNumForms;
 
   static uint32_t gWyciwygSessionCnt;
 
   static void TryHintCharset(nsIMarkupDocumentViewer* aMarkupDV,
                              int32_t& aCharsetSource,
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -74,17 +74,17 @@ AudioBuffer::InitializeBuffers(uint32_t 
   if (!mJSChannels.SetCapacity(aNumberOfChannels)) {
     return false;
   }
   for (uint32_t i = 0; i < aNumberOfChannels; ++i) {
     JS::RootedObject array(aJSContext, JS_NewFloat32Array(aJSContext, mLength));
     if (!array) {
       return false;
     }
-    mJSChannels.AppendElement(array);
+    mJSChannels.AppendElement(array.get());
   }
 
   return true;
 }
 
 JSObject*
 AudioBuffer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
--- a/content/media/webaudio/AudioBuffer.h
+++ b/content/media/webaudio/AudioBuffer.h
@@ -111,17 +111,17 @@ public:
   void MixToMono(JSContext* aJSContext);
 
 protected:
   bool RestoreJSChannelData(JSContext* aJSContext);
   void ClearJSChannels();
 
   nsRefPtr<AudioContext> mContext;
   // Float32Arrays
-  AutoFallibleTArray<JSObject*,2> mJSChannels;
+  AutoFallibleTArray<JS::Heap<JSObject*>, 2> mJSChannels;
 
   // mSharedChannels aggregates the data from mJSChannels. This is non-null
   // if and only if the mJSChannels are neutered.
   nsRefPtr<ThreadSharedFloatArrayBufferList> mSharedChannels;
 
   uint32_t mLength;
   float mSampleRate;
 };
--- a/content/media/webaudio/WaveShaperNode.h
+++ b/content/media/webaudio/WaveShaperNode.h
@@ -32,15 +32,15 @@ public:
     return mCurve;
   }
   void SetCurve(const Float32Array* aData);
 
 private:
   void ClearCurve();
 
 private:
-  JSObject* mCurve;
+  JS::Heap<JSObject*> mCurve;
 };
 
 }
 }
 
 #endif
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -89,17 +89,17 @@ CPP_SOURCES += [
     'nsMimeTypeArray.cpp',
     'nsPerformance.cpp',
     'nsPluginArray.cpp',
     'nsQueryContentEventResult.cpp',
     'nsScreen.cpp',
     'nsScriptNameSpaceManager.cpp',
     'nsStructuredCloneContainer.cpp',
     'nsWindowMemoryReporter.cpp',
-    'nsWindowRoot.cpp',
+    'nsWindowRoot.cpp'
 ]
 
 EXTRA_COMPONENTS += [
     'ConsoleAPI.js',
     'ConsoleAPI.manifest',
     'SiteSpecificUserAgent.js',
     'SiteSpecificUserAgent.manifest',
 ]
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1583,26 +1583,26 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   END_OUTER_WINDOW_ONLY
 NS_INTERFACE_MAP_END
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
 
 static PLDHashOperator
-MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JSObject* aData, void* aClosure)
+MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
 {
   xpc_UnmarkGrayObject(aData);
   return PL_DHASH_NEXT;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
   if (tmp->IsBlackForCC()) {
     if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
-      tmp->mCachedXBLPrototypeHandlers.EnumerateRead(MarkXBLHandlers, nullptr);
+      tmp->mCachedXBLPrototypeHandlers.Enumerate(MarkXBLHandlers, nullptr);
     }
     nsEventListenerManager* elm = tmp->GetListenerManager(false);
     if (elm) {
       elm->MarkForCC();
     }
     tmp->UnmarkGrayTimers();
     return true;
   }
@@ -1744,17 +1744,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 struct TraceData
 {
   const TraceCallbacks& callbacks;
   void* closure;
 };
 
 static PLDHashOperator
-TraceXBLHandlers(nsXBLPrototypeHandler* aKey, JSObject*& aData, void* aClosure)
+TraceXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
 {
   TraceData* data = static_cast<TraceData*>(aClosure);
   data->callbacks.Trace(&aData, "Cached XBL prototype handler", data->closure);
   return PL_DHASH_NEXT;
 }
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
   if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -10,16 +10,17 @@
 #include "mozilla/XPCOM.h" // for TimeStamp/TimeDuration
 
 // Local Includes
 // Helper Classes
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsWeakReference.h"
 #include "nsDataHashtable.h"
+#include "nsJSThingHashtable.h"
 #include "nsCycleCollectionParticipant.h"
 
 // Interfaces Needed
 #include "nsDOMWindowList.h"
 #include "nsIBaseWindow.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocShellTreeItem.h"
@@ -1229,17 +1230,17 @@ protected:
   bool mSetOpenerWindowCalled;
   nsCOMPtr<nsIURI> mLastOpenedURI;
 #endif
 
   bool mCleanedUp, mCallCleanUpAfterModalDialogCloses;
 
   nsCOMPtr<nsIDOMOfflineResourceList> mApplicationCache;
 
-  nsDataHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*> mCachedXBLPrototypeHandlers;
+  nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*> mCachedXBLPrototypeHandlers;
 
   nsCOMPtr<nsIDocument> mSuspendedDoc;
 
   nsRefPtr<mozilla::dom::indexedDB::IDBFactory> mIndexedDB;
 
   // This counts the number of windows that have been opened in rapid succession
   // (i.e. within dom.successive_dialog_time_limit of each other). It is reset
   // to 0 once a dialog is opened after dom.successive_dialog_time_limit seconds
--- a/dom/base/nsIJSEventListener.h
+++ b/dom/base/nsIJSEventListener.h
@@ -263,17 +263,17 @@ protected:
     NS_ASSERTION(!mTarget, "Should have called Disconnect()!");
   }
 
   // Update our mScopeObject; we have to make sure we properly handle
   // the hold/drop stuff, so have to do it in nsJSEventListener.
   virtual void UpdateScopeObject(JS::Handle<JSObject*> aScopeObject) = 0;
 
   nsCOMPtr<nsIScriptContext> mContext;
-  JSObject* mScopeObject;
+  JS::Heap<JSObject*> mScopeObject;
   nsISupports* mTarget;
   nsCOMPtr<nsIAtom> mEventName;
   nsEventHandler mHandler;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID)
 
 /* factory function.  aHandler must already be bound to aTarget.
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -3,17 +3,17 @@
  * 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/. */
 
 #ifndef nsWrapperCache_h___
 #define nsWrapperCache_h___
 
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Assertions.h"
-#include "js/RootingAPI.h"
+#include "js/Value.h"
 
 struct JSTracer;
 class JSObject;
 struct JSContext;
 class XPCWrappedNativeScope;
 
 namespace mozilla {
 namespace dom {
@@ -177,17 +177,17 @@ public:
     else {
       UnsetWrapperFlags(WRAPPER_BIT_PRESERVED);
     }
   }
 
   void TraceWrapper(const TraceCallbacks& aCallbacks, void* aClosure)
   {
     if (PreservingWrapper() && mWrapper) {
-        aCallbacks.Trace(&mWrapper, "Preserved wrapper", aClosure);
+      aCallbacks.Trace(&mWrapper, "Preserved wrapper", aClosure);
     }
   }
 
   /* 
    * The following methods for getting and manipulating flags allow the unused
    * bits of mFlags to be used by derived classes.
    */
 
@@ -275,18 +275,18 @@ private:
    * (regular JS object or proxy) that has a system only wrapper for same-origin
    * access.
    */
   enum { WRAPPER_HAS_SOW = 1 << 2 };
 
   enum { kWrapperFlagsMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_DOM_BINDING |
                               WRAPPER_HAS_SOW) };
 
-  JSObject* mWrapper;
-  uint32_t  mFlags;
+  JS::Heap<JSObject*> mWrapper;
+  uint32_t            mFlags;
 };
 
 enum { WRAPPER_CACHE_FLAGS_BITS_USED = 3 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID)
 
 #define NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY                                   \
   if ( aIID.Equals(NS_GET_IID(nsWrapperCache)) ) {                            \
--- a/dom/base/nsWrapperCacheInlines.h
+++ b/dom/base/nsWrapperCacheInlines.h
@@ -45,12 +45,12 @@ nsWrapperCache::IsBlackAndDoesNotNeedTra
     return !hasGrayObjects;
   }
   return false;
 }
 
 inline void
 nsWrapperCache::TraceWrapperJSObject(JSTracer* aTrc, const char* aName)
 {
-  JS_CallObjectTracer(aTrc, &mWrapper, aName);
+  JS_CallHeapObjectTracer(aTrc, &mWrapper, aName);
 }
 
 #endif /* nsWrapperCache_h___ */
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -71,17 +71,17 @@ public:
    * This should only be called if you are certain that the return value won't
    * be passed into a JS API function and that it won't be stored without being
    * rooted (or otherwise signaling the stored value to the CC).
    *
    * This can return a handle because we trace our mCallback.
    */
   JS::Handle<JSObject*> CallbackPreserveColor() const
   {
-    return JS::Handle<JSObject*>::fromMarkedLocation(&mCallback);
+    return mCallback;
   }
 
   enum ExceptionHandling {
     eReportExceptions,
     eRethrowExceptions
   };
 
 protected:
@@ -106,17 +106,17 @@ protected:
   {
     if (mCallback) {
       mCallback = nullptr;
       NS_DROP_JS_OBJECTS(this, CallbackObject);
       nsLayoutStatics::Release();
     }
   }
 
-  JSObject* mCallback;
+  JS::Heap<JSObject*> mCallback;
 
   class MOZ_STACK_CLASS CallSetup
   {
     /**
      * A class that performs whatever setup we need to safely make a
      * call while this class is on the stack, After the constructor
      * returns, the call is safe to make if GetContext() returns
      * non-null.
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -257,39 +257,43 @@ BluetoothAdapter::SetPropertyByValue(con
     mClass = value.get_uint32_t();
   } else if (name.EqualsLiteral("UUIDs")) {
     mUuids = value.get_ArrayOfnsString();
     nsresult rv;
     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     AutoPushJSContext cx(sc->GetNativeContext());
-    if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, &mJsUuids))) {
+    JS::Rooted<JSObject*> uuids(cx);
+    if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) {
       NS_WARNING("Cannot set JS UUIDs object!");
       return;
     }
+    mJsUuids = uuids;
     Root();
   } else if (name.EqualsLiteral("Devices")) {
     mDeviceAddresses = value.get_ArrayOfnsString();
 
     uint32_t length = mDeviceAddresses.Length();
     for (int i = 0; i < length; i++) {
       mDeviceAddresses[i] = GetAddressFromObjectPath(mDeviceAddresses[i]);
     }
 
     nsresult rv;
     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     AutoPushJSContext cx(sc->GetNativeContext());
+    JS::Rooted<JSObject*> deviceAddresses(cx);
     if (NS_FAILED(nsTArrayToJSArray(cx, mDeviceAddresses,
-                                    &mJsDeviceAddresses))) {
+                                    deviceAddresses.address()))) {
       NS_WARNING("Cannot set JS Devices object!");
       return;
     }
+    mJsDeviceAddresses = deviceAddresses;
     Root();
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling adapter property: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(name));
     NS_WARNING(warningMsg.get());
 #endif
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -67,16 +67,16 @@ private:
   bool mDiscovering;
   bool mPairable;
   bool mPowered;
   uint32_t mPairableTimeout;
   uint32_t mDiscoverableTimeout;
   uint32_t mClass;
   nsTArray<nsString> mDeviceAddresses;
   nsTArray<nsString> mUuids;
-  JSObject* mJsUuids;
-  JSObject* mJsDeviceAddresses;
+  JS::Heap<JSObject*> mJsUuids;
+  JS::Heap<JSObject*> mJsDeviceAddresses;
   bool mIsRooted;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothDevice.cpp
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -119,33 +119,37 @@ BluetoothDevice::SetPropertyByValue(cons
   } else if (name.EqualsLiteral("UUIDs")) {
     mUuids = value.get_ArrayOfnsString();
     nsresult rv;
     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     AutoPushJSContext cx(sc->GetNativeContext());
 
-    if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, &mJsUuids))) {
+    JS::Rooted<JSObject*> uuids(cx);
+    if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) {
       NS_WARNING("Cannot set JS UUIDs object!");
       return;
     }
+    mJsUuids = uuids;
     Root();
   } else if (name.EqualsLiteral("Services")) {
     mServices = value.get_ArrayOfnsString();
     nsresult rv;
     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     AutoPushJSContext cx(sc->GetNativeContext());
 
-    if (NS_FAILED(nsTArrayToJSArray(cx, mServices, &mJsServices))) {
+    JS::Rooted<JSObject*> services(cx);
+    if (NS_FAILED(nsTArrayToJSArray(cx, mServices, services.address()))) {
       NS_WARNING("Cannot set JS Services object!");
       return;
     }
+    mJsServices = services;
     Root();
   } else {
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling device property: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(name));
     NS_WARNING(warningMsg.get());
   }
 }
--- a/dom/bluetooth/BluetoothDevice.h
+++ b/dom/bluetooth/BluetoothDevice.h
@@ -53,18 +53,18 @@ public:
 
   void Unroot();
 private:
   BluetoothDevice(nsPIDOMWindow* aOwner, const nsAString& aAdapterPath,
                   const BluetoothValue& aValue);
   ~BluetoothDevice();
   void Root();
 
-  JSObject* mJsUuids;
-  JSObject* mJsServices;
+  JS::Heap<JSObject*> mJsUuids;
+  JS::Heap<JSObject*> mJsServices;
 
   nsString mAdapterPath;
   nsString mAddress;
   nsString mName;
   nsString mIcon;
   uint32_t mClass;
   bool mConnected;
   bool mPaired;
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -163,17 +163,17 @@ protected:
                const nsACString& aContinueQuery,
                const nsACString& aContinueToQuery);
 
   nsRefPtr<IDBRequest> mRequest;
   nsRefPtr<IDBTransaction> mTransaction;
   nsRefPtr<IDBObjectStore> mObjectStore;
   nsRefPtr<IDBIndex> mIndex;
 
-  JSObject* mScriptOwner;
+  JS::Heap<JSObject*> mScriptOwner;
 
   Type mType;
   Direction mDirection;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
 
   // These are cycle-collected!
   JS::Heap<JS::Value> mCachedKey;
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -178,17 +178,17 @@ private:
   Open(JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName,
        const Optional<uint64_t>& aVersion, bool aDelete, ErrorResult& aRv);
 
   nsCString mASCIIOrigin;
 
   // If this factory lives on a window then mWindow must be non-null. Otherwise
   // mOwningObject must be non-null.
   nsCOMPtr<nsPIDOMWindow> mWindow;
-  JSObject* mOwningObject;
+  JS::Heap<JSObject*> mOwningObject;
 
   IndexedDBChild* mActorChild;
   IndexedDBParent* mActorParent;
 
   mozilla::dom::ContentParent* mContentParent;
 
   bool mRootedOwningObject;
 };
--- a/dom/indexedDB/IDBWrapperCache.h
+++ b/dom/indexedDB/IDBWrapperCache.h
@@ -57,14 +57,14 @@ public:
 protected:
   IDBWrapperCache()
   : mScriptOwner(nullptr)
   { }
 
   virtual ~IDBWrapperCache();
 
 private:
-  JSObject* mScriptOwner;
+  JS::Heap<JSObject*> mScriptOwner;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbwrappercache_h__
--- a/dom/telephony/Telephony.h
+++ b/dom/telephony/Telephony.h
@@ -36,17 +36,17 @@ class Telephony : public nsDOMEventTarge
   nsCOMPtr<nsITelephonyProvider> mProvider;
   nsRefPtr<Listener> mListener;
 
   TelephonyCall* mActiveCall;
   nsTArray<nsRefPtr<TelephonyCall> > mCalls;
 
   // Cached calls array object. Cleared whenever mCalls changes and then rebuilt
   // once a page looks for the liveCalls attribute.
-  JSObject* mCallsArray;
+  JS::Heap<JSObject*> mCallsArray;
 
   bool mRooted;
   bool mEnumerated;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMTELEPHONY
   NS_DECL_NSITELEPHONYLISTENER
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -504,20 +504,20 @@ void XPCJSRuntime::TraceGrayJS(JSTracer*
 struct JsGcTracer : public TraceCallbacks
 {
     virtual void Trace(JS::Heap<JS::Value> *p, const char *name, void *closure) const MOZ_OVERRIDE {
         JS_CallHeapValueTracer(static_cast<JSTracer*>(closure), p, name);
     }
     virtual void Trace(JS::Heap<jsid> *p, const char *name, void *closure) const MOZ_OVERRIDE {
         JS_CallHeapIdTracer(static_cast<JSTracer*>(closure), p, name);
     }
-    virtual void Trace(JSObject **p, const char *name, void *closure) const MOZ_OVERRIDE {
-        JS_CallObjectTracer(static_cast<JSTracer*>(closure), p, name);
+    virtual void Trace(JS::Heap<JSObject *> *p, const char *name, void *closure) const MOZ_OVERRIDE {
+        JS_CallHeapObjectTracer(static_cast<JSTracer*>(closure), p, name);
     }
-    virtual void Trace(JS::Heap<JSString *>*p, const char *name, void *closure) const MOZ_OVERRIDE {
+    virtual void Trace(JS::Heap<JSString *> *p, const char *name, void *closure) const MOZ_OVERRIDE {
         JS_CallHeapStringTracer(static_cast<JSTracer*>(closure), p, name);
     }
     virtual void Trace(JS::Heap<JSScript *> *p, const char *name, void *closure) const MOZ_OVERRIDE {
         JS_CallHeapScriptTracer(static_cast<JSTracer*>(closure), p, name);
     }
 };
 
 static PLDHashOperator
--- a/xpcom/glue/nsCycleCollectionParticipant.cpp
+++ b/xpcom/glue/nsCycleCollectionParticipant.cpp
@@ -79,17 +79,17 @@ TraceCallbackFunc::Trace(JS::Heap<jsid>*
 {
   void *thing = JSID_TO_GCTHING(*p);
   if (thing) {
     mCallback(thing, name, closure);
   }
 }
 
 void
-TraceCallbackFunc::Trace(JSObject** p, const char* name, void* closure) const
+TraceCallbackFunc::Trace(JS::Heap<JSObject*>* p, const char* name, void* closure) const
 {
   mCallback(*p, name, closure);
 }
 
 void
 TraceCallbackFunc::Trace(JS::Heap<JSString*>* p, const char* name, void* closure) const
 {
   mCallback(*p, name, closure);
--- a/xpcom/glue/nsCycleCollectionParticipant.h
+++ b/xpcom/glue/nsCycleCollectionParticipant.h
@@ -59,34 +59,34 @@ template <class T> class Heap;
  * A struct defining pure virtual methods which are called when tracing cycle
  * collection paticipants.  The appropriate method is called depending on the
  * type of JS GC thing.
  */
 struct TraceCallbacks
 {
     virtual void Trace(JS::Heap<JS::Value>* p, const char* name, void* closure) const = 0;
     virtual void Trace(JS::Heap<jsid>* p, const char* name, void* closure) const = 0;
-    virtual void Trace(JSObject** p, const char* name, void* closure) const = 0;
+    virtual void Trace(JS::Heap<JSObject*>* p, const char* name, void* closure) const = 0;
     virtual void Trace(JS::Heap<JSString*>* p, const char* name, void* closure) const = 0;
     virtual void Trace(JS::Heap<JSScript*>* p, const char* name, void* closure) const = 0;
 };
 
 /*
  * An implementation of TraceCallbacks that calls a single function for all JS
  * GC thing types encountered.
  */
 struct TraceCallbackFunc : public TraceCallbacks
 {
     typedef void (* Func)(void* p, const char* name, void* closure);
 
     explicit TraceCallbackFunc(Func cb) : mCallback(cb) {}
 
     virtual void Trace(JS::Heap<JS::Value>* p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(JS::Heap<jsid>* p, const char* name, void* closure) const MOZ_OVERRIDE;
-    virtual void Trace(JSObject** p, const char* name, void* closure) const MOZ_OVERRIDE;
+    virtual void Trace(JS::Heap<JSObject*>* p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(JS::Heap<JSString*>* p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(JS::Heap<JSScript*>* p, const char* name, void* closure) const MOZ_OVERRIDE;
 
   private:
     Func mCallback;
 };
 
 /**