Bug 1105069 - Part 17: Convert xpc_IsGrayGCThing to GCCellPtr; r=mccr8, j=jonco
authorTerrence Cole <terrence@mozilla.com>
Fri, 05 Dec 2014 09:38:34 -0800
changeset 220013 c7d90ce714c9981d99446601fb8f4d4da851cfaa
parent 220012 68386a0e19d0a1dd03cf57388c5fe5e4009ed915
child 220014 bc3fbb01003dfa973033635bbc3ca7f5cad2dcb6
push id27974
push userdgohman@mozilla.com
push dateWed, 17 Dec 2014 00:41:35 +0000
treeherdermozilla-central@b7eb1ce0237d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
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 17: Convert xpc_IsGrayGCThing to GCCellPtr; r=mccr8, j=jonco
dom/base/FragmentOrElement.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsWrapperCacheInlines.h
dom/bindings/CallbackFunction.h
js/public/GCAPI.h
js/public/HeapAPI.h
js/public/Value.h
js/src/jsfriendapi.cpp
js/src/jsgc.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCWrappedJS.cpp
js/xpconnect/src/xpcpublic.h
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/nsCycleCollector.cpp
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1615,17 +1615,17 @@ void ClearCycleCollectorCleanupData()
 static bool
 ShouldClearPurple(nsIContent* aContent)
 {
   if (aContent && aContent->IsPurple()) {
     return true;
   }
 
   JSObject* o = GetJSObjectChild(aContent);
-  if (o && xpc_IsGrayGCThing(o)) {
+  if (o && JS::ObjectIsMarkedGray(o)) {
     return true;
   }
 
   if (aContent->HasListenerManager()) {
     return true;
   }
 
   return aContent->HasProperties();
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1908,17 +1908,18 @@ nsGlobalWindow::UnmarkGrayTimers()
   for (nsTimeout* timeout = mTimeouts.getFirst();
        timeout;
        timeout = timeout->getNext()) {
     if (timeout->mScriptHandler) {
       Function* f = timeout->mScriptHandler->GetCallback();
       if (f) {
         // Callable() already does xpc_UnmarkGrayObject.
         DebugOnly<JS::Handle<JSObject*> > o = f->Callable();
-        MOZ_ASSERT(!xpc_IsGrayGCThing(o.value), "Should have been unmarked");
+        MOZ_ASSERT(!JS::ObjectIsMarkedGray(o.value),
+                   "Should have been unmarked");
       }
     }
   }
 }
 
 //*****************************************************************************
 // nsGlobalWindow::nsIScriptGlobalObject
 //*****************************************************************************
--- a/dom/base/nsWrapperCacheInlines.h
+++ b/dom/base/nsWrapperCacheInlines.h
@@ -19,24 +19,24 @@ nsWrapperCache::GetWrapper() const
     }
     return obj;
 }
 
 inline bool
 nsWrapperCache::IsBlack()
 {
   JSObject* o = GetWrapperPreserveColor();
-  return o && !JS::GCThingIsMarkedGray(o);
+  return o && !JS::ObjectIsMarkedGray(o);
 }
 
 static void
 SearchGray(JS::GCCellPtr aGCThing, const char* aName, void* aClosure)
 {
   bool* hasGrayObjects = static_cast<bool*>(aClosure);
-  if (!*hasGrayObjects && aGCThing && JS::GCThingIsMarkedGray(aGCThing.asCell())) {
+  if (!*hasGrayObjects && aGCThing && JS::GCThingIsMarkedGray(aGCThing)) {
     *hasGrayObjects = true;
   }
 }
 
 inline bool
 nsWrapperCache::HasNothingToTrace(nsISupports* aThis)
 {
   nsXPCOMCycleCollectionParticipant* participant = nullptr;
--- a/dom/bindings/CallbackFunction.h
+++ b/dom/bindings/CallbackFunction.h
@@ -34,17 +34,17 @@ public:
   JS::Handle<JSObject*> Callable() const
   {
     return Callback();
   }
 
   bool HasGrayCallable() const
   {
     // Play it safe in case this gets called after unlink.
-    return mCallback && xpc_IsGrayGCThing(mCallback);
+    return mCallback && JS::ObjectIsMarkedGray(mCallback);
   }
 
 protected:
   explicit CallbackFunction(CallbackFunction* aCallbackFunction)
     : CallbackObject(aCallbackFunction)
   {
   }
 };
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -503,17 +503,17 @@ ExposeGCThingToActiveJS(JS::GCCellPtr th
      * All live objects in the nursery are moved to tenured at the beginning of
      * each GC slice, so the gray marker never sees nursery things.
      */
     if (IsInsideNursery(thing.asCell()))
         return;
     JS::shadow::Runtime *rt = detail::GetGCThingRuntime(thing.unsafeAsUIntPtr());
     if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing))
         JS::IncrementalReferenceBarrier(thing);
-    else if (JS::GCThingIsMarkedGray(thing.asCell()))
+    else if (JS::GCThingIsMarkedGray(thing))
         JS::UnmarkGrayGCThingRecursively(thing);
 }
 
 static MOZ_ALWAYS_INLINE void
 MarkGCThingAsLive(JSRuntime *aRt, JS::GCCellPtr thing)
 {
     JS::shadow::Runtime *rt = JS::shadow::Runtime::asShadowRuntime(aRt);
     /*
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -341,16 +341,26 @@ GetGCThingMarkWordAndMask(const uintptr_
 
 static MOZ_ALWAYS_INLINE JS::shadow::ArenaHeader *
 GetGCThingArena(const uintptr_t addr)
 {
     MOZ_ASSERT(addr);
     return reinterpret_cast<JS::shadow::ArenaHeader *>(addr & ~ArenaMask);
 }
 
+static MOZ_ALWAYS_INLINE bool
+CellIsMarkedGray(const Cell *cell)
+{
+    MOZ_ASSERT(cell);
+    MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
+    uintptr_t *word, mask;
+    js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(cell), js::gc::GRAY, &word, &mask);
+    return *word & mask;
+}
+
 } /* namespace detail */
 
 MOZ_ALWAYS_INLINE bool
 IsInsideNursery(const js::gc::Cell *cell)
 {
     if (!cell)
         return false;
     uintptr_t addr = uintptr_t(cell);
@@ -373,41 +383,40 @@ GetTenuredGCThingZone(void *thing)
     MOZ_ASSERT(!js::gc::IsInsideNursery((js::gc::Cell *)thing));
     return js::gc::detail::GetGCThingArena(uintptr_t(thing))->zone;
 }
 
 extern JS_PUBLIC_API(Zone *)
 GetObjectZone(JSObject *obj);
 
 static MOZ_ALWAYS_INLINE bool
-GCThingIsMarkedGray(void *thing)
+ObjectIsMarkedGray(JSObject *obj)
 {
-    MOZ_ASSERT(thing);
     /*
      * GC things residing in the nursery cannot be gray: they have no mark bits.
      * All live objects in the nursery are moved to tenured at the beginning of
      * each GC slice, so the gray marker never sees nursery things.
      */
-    if (js::gc::IsInsideNursery((js::gc::Cell *)thing))
+    if (js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell *>(obj)))
         return false;
-    uintptr_t *word, mask;
-    js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(thing), js::gc::GRAY, &word, &mask);
-    return *word & mask;
-}
-
-static MOZ_ALWAYS_INLINE bool
-ObjectIsMarkedGray(JSObject *obj)
-{
-    return GCThingIsMarkedGray(obj);
+    return js::gc::detail::CellIsMarkedGray(reinterpret_cast<js::gc::Cell *>(obj));
 }
 
 static MOZ_ALWAYS_INLINE bool
 ScriptIsMarkedGray(JSScript *script)
 {
-    return GCThingIsMarkedGray(script);
+    return js::gc::detail::CellIsMarkedGray(reinterpret_cast<js::gc::Cell *>(script));
+}
+
+static MOZ_ALWAYS_INLINE bool
+GCThingIsMarkedGray(GCCellPtr thing)
+{
+    if (js::gc::IsInsideNursery(thing.asCell()))
+        return false;
+    return js::gc::detail::CellIsMarkedGray(thing.asCell());
 }
 
 } /* namespace JS */
 
 namespace js {
 namespace gc {
 
 static MOZ_ALWAYS_INLINE bool
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -1246,16 +1246,20 @@ class Value
         return JSVAL_TO_OBJECT_IMPL(data);
     }
 
     js::gc::Cell *toGCThing() const {
         MOZ_ASSERT(isGCThing());
         return JSVAL_TO_GCTHING_IMPL(data);
     }
 
+    GCCellPtr toGCCellPtr() const {
+        return GCCellPtr(toGCThing(), gcKind());
+    }
+
     bool toBoolean() const {
         MOZ_ASSERT(isBoolean());
         return JSVAL_TO_BOOLEAN_IMPL(data);
     }
 
     uint32_t payloadAsRawUint32() const {
         MOZ_ASSERT(!isDouble());
         return data.s.payload.u32;
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -634,17 +634,17 @@ js::AreGCGrayBitsValid(JSRuntime *rt)
     return rt->gc.areGrayBitsValid();
 }
 
 JS_FRIEND_API(bool)
 js::ZoneGlobalsAreAllGray(JS::Zone *zone)
 {
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
         JSObject *obj = comp->maybeGlobal();
-        if (!obj || !JS::GCThingIsMarkedGray(obj))
+        if (!obj || !JS::ObjectIsMarkedGray(obj))
             return false;
     }
     return true;
 }
 
 JS_FRIEND_API(JSGCTraceKind)
 js::GCThingTraceKind(void *thing)
 {
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -825,18 +825,18 @@ void Chunk::decommitAllArenas(JSRuntime 
 }
 
 void
 Chunk::init(JSRuntime *rt)
 {
     JS_POISON(this, JS_FRESH_TENURED_PATTERN, ChunkSize);
 
     /*
-     * We clear the bitmap to guard against xpc_IsGrayGCThing being called on
-     * uninitialized data, which would happen before the first GC cycle.
+     * We clear the bitmap to guard against JS::GCThingIsMarkedGray being called
+     * on uninitialized data, which would happen before the first GC cycle.
      */
     bitmap.clear();
 
     /*
      * Decommit the arenas. We do this after poisoning so that if the OS does
      * not have to recycle the pages, we still get the benefit of poisoning.
      */
     decommitAllArenas(rt);
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -647,31 +647,31 @@ XPCJSRuntime::SuspectWrappedNative(XPCWr
         return;
 
     MOZ_ASSERT(NS_IsMainThread(),
                "Suspecting wrapped natives from non-main thread");
 
     // Only record objects that might be part of a cycle as roots, unless
     // the callback wants all traces (a debug feature).
     JSObject* obj = wrapper->GetFlatJSObjectPreserveColor();
-    if (xpc_IsGrayGCThing(obj) || cb.WantAllTraces())
+    if (JS::ObjectIsMarkedGray(obj) || cb.WantAllTraces())
         cb.NoteJSRoot(obj);
 }
 
 void
 XPCJSRuntime::TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback &cb)
 {
     XPCWrappedNativeScope::SuspectAllWrappers(this, cb);
 
     for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot()) {
         XPCTraceableVariant* v = static_cast<XPCTraceableVariant*>(e);
         if (nsCCUncollectableMarker::InGeneration(cb,
                                                   v->CCGeneration())) {
-           jsval val = v->GetJSValPreserveColor();
-           if (val.isObject() && !xpc_IsGrayGCThing(&val.toObject()))
+           JS::Value val = v->GetJSValPreserveColor();
+           if (val.isObject() && !JS::ObjectIsMarkedGray(&val.toObject()))
                continue;
         }
         cb.NoteXPCOMRoot(v);
     }
 
     for (XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot()) {
         cb.NoteXPCOMRoot(ToSupports(static_cast<nsXPCWrappedJS*>(e)));
     }
--- a/js/xpconnect/src/XPCWrappedJS.cpp
+++ b/js/xpconnect/src/XPCWrappedJS.cpp
@@ -60,17 +60,17 @@ nsXPCWrappedJS::CanSkip()
     if (!nsCCUncollectableMarker::sGeneration)
         return false;
 
     if (IsSubjectToFinalization())
         return true;
 
     // If this wrapper holds a gray object, need to trace it.
     JSObject *obj = GetJSObjectPreserveColor();
-    if (obj && xpc_IsGrayGCThing(obj))
+    if (obj && JS::ObjectIsMarkedGray(obj))
         return false;
 
     // For non-root wrappers, check if the root wrapper will be
     // added to the CC graph.
     if (!IsRootWrapper()) {
         // mRoot points to null after unlinking.
         NS_ENSURE_TRUE(mRoot, false);
         return mRoot->CanSkip();
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -171,25 +171,16 @@ xpc_FastGetCachedWrapper(JSContext *cx, 
             vp.setObject(*wrapper);
             return wrapper;
         }
     }
 
     return nullptr;
 }
 
-// The JS GC marks objects gray that are held alive directly or
-// indirectly by an XPConnect root. The cycle collector explores only
-// this subset of the JS heap.
-inline bool
-xpc_IsGrayGCThing(void *thing)
-{
-    return JS::GCThingIsMarkedGray(thing);
-}
-
 inline JSScript *
 xpc_UnmarkGrayScript(JSScript *script)
 {
     if (script)
         JS::ExposeScriptToActiveJS(script);
 
     return script;
 }
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -136,35 +136,34 @@ struct NoteWeakMapChildrenTracer : publi
   JS::GCCellPtr mKey;
   JSObject* mKeyDelegate;
 };
 
 static void
 TraceWeakMappingChild(JSTracer* aTrc, void** aThingp, JSGCTraceKind aKind)
 {
   MOZ_ASSERT(aTrc->callback == TraceWeakMappingChild);
-  void* thing = *aThingp;
   NoteWeakMapChildrenTracer* tracer =
     static_cast<NoteWeakMapChildrenTracer*>(aTrc);
+  JS::GCCellPtr thing(*aThingp, aKind);
 
-  if (aKind == JSTRACE_STRING) {
+  if (thing.isString()) {
     return;
   }
 
-  if (!xpc_IsGrayGCThing(thing) && !tracer->mCb.WantAllTraces()) {
+  if (!JS::GCThingIsMarkedGray(thing) && !tracer->mCb.WantAllTraces()) {
     return;
   }
 
-  if (AddToCCKind(aKind)) {
+  if (AddToCCKind(thing.kind())) {
     tracer->mCb.NoteWeakMapping(tracer->mMap, tracer->mKey,
-                                tracer->mKeyDelegate,
-                                JS::GCCellPtr(thing, aKind));
+                                tracer->mKeyDelegate, thing);
     tracer->mTracedAny = true;
   } else {
-    JS_TraceChildren(aTrc, thing, aKind);
+    JS_TraceChildren(aTrc, thing.asCell(), thing.kind());
   }
 }
 
 struct NoteWeakMapsTracer : public js::WeakMapTracer
 {
   NoteWeakMapsTracer(JSRuntime* aRt, js::WeakMapTraceCallback aCb,
                      nsCycleCollectionNoteRootCallback& aCccb)
     : js::WeakMapTracer(aRt, aCb), mCb(aCccb), mChildTracer(aRt, aCccb)
@@ -177,19 +176,19 @@ struct NoteWeakMapsTracer : public js::W
 static void
 TraceWeakMapping(js::WeakMapTracer* aTrc, JSObject* aMap,
                  JS::GCCellPtr aKey, JS::GCCellPtr aValue)
 {
   MOZ_ASSERT(aTrc->callback == TraceWeakMapping);
   NoteWeakMapsTracer* tracer = static_cast<NoteWeakMapsTracer*>(aTrc);
 
   // If nothing that could be held alive by this entry is marked gray, return.
-  if ((!aKey || !xpc_IsGrayGCThing(aKey.asCell())) &&
+  if ((!aKey || !JS::GCThingIsMarkedGray(aKey)) &&
       MOZ_LIKELY(!tracer->mCb.WantAllTraces())) {
-    if (!aValue || !xpc_IsGrayGCThing(aValue.asCell()) || aValue.isString()) {
+    if (!aValue || !JS::GCThingIsMarkedGray(aValue) || aValue.isString()) {
       return;
     }
   }
 
   // The cycle collector can only properly reason about weak maps if it can
   // reason about the liveness of their keys, which in turn requires that
   // the key can be represented in the cycle collector graph.  All existing
   // uses of weak maps use either objects or scripts as keys, which are okay.
@@ -218,17 +217,17 @@ TraceWeakMapping(js::WeakMapTracer* aTrc
 
     if (aValue.isString()) {
       JS_TraceChildren(&tracer->mChildTracer, aValue.asCell(), aValue.kind());
     }
 
     // The delegate could hold alive the key, so report something to the CC
     // if we haven't already.
     if (!tracer->mChildTracer.mTracedAny &&
-        aKey && xpc_IsGrayGCThing(aKey.asCell()) && kdelegate) {
+        aKey && JS::GCThingIsMarkedGray(aKey) && kdelegate) {
       tracer->mCb.NoteWeakMapping(aMap, aKey, kdelegate,
                                   JS::GCCellPtr::NullPtr());
     }
   }
 }
 
 // This is based on the logic in TraceWeakMapping.
 struct FixWeakMappingGrayBitsTracer : public js::WeakMapTracer
@@ -252,39 +251,39 @@ private:
   static void
   FixWeakMappingGrayBits(js::WeakMapTracer* aTrc, JSObject* aMap,
                          JS::GCCellPtr aKey, JS::GCCellPtr aValue)
   {
     FixWeakMappingGrayBitsTracer* tracer =
       static_cast<FixWeakMappingGrayBitsTracer*>(aTrc);
 
     // If nothing that could be held alive by this entry is marked gray, return.
-    bool delegateMightNeedMarking = aKey && xpc_IsGrayGCThing(aKey.asCell());
-    bool valueMightNeedMarking = aValue && xpc_IsGrayGCThing(aValue.asCell()) &&
+    bool delegateMightNeedMarking = aKey && JS::GCThingIsMarkedGray(aKey);
+    bool valueMightNeedMarking = aValue && JS::GCThingIsMarkedGray(aValue) &&
                                  aValue.kind() != JSTRACE_STRING;
     if (!delegateMightNeedMarking && !valueMightNeedMarking) {
       return;
     }
 
     if (!AddToCCKind(aKey.kind())) {
       aKey = JS::GCCellPtr::NullPtr();
     }
 
     if (delegateMightNeedMarking && aKey.isObject()) {
       JSObject* kdelegate = js::GetWeakmapKeyDelegate(aKey.toObject());
-      if (kdelegate && !xpc_IsGrayGCThing(kdelegate)) {
+      if (kdelegate && !JS::ObjectIsMarkedGray(kdelegate)) {
         if (JS::UnmarkGrayGCThingRecursively(aKey)) {
           tracer->mAnyMarked = true;
         }
       }
     }
 
-    if (aValue && xpc_IsGrayGCThing(aValue.asCell()) &&
-        (!aKey || !xpc_IsGrayGCThing(aKey.asCell())) &&
-        (!aMap || !xpc_IsGrayGCThing(aMap)) &&
+    if (aValue && JS::GCThingIsMarkedGray(aValue) &&
+        (!aKey || !JS::GCThingIsMarkedGray(aKey)) &&
+        (!aMap || !JS::ObjectIsMarkedGray(aMap)) &&
         aValue.kind() != JSTRACE_SHAPE) {
       if (JS::UnmarkGrayGCThingRecursively(aValue)) {
         tracer->mAnyMarked = true;
       }
     }
   }
 
   bool mAnyMarked;
@@ -306,18 +305,17 @@ CheckParticipatesInCycleCollection(JS::G
                                    void* aClosure)
 {
   Closure* closure = static_cast<Closure*>(aClosure);
 
   if (closure->mCycleCollectionEnabled) {
     return;
   }
 
-  if (AddToCCKind(aThing.kind()) &&
-      xpc_IsGrayGCThing(aThing.asCell())) {
+  if (AddToCCKind(aThing.kind()) && JS::GCThingIsMarkedGray(aThing)) {
     closure->mCycleCollectionEnabled = true;
   }
 }
 
 static PLDHashOperator
 NoteJSHolder(void* aHolder, nsScriptObjectTracer*& aTracer, void* aArg)
 {
   Closure* closure = static_cast<Closure*>(aArg);
@@ -381,20 +379,21 @@ struct TraversalTracer : public JSTracer
   {
   }
   nsCycleCollectionTraversalCallback& mCb;
 };
 
 static void
 NoteJSChild(JSTracer* aTrc, void* aThing, JSGCTraceKind aTraceKind)
 {
+  JS::GCCellPtr thing(aThing, aTraceKind);
   TraversalTracer* tracer = static_cast<TraversalTracer*>(aTrc);
 
   // Don't traverse non-gray objects, unless we want all traces.
-  if (!xpc_IsGrayGCThing(aThing) && !tracer->mCb.WantAllTraces()) {
+  if (!JS::GCThingIsMarkedGray(thing) && !tracer->mCb.WantAllTraces()) {
     return;
   }
 
   /*
    * This function needs to be careful to avoid stack overflow. Normally, when
    * AddToCCKind is true, the recursion terminates immediately as we just add
    * |thing| to the CC graph. So overflow is only possible when there are long
    * chains of non-AddToCCKind GC things. Currently, this only can happen via
@@ -413,17 +412,16 @@ 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()));
       }
     }
-    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) {
@@ -634,17 +632,17 @@ CycleCollectedJSRuntime::NoteGCThingXPCO
 }
 
 void
 CycleCollectedJSRuntime::TraverseGCThing(TraverseSelect aTs, void* aThing,
                                          JSGCTraceKind aTraceKind,
                                          nsCycleCollectionTraversalCallback& aCb)
 {
   MOZ_ASSERT(aTraceKind == js::GCThingTraceKind(aThing));
-  bool isMarkedGray = xpc_IsGrayGCThing(aThing);
+  bool isMarkedGray = JS::GCThingIsMarkedGray(JS::GCCellPtr(aThing, aTraceKind));
 
   if (aTs == TRAVERSE_FULL) {
     DescribeGCThing(!isMarkedGray, aThing, aTraceKind, aCb);
   }
 
   // If this object is alive, then all of its children are alive. For JS objects,
   // the black-gray invariant ensures the children are also marked black. For C++
   // objects, the ref count from this object will keep them alive. Thus we don't
@@ -992,17 +990,17 @@ CycleCollectedJSRuntime::UsefulToMergeZo
     JS::RootedObject obj(cx, scx ? scx->GetWindowProxyPreserveColor() : nullptr);
     if (!obj) {
       continue;
     }
     MOZ_ASSERT(js::IsOuterObject(obj));
     // Grab the inner from the outer.
     obj = JS_ObjectToInnerObject(cx, obj);
     MOZ_ASSERT(!js::GetObjectParent(obj));
-    if (JS::GCThingIsMarkedGray(obj) &&
+    if (JS::ObjectIsMarkedGray(obj) &&
         !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
       return true;
     }
   }
   return false;
 }
 
 void
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -2016,24 +2016,24 @@ nsCycleCollectorLoggerConstructor(nsISup
 
   return logger->QueryInterface(aIID, aInstancePtr);
 }
 
 static bool
 GCThingIsGrayCCThing(JS::GCCellPtr thing)
 {
     return AddToCCKind(thing.kind()) &&
-           JS::GCThingIsMarkedGray(thing.asCell());
+           JS::GCThingIsMarkedGray(thing);
 }
 
 static bool
 ValueIsGrayCCThing(const JS::Value& value)
 {
     return AddToCCKind(value.gcKind()) &&
-           JS::GCThingIsMarkedGray(value.toGCThing());
+           JS::GCThingIsMarkedGray(value.toGCCellPtr());
 }
 
 ////////////////////////////////////////////////////////////////////////
 // Bacon & Rajan's |MarkRoots| routine.
 ////////////////////////////////////////////////////////////////////////
 
 class CCGraphBuilder MOZ_FINAL : public nsCycleCollectionTraversalCallback,
   public nsCycleCollectionNoteRootCallback