Bug 1105069 - Part 14: Convert NoteJSChild to GCCellPtr; r=mccr8, r=jonco
authorTerrence Cole <terrence@mozilla.com>
Fri, 05 Dec 2014 09:38:34 -0800
changeset 247531 bf0e4454f0d2afea829fcb1a8edd08881ce15e2d
parent 247530 0ee3fa1e76c673b8ff2788158a8cfc2782192083
child 247532 d67eb145b3c2a1aba3cff72b66dcfc6fe2ac81ba
push id698
push userjlund@mozilla.com
push dateMon, 23 Mar 2015 22:08:11 +0000
treeherdermozilla-release@b0c0ae7b02a3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8, jonco
bugs1105069
milestone37.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 1105069 - Part 14: Convert NoteJSChild to GCCellPtr; r=mccr8, r=jonco
dom/base/nsWrapperCache.cpp
dom/base/nsWrapperCacheInlines.h
dom/xbl/nsXBLDocumentInfo.cpp
js/public/Id.h
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/XPCWrappedJS.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/xpcprivate.h
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/CycleCollectedJSRuntime.h
xpcom/base/nsCycleCollector.cpp
xpcom/glue/nsCycleCollectionParticipant.cpp
xpcom/glue/nsCycleCollectionParticipant.h
xpcom/glue/nsCycleCollectionTraversalCallback.h
--- a/dom/base/nsWrapperCache.cpp
+++ b/dom/base/nsWrapperCache.cpp
@@ -38,76 +38,85 @@ nsWrapperCache::ReleaseWrapper(void* aSc
   }
 }
 
 #ifdef DEBUG
 
 class DebugWrapperTraversalCallback : public nsCycleCollectionTraversalCallback
 {
 public:
-  explicit DebugWrapperTraversalCallback(void* aWrapper)
+  explicit DebugWrapperTraversalCallback(JSObject* aWrapper)
     : mFound(false)
     , mWrapper(aWrapper)
   {
     mFlags = WANT_ALL_TRACES;
   }
 
   NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt aRefCount,
                                            const char* aObjName)
   {
   }
   NS_IMETHOD_(void) DescribeGCedNode(bool aIsMarked,
                                      const char* aObjName,
                                      uint64_t aCompartmentAddress)
   {
   }
 
-  NS_IMETHOD_(void) NoteJSChild(void* aChild)
+  NS_IMETHOD_(void) NoteJSObject(JSObject* aChild)
   {
     if (aChild == mWrapper) {
       mFound = true;
     }
   }
+  NS_IMETHOD_(void) NoteJSScript(JSScript* aChild)
+  {
+  }
   NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild)
   {
   }
   NS_IMETHOD_(void) NoteNativeChild(void* aChild,
                                     nsCycleCollectionParticipant* aHelper)
   {
   }
 
   NS_IMETHOD_(void) NoteNextEdgeName(const char* aName)
   {
   }
 
   bool mFound;
 
 private:
-  void* mWrapper;
+  JSObject* mWrapper;
 };
 
 static void
-DebugWrapperTraceCallback(void* aP, const char* aName, void* aClosure)
+DebugWrapperTraceCallback(JS::GCCellPtr aPtr, const char* aName, void* aClosure)
 {
   DebugWrapperTraversalCallback* callback =
     static_cast<DebugWrapperTraversalCallback*>(aClosure);
-  callback->NoteJSChild(aP);
+  if (aPtr.isObject()) {
+    callback->NoteJSObject(aPtr.toObject());
+  }
 }
 
 void
 nsWrapperCache::CheckCCWrapperTraversal(void* aScriptObjectHolder,
                                         nsScriptObjectTracer* aTracer)
 {
   JSObject* wrapper = GetWrapper();
   if (!wrapper) {
     return;
   }
 
   DebugWrapperTraversalCallback callback(wrapper);
 
+  // The CC traversal machinery cannot trigger GC; however, the analysis cannot
+  // see through the COM layer, so we use a suppression to help it.
+  JS::AutoSuppressGCAnalysis suppress;
+
   aTracer->Traverse(aScriptObjectHolder, callback);
   MOZ_ASSERT(callback.mFound,
              "Cycle collection participant didn't traverse to preserved "
              "wrapper! This will probably crash.");
 
   callback.mFound = false;
   aTracer->Trace(aScriptObjectHolder,
                  TraceCallbackFunc(DebugWrapperTraceCallback), &callback);
--- a/dom/base/nsWrapperCacheInlines.h
+++ b/dom/base/nsWrapperCacheInlines.h
@@ -23,20 +23,20 @@ nsWrapperCache::GetWrapper() const
 inline bool
 nsWrapperCache::IsBlack()
 {
   JSObject* o = GetWrapperPreserveColor();
   return o && !JS::GCThingIsMarkedGray(o);
 }
 
 static void
-SearchGray(void* aGCThing, const char* aName, void* aClosure)
+SearchGray(JS::GCCellPtr aGCThing, const char* aName, void* aClosure)
 {
   bool* hasGrayObjects = static_cast<bool*>(aClosure);
-  if (!*hasGrayObjects && aGCThing && JS::GCThingIsMarkedGray(aGCThing)) {
+  if (!*hasGrayObjects && aGCThing && JS::GCThingIsMarkedGray(aGCThing.asCell())) {
     *hasGrayObjects = true;
   }
 }
 
 inline bool
 nsWrapperCache::HasNothingToTrace(nsISupports* aThis)
 {
   nsXPCOMCycleCollectionParticipant* participant = nullptr;
--- a/dom/xbl/nsXBLDocumentInfo.cpp
+++ b/dom/xbl/nsXBLDocumentInfo.cpp
@@ -93,19 +93,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXBLDocumentInfo)
   if (tmp->mBindingTable) {
     ProtoTracer closure = { aCallbacks, aClosure };
     tmp->mBindingTable->EnumerateRead(TraceProtos, &closure);
   }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 static void
-UnmarkXBLJSObject(void* aP, const char* aName, void* aClosure)
+UnmarkXBLJSObject(JS::GCCellPtr aPtr, const char* aName, void* aClosure)
 {
-  JS::ExposeObjectToActiveJS(static_cast<JSObject*>(aP));
+  JS::ExposeObjectToActiveJS(aPtr.toObject());
 }
 
 static PLDHashOperator
 UnmarkProtos(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
 {
   aProto->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr);
   return PL_DHASH_NEXT;
 }
--- a/js/public/Id.h
+++ b/js/public/Id.h
@@ -134,20 +134,24 @@ SYMBOL_TO_JSID(JS::Symbol *sym)
 }
 
 static MOZ_ALWAYS_INLINE bool
 JSID_IS_GCTHING(jsid id)
 {
     return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id);
 }
 
-static MOZ_ALWAYS_INLINE void *
+static MOZ_ALWAYS_INLINE JS::GCCellPtr
 JSID_TO_GCTHING(jsid id)
 {
-    return (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
+    void *thing = (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
+    if (JSID_IS_STRING(id))
+        return JS::GCCellPtr(thing, JSTRACE_STRING);
+    MOZ_ASSERT(JSID_IS_SYMBOL(id));
+    return JS::GCCellPtr(thing, JSTRACE_SYMBOL);
 }
 
 static MOZ_ALWAYS_INLINE bool
 JSID_IS_VOID(const jsid id)
 {
     MOZ_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID,
                  JSID_BITS(id) == JSID_TYPE_VOID);
     return (size_t)JSID_BITS(id) == JSID_TYPE_VOID;
--- a/js/xpconnect/src/XPCVariant.cpp
+++ b/js/xpconnect/src/XPCVariant.cpp
@@ -78,19 +78,19 @@ XPCTraceableVariant::GetTraceName(JSTrac
 {
     JS_snprintf(buf, bufsize, "XPCVariant[0x%p].mJSVal", trc->debugPrintArg());
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(XPCVariant)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant)
     JS::Value val = tmp->GetJSValPreserveColor();
-    if (val.isObjectOrNull()) {
+    if (val.isObject()) {
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSVal");
-        cb.NoteJSChild(val.toObjectOrNull());
+        cb.NoteJSObject(&val.toObject());
     }
 
     nsVariant::Traverse(tmp->mData, cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant)
     JS::Value val = tmp->GetJSValPreserveColor();
 
--- a/js/xpconnect/src/XPCWrappedJS.cpp
+++ b/js/xpconnect/src/XPCWrappedJS.cpp
@@ -118,17 +118,17 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrapp
     // Don't let the extra reference for nsSupportsWeakReference keep a wrapper that is
     // not subject to finalization alive.
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "self");
     cb.NoteXPCOMChild(s);
 
     if (tmp->IsValid()) {
         MOZ_ASSERT(refcnt > 1);
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSObj");
-        cb.NoteJSChild(tmp->GetJSObjectPreserveColor());
+        cb.NoteJSObject(tmp->GetJSObjectPreserveColor());
     }
 
     if (tmp->IsRootWrapper()) {
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "aggregated native");
         cb.NoteXPCOMChild(tmp->GetAggregatedNativeObject());
     } else {
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "root");
         cb.NoteXPCOMChild(ToSupports(tmp->GetRootWrapper()));
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -72,17 +72,17 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrapped
         // considered "weak", and we're *not* going to traverse it.
         //
         // This reasoning is in line with the slightly confusing lifecycle rules
         // for XPCWrappedNatives, described in a larger comment below and also
         // on our wiki at http://wiki.mozilla.org/XPConnect_object_wrapping
 
         JSObject *obj = tmp->GetFlatJSObjectPreserveColor();
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFlatJSObject");
-        cb.NoteJSChild(obj);
+        cb.NoteJSObject(obj);
     }
 
     // XPCWrappedNative keeps its native object alive.
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mIdentity");
     cb.NoteXPCOMChild(tmp->GetIdentityObject());
 
     tmp->NoteTearoffs(cb);
 
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -238,22 +238,16 @@ static inline bool IS_WN_REFLECTOR(JSObj
 ****************************************************************************
 ***************************************************************************/
 
 // We have a general rule internally that getters that return addref'd interface
 // pointer generally do so using an 'out' parm. When interface pointers are
 // returned as function call result values they are not addref'd. Exceptions
 // to this rule are noted explicitly.
 
-inline bool
-AddToCCKind(JSGCTraceKind kind)
-{
-    return kind == JSTRACE_OBJECT || kind == JSTRACE_SCRIPT;
-}
-
 class nsXPConnect : public nsIXPConnect,
                     public nsIThreadObserver,
                     public nsSupportsWeakReference,
                     public nsIJSRuntimeService
 {
 public:
     // all the interface method declarations...
     NS_DECL_ISUPPORTS
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -114,22 +114,16 @@ public:
 
   void ReleaseNow(bool aLimited);
 
   NS_DECL_NSIRUNNABLE
 };
 
 } // namespace mozilla
 
-inline bool
-AddToCCKind(JSGCTraceKind aKind)
-{
-  return aKind == JSTRACE_OBJECT || aKind == JSTRACE_SCRIPT;
-}
-
 static void
 TraceWeakMappingChild(JSTracer* aTrc, void** aThingp, JSGCTraceKind aKind);
 
 struct NoteWeakMapChildrenTracer : public JSTracer
 {
   NoteWeakMapChildrenTracer(JSRuntime* aRt,
                             nsCycleCollectionNoteRootCallback& aCb)
     : JSTracer(aRt, TraceWeakMappingChild), mCb(aCb), mTracedAny(false),
@@ -303,27 +297,27 @@ struct Closure
   {
   }
 
   bool mCycleCollectionEnabled;
   nsCycleCollectionNoteRootCallback* mCb;
 };
 
 static void
-CheckParticipatesInCycleCollection(void* aThing, const char* aName,
+CheckParticipatesInCycleCollection(JS::GCCellPtr aThing, const char* aName,
                                    void* aClosure)
 {
   Closure* closure = static_cast<Closure*>(aClosure);
 
   if (closure->mCycleCollectionEnabled) {
     return;
   }
 
-  if (AddToCCKind(js::GCThingTraceKind(aThing)) &&
-      xpc_IsGrayGCThing(aThing)) {
+  if (AddToCCKind(aThing.kind()) &&
+      xpc_IsGrayGCThing(aThing.asCell())) {
     closure->mCycleCollectionEnabled = true;
   }
 }
 
 static PLDHashOperator
 NoteJSHolder(void* aHolder, nsScriptObjectTracer*& aTracer, void* aArg)
 {
   Closure* closure = static_cast<Closure*>(aArg);
@@ -419,17 +413,22 @@ NoteJSChild(JSTracer* aTrc, void* aThing
         JS_snprintf(buffer, sizeof(buffer), "%s[%lu]",
                     static_cast<const char*>(tracer->debugPrintArg()),
                     tracer->debugPrintIndex());
         tracer->mCb.NoteNextEdgeName(buffer);
       } else {
         tracer->mCb.NoteNextEdgeName(static_cast<const char*>(tracer->debugPrintArg()));
       }
     }
-    tracer->mCb.NoteJSChild(aThing);
+    JS::GCCellPtr thing(aThing, aTraceKind);
+    if (thing.isObject()) {
+      tracer->mCb.NoteJSObject(thing.toObject());
+    } else {
+      tracer->mCb.NoteJSScript(thing.toScript());
+    }
   } else if (aTraceKind == JSTRACE_SHAPE) {
     JS_TraceShapeCycleCollectorChildren(aTrc, aThing);
   } else if (aTraceKind != JSTRACE_STRING) {
     JS_TraceChildren(aTrc, aThing, aTraceKind);
   }
 }
 
 static void
@@ -910,17 +909,17 @@ CycleCollectedJSRuntime::RemoveJSHolder(
 #ifdef DEBUG
 bool
 CycleCollectedJSRuntime::IsJSHolder(void* aHolder)
 {
   return mJSHolders.Get(aHolder, nullptr);
 }
 
 static void
-AssertNoGcThing(void* aGCThing, const char* aName, void* aClosure)
+AssertNoGcThing(JS::GCCellPtr aGCThing, const char* aName, void* aClosure)
 {
   MOZ_ASSERT(!aGCThing);
 }
 
 void
 CycleCollectedJSRuntime::AssertNoObjectsToTrace(void* aPossibleJSHolder)
 {
   nsScriptObjectTracer* tracer = mJSHolders.Get(aPossibleJSHolder);
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -329,11 +329,17 @@ private:
 
   nsTHashtable<nsPtrHashKey<JS::Zone>> mZonesWaitingForGC;
 };
 
 MOZ_FINISH_NESTED_ENUM_CLASS(CycleCollectedJSRuntime::OOMState)
 
 void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer);
 
+// Returns true if the JSGCTraceKind is one the cycle collector cares about.
+inline bool AddToCCKind(JSGCTraceKind aKind)
+{
+  return aKind == JSTRACE_OBJECT || aKind == JSTRACE_SCRIPT;
+}
+
 } // namespace mozilla
 
 #endif // mozilla_CycleCollectedJSRuntime_h__
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -2077,22 +2077,25 @@ public:
 
   // nsCycleCollectionTraversalCallback methods.
   NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt aRefCount,
                                            const char* aObjName);
   NS_IMETHOD_(void) DescribeGCedNode(bool aIsMarked, const char* aObjName,
                                      uint64_t aCompartmentAddress);
 
   NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild);
-  NS_IMETHOD_(void) NoteJSChild(void* aChild);
+  NS_IMETHOD_(void) NoteJSObject(JSObject* aChild);
+  NS_IMETHOD_(void) NoteJSScript(JSScript* aChild);
   NS_IMETHOD_(void) NoteNativeChild(void* aChild,
                                     nsCycleCollectionParticipant* aParticipant);
   NS_IMETHOD_(void) NoteNextEdgeName(const char* aName);
 
 private:
+  void NoteJSChild(JS::GCCellPtr aChild);
+
   NS_IMETHOD_(void) NoteRoot(void* aRoot,
                              nsCycleCollectionParticipant* aParticipant)
   {
     MOZ_ASSERT(aRoot);
     MOZ_ASSERT(aParticipant);
 
     if (!aParticipant->CanSkipInCC(aRoot) || MOZ_UNLIKELY(WantAllTraces())) {
       AddNode(aRoot, aParticipant);
@@ -2313,33 +2316,45 @@ CCGraphBuilder::NoteNativeChild(void* aC
 
   MOZ_ASSERT(aParticipant, "Need a nsCycleCollectionParticipant!");
   if (!aParticipant->CanSkipThis(aChild) || WantAllTraces()) {
     NoteChild(aChild, aParticipant, edgeName);
   }
 }
 
 NS_IMETHODIMP_(void)
-CCGraphBuilder::NoteJSChild(void* aChild)
+CCGraphBuilder::NoteJSObject(JSObject* aChild)
+{
+  return NoteJSChild(JS::GCCellPtr(aChild));
+}
+
+NS_IMETHODIMP_(void)
+CCGraphBuilder::NoteJSScript(JSScript* aChild)
+{
+  return NoteJSChild(JS::GCCellPtr(aChild));
+}
+
+void
+CCGraphBuilder::NoteJSChild(JS::GCCellPtr aChild)
 {
   if (!aChild) {
     return;
   }
 
   nsCString edgeName;
   if (MOZ_UNLIKELY(WantDebugInfo())) {
     edgeName.Assign(mNextEdgeName);
     mNextEdgeName.Truncate();
   }
 
-  if (xpc_GCThingIsGrayCCThing(aChild) || MOZ_UNLIKELY(WantAllTraces())) {
-    if (JS::Zone* zone = MergeZone(aChild)) {
+  if (xpc_GCThingIsGrayCCThing(aChild.asCell()) || MOZ_UNLIKELY(WantAllTraces())) {
+    if (JS::Zone* zone = MergeZone(aChild.asCell())) {
       NoteChild(zone, mJSZoneParticipant, edgeName);
     } else {
-      NoteChild(aChild, mJSParticipant, edgeName);
+      NoteChild(aChild.asCell(), mJSParticipant, edgeName);
     }
   }
 }
 
 NS_IMETHODIMP_(void)
 CCGraphBuilder::NoteNextEdgeName(const char* aName)
 {
   if (WantDebugInfo()) {
@@ -2405,17 +2420,18 @@ public:
   {
   }
 
   // The logic of the Note*Child functions must mirror that of their
   // respective functions in CCGraphBuilder.
   NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild);
   NS_IMETHOD_(void) NoteNativeChild(void* aChild,
                                     nsCycleCollectionParticipant* aHelper);
-  NS_IMETHOD_(void) NoteJSChild(void* aChild);
+  NS_IMETHOD_(void) NoteJSObject(JSObject* aChild);
+  NS_IMETHOD_(void) NoteJSScript(JSScript* aChild);
 
   NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt aRefcount,
                                            const char* aObjname)
   {
   }
   NS_IMETHOD_(void) DescribeGCedNode(bool aIsMarked,
                                      const char* aObjname,
                                      uint64_t aCompartmentAddress)
@@ -2454,17 +2470,25 @@ ChildFinder::NoteNativeChild(void* aChil
   }
   MOZ_ASSERT(aHelper, "Native child must have a participant");
   if (!aHelper->CanSkip(aChild, true)) {
     mMayHaveChild = true;
   }
 }
 
 NS_IMETHODIMP_(void)
-ChildFinder::NoteJSChild(void* aChild)
+ChildFinder::NoteJSObject(JSObject* aChild)
+{
+  if (aChild && xpc_GCThingIsGrayCCThing(aChild)) {
+    mMayHaveChild = true;
+  }
+}
+
+NS_IMETHODIMP_(void)
+ChildFinder::NoteJSScript(JSScript* aChild)
 {
   if (aChild && xpc_GCThingIsGrayCCThing(aChild)) {
     mMayHaveChild = true;
   }
 }
 
 static bool
 MayHaveChild(void* aObj, nsCycleCollectionParticipant* aCp)
--- a/xpcom/glue/nsCycleCollectionParticipant.cpp
+++ b/xpcom/glue/nsCycleCollectionParticipant.cpp
@@ -1,32 +1,40 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "nsCycleCollectionParticipant.h"
+#include "mozilla/CycleCollectedJSRuntime.h"
 #include "nsCOMPtr.h"
 #include "jsapi.h"
+#include "jsfriendapi.h"
 
 #ifdef MOZILLA_INTERNAL_API
 #include "nsString.h"
 #else
 #include "nsStringAPI.h"
 #endif
 
 void
-nsScriptObjectTracer::NoteJSChild(void* aScriptThing, const char* aName,
+nsScriptObjectTracer::NoteJSChild(JS::GCCellPtr aGCThing, const char* aName,
                                   void* aClosure)
 {
   nsCycleCollectionTraversalCallback* cb =
     static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, aName);
-  cb->NoteJSChild(aScriptThing);
+  if (aGCThing.isObject()) {
+    cb->NoteJSObject(aGCThing.toObject());
+  } else if (aGCThing.isScript()) {
+    cb->NoteJSScript(aGCThing.toScript());
+  } else {
+    MOZ_ASSERT(!mozilla::AddToCCKind(aGCThing.kind()));
+  }
 }
 
 NS_IMETHODIMP_(void)
 nsXPCOMCycleCollectionParticipant::Root(void* aPtr)
 {
   nsISupports* s = static_cast<nsISupports*>(aPtr);
   NS_ADDREF(s);
 }
@@ -67,56 +75,55 @@ CycleCollectionNoteEdgeNameImpl(nsCycleC
   aCallback.NoteNextEdgeName(arrayEdgeName.get());
 }
 
 void
 TraceCallbackFunc::Trace(JS::Heap<JS::Value>* aPtr, const char* aName,
                          void* aClosure) const
 {
   if (aPtr->isMarkable()) {
-    mCallback(aPtr->toGCThing(), aName, aClosure);
+    mCallback(JS::GCCellPtr(*aPtr), aName, aClosure);
   }
 }
 
 void
 TraceCallbackFunc::Trace(JS::Heap<jsid>* aPtr, const char* aName,
                          void* aClosure) const
 {
-  void* thing = JSID_TO_GCTHING(*aPtr);
-  if (thing) {
-    mCallback(thing, aName, aClosure);
+  if (JSID_IS_GCTHING(*aPtr)) {
+    mCallback(JSID_TO_GCTHING(*aPtr), aName, aClosure);
   }
 }
 
 void
 TraceCallbackFunc::Trace(JS::Heap<JSObject*>* aPtr, const char* aName,
                          void* aClosure) const
 {
-  mCallback(*aPtr, aName, aClosure);
+  mCallback(JS::GCCellPtr(*aPtr), aName, aClosure);
 }
 
 void
 TraceCallbackFunc::Trace(JS::TenuredHeap<JSObject*>* aPtr, const char* aName,
                          void* aClosure) const
 {
-  mCallback(*aPtr, aName, aClosure);
+  mCallback(JS::GCCellPtr(*aPtr), aName, aClosure);
 }
 
 void
 TraceCallbackFunc::Trace(JS::Heap<JSFunction*>* aPtr, const char* aName,
                          void* aClosure) const
 {
-  mCallback(*aPtr, aName, aClosure);
+  mCallback(JS::GCCellPtr(*aPtr), aName, aClosure);
 }
 
 void
 TraceCallbackFunc::Trace(JS::Heap<JSString*>* aPtr, const char* aName,
                          void* aClosure) const
 {
-  mCallback(*aPtr, aName, aClosure);
+  mCallback(JS::GCCellPtr(*aPtr), aName, aClosure);
 }
 
 void
 TraceCallbackFunc::Trace(JS::Heap<JSScript*>* aPtr, const char* aName,
                          void* aClosure) const
 {
-  mCallback(aPtr->get(), aName, aClosure);
+  mCallback(JS::GCCellPtr(*aPtr), aName, aClosure);
 }
--- a/xpcom/glue/nsCycleCollectionParticipant.h
+++ b/xpcom/glue/nsCycleCollectionParticipant.h
@@ -75,17 +75,17 @@ struct TraceCallbacks
 };
 
 /*
  * An implementation of TraceCallbacks that calls a single function for all JS
  * GC thing types encountered.
  */
 struct TraceCallbackFunc : public TraceCallbacks
 {
-  typedef void (*Func)(void* aPtr, const char* aName, void* aClosure);
+  typedef void (*Func)(JS::GCCellPtr aPtr, const char* aName, void* aClosure);
 
   explicit TraceCallbackFunc(Func aCb) : mCallback(aCb) {}
 
   virtual void Trace(JS::Heap<JS::Value>* aPtr, const char* aName,
                      void* aClosure) const MOZ_OVERRIDE;
   virtual void Trace(JS::Heap<jsid>* aPtr, const char* aName,
                      void* aClosure) const MOZ_OVERRIDE;
   virtual void Trace(JS::Heap<JSObject*>* aPtr, const char* aName,
@@ -179,17 +179,17 @@ public:
   MOZ_CONSTEXPR explicit nsScriptObjectTracer(bool aSkip)
     : nsCycleCollectionParticipant(aSkip)
   {
   }
 
   NS_IMETHOD_(void) Trace(void* aPtr, const TraceCallbacks& aCb,
                           void* aClosure) = 0;
 
-  static void NoteJSChild(void* aScriptThing, const char* aName,
+  static void NoteJSChild(JS::GCCellPtr aGCThing, const char* aName,
                           void* aClosure);
 };
 
 class NS_NO_VTABLE nsXPCOMCycleCollectionParticipant : public nsScriptObjectTracer
 {
 public:
   MOZ_CONSTEXPR nsXPCOMCycleCollectionParticipant()
     : nsScriptObjectTracer(false)
--- a/xpcom/glue/nsCycleCollectionTraversalCallback.h
+++ b/xpcom/glue/nsCycleCollectionTraversalCallback.h
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 nsCycleCollectionTraversalCallback_h__
 #define nsCycleCollectionTraversalCallback_h__
 
+#include "jspubtd.h"
 #include "nsISupports.h"
 
 class nsCycleCollectionParticipant;
 
 class NS_NO_VTABLE nsCycleCollectionTraversalCallback
 {
 public:
   // You must call DescribeRefCountedNode() with an accurate
@@ -21,22 +22,23 @@ public:
   NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt aRefcount,
                                            const char* aObjName) = 0;
   // Note, aCompartmentAddress is 0 if it is unknown.
   NS_IMETHOD_(void) DescribeGCedNode(bool aIsMarked,
                                      const char* aObjName,
                                      uint64_t aCompartmentAddress = 0) = 0;
 
   NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild) = 0;
-  NS_IMETHOD_(void) NoteJSChild(void* aChild) = 0;
+  NS_IMETHOD_(void) NoteJSObject(JSObject* aChild) = 0;
+  NS_IMETHOD_(void) NoteJSScript(JSScript* aChild) = 0;
   NS_IMETHOD_(void) NoteNativeChild(void* aChild,
                                     nsCycleCollectionParticipant* aHelper) = 0;
 
   // Give a name to the edge associated with the next call to
-  // NoteXPCOMChild, NoteJSChild, or NoteNativeChild.
+  // NoteXPCOMChild, NoteJSObject, NoteJSScript, or NoteNativeChild.
   // Callbacks who care about this should set WANT_DEBUG_INFO in the
   // flags.
   NS_IMETHOD_(void) NoteNextEdgeName(const char* aName) = 0;
 
   enum
   {
     // Values for flags: