Bug 1268805 - Implement PrivateGCThingValue. (r=terrence)
☠☠ backed out by 03af61c547dd ☠ ☠
authorShu-yu Guo <shu@rfrn.org>
Fri, 29 Apr 2016 15:12:13 -0700
changeset 295579 31075a760b2e8d517de2f16a163621c72549f3a6
parent 295578 dc1a65977fb4fb4a4db5b41f047a2a8ccc4237a4
child 295580 b8a517eb7c6b700b6845a4f43e65cb2f0da58287
push id19015
push usercbook@mozilla.com
push dateMon, 02 May 2016 09:39:23 +0000
treeherderfx-team@2080375bc69d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1268805
milestone49.0a1
Bug 1268805 - Implement PrivateGCThingValue. (r=terrence)
js/public/HeapAPI.h
js/public/Value.h
js/src/gc/Barrier.cpp
js/src/gc/Barrier.h
js/src/gc/Marking.cpp
js/src/gc/Marking.h
js/src/gc/Tracer.cpp
js/src/jit/BaselineIC.h
js/src/jsapi-tests/moz.build
js/src/jsapi-tests/testPrivateGCThingValue.cpp
js/src/jsapi.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsgc.cpp
js/src/jsgc.h
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/nsCycleCollector.cpp
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -389,16 +389,19 @@ GCThingIsMarkedGray(GCCellPtr thing)
 {
     if (js::gc::IsInsideNursery(thing.asCell()))
         return false;
     if (thing.mayBeOwnedByOtherRuntime())
         return false;
     return js::gc::detail::CellIsMarkedGray(thing.asCell());
 }
 
+extern JS_PUBLIC_API(JS::TraceKind)
+GCThingTraceKind(js::gc::Cell* thing);
+
 } /* namespace JS */
 
 namespace js {
 namespace gc {
 
 static MOZ_ALWAYS_INLINE bool
 IsIncrementalBarrierNeededOnTenuredGCThing(JS::shadow::Runtime* rt, const JS::GCCellPtr thing)
 {
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -71,18 +71,19 @@ JS_ENUM_HEADER(JSValueType, uint8_t)
 {
     JSVAL_TYPE_DOUBLE              = 0x00,
     JSVAL_TYPE_INT32               = 0x01,
     JSVAL_TYPE_UNDEFINED           = 0x02,
     JSVAL_TYPE_BOOLEAN             = 0x03,
     JSVAL_TYPE_MAGIC               = 0x04,
     JSVAL_TYPE_STRING              = 0x05,
     JSVAL_TYPE_SYMBOL              = 0x06,
-    JSVAL_TYPE_NULL                = 0x07,
-    JSVAL_TYPE_OBJECT              = 0x08,
+    JSVAL_TYPE_PRIVATE_GCTHING     = 0x07,
+    JSVAL_TYPE_NULL                = 0x08,
+    JSVAL_TYPE_OBJECT              = 0x0c,
 
     /* These never appear in a jsval; they are only provided as an out-of-band value. */
     JSVAL_TYPE_UNKNOWN             = 0x20,
     JSVAL_TYPE_MISSING             = 0x21
 } JS_ENUM_FOOTER(JSValueType);
 
 static_assert(sizeof(JSValueType) == 1,
               "compiler typed enum support is apparently buggy");
@@ -95,17 +96,18 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
     JSVAL_TAG_CLEAR                = 0xFFFFFF80,
     JSVAL_TAG_INT32                = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
     JSVAL_TAG_STRING               = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
     JSVAL_TAG_SYMBOL               = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
     JSVAL_TAG_MAGIC                = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
     JSVAL_TAG_NULL                 = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
-    JSVAL_TAG_OBJECT               = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
+    JSVAL_TAG_OBJECT               = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT,
+    JSVAL_TAG_PRIVATE_GCTHING      = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING
 } JS_ENUM_FOOTER(JSValueTag);
 
 static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
               "compiler typed enum support is apparently buggy");
 
 #elif defined(JS_PUNBOX64)
 
 /* Remember to propagate changes to the C defines below. */
@@ -114,33 +116,35 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
     JSVAL_TAG_MAX_DOUBLE           = 0x1FFF0,
     JSVAL_TAG_INT32                = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
     JSVAL_TAG_STRING               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
     JSVAL_TAG_SYMBOL               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
     JSVAL_TAG_MAGIC                = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
     JSVAL_TAG_NULL                 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
-    JSVAL_TAG_OBJECT               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
+    JSVAL_TAG_OBJECT               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT,
+    JSVAL_TAG_PRIVATE_GCTHING      = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING
 } JS_ENUM_FOOTER(JSValueTag);
 
 static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
               "compiler typed enum support is apparently buggy");
 
 JS_ENUM_HEADER(JSValueShiftedTag, uint64_t)
 {
-    JSVAL_SHIFTED_TAG_MAX_DOUBLE   = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
-    JSVAL_SHIFTED_TAG_INT32        = (((uint64_t)JSVAL_TAG_INT32)      << JSVAL_TAG_SHIFT),
-    JSVAL_SHIFTED_TAG_UNDEFINED    = (((uint64_t)JSVAL_TAG_UNDEFINED)  << JSVAL_TAG_SHIFT),
-    JSVAL_SHIFTED_TAG_STRING       = (((uint64_t)JSVAL_TAG_STRING)     << JSVAL_TAG_SHIFT),
-    JSVAL_SHIFTED_TAG_SYMBOL       = (((uint64_t)JSVAL_TAG_SYMBOL)     << JSVAL_TAG_SHIFT),
-    JSVAL_SHIFTED_TAG_BOOLEAN      = (((uint64_t)JSVAL_TAG_BOOLEAN)    << JSVAL_TAG_SHIFT),
-    JSVAL_SHIFTED_TAG_MAGIC        = (((uint64_t)JSVAL_TAG_MAGIC)      << JSVAL_TAG_SHIFT),
-    JSVAL_SHIFTED_TAG_NULL         = (((uint64_t)JSVAL_TAG_NULL)       << JSVAL_TAG_SHIFT),
-    JSVAL_SHIFTED_TAG_OBJECT       = (((uint64_t)JSVAL_TAG_OBJECT)     << JSVAL_TAG_SHIFT)
+    JSVAL_SHIFTED_TAG_MAX_DOUBLE      = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE)     << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
+    JSVAL_SHIFTED_TAG_INT32           = (((uint64_t)JSVAL_TAG_INT32)           << JSVAL_TAG_SHIFT),
+    JSVAL_SHIFTED_TAG_UNDEFINED       = (((uint64_t)JSVAL_TAG_UNDEFINED)       << JSVAL_TAG_SHIFT),
+    JSVAL_SHIFTED_TAG_STRING          = (((uint64_t)JSVAL_TAG_STRING)          << JSVAL_TAG_SHIFT),
+    JSVAL_SHIFTED_TAG_SYMBOL          = (((uint64_t)JSVAL_TAG_SYMBOL)          << JSVAL_TAG_SHIFT),
+    JSVAL_SHIFTED_TAG_BOOLEAN         = (((uint64_t)JSVAL_TAG_BOOLEAN)         << JSVAL_TAG_SHIFT),
+    JSVAL_SHIFTED_TAG_MAGIC           = (((uint64_t)JSVAL_TAG_MAGIC)           << JSVAL_TAG_SHIFT),
+    JSVAL_SHIFTED_TAG_NULL            = (((uint64_t)JSVAL_TAG_NULL)            << JSVAL_TAG_SHIFT),
+    JSVAL_SHIFTED_TAG_OBJECT          = (((uint64_t)JSVAL_TAG_OBJECT)          << JSVAL_TAG_SHIFT),
+    JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT)
 } JS_ENUM_FOOTER(JSValueShiftedTag);
 
 static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
               "compiler typed enum support is apparently buggy");
 
 #endif
 
 /*
@@ -158,56 +162,60 @@ static_assert(sizeof(JSValueShiftedTag) 
 typedef uint8_t JSValueType;
 #define JSVAL_TYPE_DOUBLE            ((uint8_t)0x00)
 #define JSVAL_TYPE_INT32             ((uint8_t)0x01)
 #define JSVAL_TYPE_UNDEFINED         ((uint8_t)0x02)
 #define JSVAL_TYPE_BOOLEAN           ((uint8_t)0x03)
 #define JSVAL_TYPE_MAGIC             ((uint8_t)0x04)
 #define JSVAL_TYPE_STRING            ((uint8_t)0x05)
 #define JSVAL_TYPE_SYMBOL            ((uint8_t)0x06)
-#define JSVAL_TYPE_NULL              ((uint8_t)0x07)
-#define JSVAL_TYPE_OBJECT            ((uint8_t)0x08)
+#define JSVAL_TYPE_PRIVATE_GCTHING   ((uint8_t)0x07)
+#define JSVAL_TYPE_NULL              ((uint8_t)0x08)
+#define JSVAL_TYPE_OBJECT            ((uint8_t)0x0c)
 #define JSVAL_TYPE_UNKNOWN           ((uint8_t)0x20)
 
 #if defined(JS_NUNBOX32)
 
 typedef uint32_t JSValueTag;
 #define JSVAL_TAG_CLEAR              ((uint32_t)(0xFFFFFF80))
 #define JSVAL_TAG_INT32              ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32))
 #define JSVAL_TAG_UNDEFINED          ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED))
 #define JSVAL_TAG_STRING             ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING))
 #define JSVAL_TAG_SYMBOL             ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL))
 #define JSVAL_TAG_BOOLEAN            ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN))
 #define JSVAL_TAG_MAGIC              ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC))
 #define JSVAL_TAG_NULL               ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL))
 #define JSVAL_TAG_OBJECT             ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT))
+#define JSVAL_TAG_PRIVATE_GCTHING    ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING))
 
 #elif defined(JS_PUNBOX64)
 
 typedef uint32_t JSValueTag;
 #define JSVAL_TAG_MAX_DOUBLE         ((uint32_t)(0x1FFF0))
 #define JSVAL_TAG_INT32              (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32)
 #define JSVAL_TAG_UNDEFINED          (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED)
 #define JSVAL_TAG_STRING             (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING)
 #define JSVAL_TAG_SYMBOL             (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL)
 #define JSVAL_TAG_BOOLEAN            (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN)
 #define JSVAL_TAG_MAGIC              (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC)
 #define JSVAL_TAG_NULL               (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL)
 #define JSVAL_TAG_OBJECT             (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT)
+#define JSVAL_TAG_PRIVATE_GCTHING    (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING)
 
 typedef uint64_t JSValueShiftedTag;
-#define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF)
-#define JSVAL_SHIFTED_TAG_INT32      (((uint64_t)JSVAL_TAG_INT32)      << JSVAL_TAG_SHIFT)
-#define JSVAL_SHIFTED_TAG_UNDEFINED  (((uint64_t)JSVAL_TAG_UNDEFINED)  << JSVAL_TAG_SHIFT)
-#define JSVAL_SHIFTED_TAG_STRING     (((uint64_t)JSVAL_TAG_STRING)     << JSVAL_TAG_SHIFT)
-#define JSVAL_SHIFTED_TAG_SYMBOL     (((uint64_t)JSVAL_TAG_SYMBOL)     << JSVAL_TAG_SHIFT)
-#define JSVAL_SHIFTED_TAG_BOOLEAN    (((uint64_t)JSVAL_TAG_BOOLEAN)    << JSVAL_TAG_SHIFT)
-#define JSVAL_SHIFTED_TAG_MAGIC      (((uint64_t)JSVAL_TAG_MAGIC)      << JSVAL_TAG_SHIFT)
-#define JSVAL_SHIFTED_TAG_NULL       (((uint64_t)JSVAL_TAG_NULL)       << JSVAL_TAG_SHIFT)
-#define JSVAL_SHIFTED_TAG_OBJECT     (((uint64_t)JSVAL_TAG_OBJECT)     << JSVAL_TAG_SHIFT)
+#define JSVAL_SHIFTED_TAG_MAX_DOUBLE      ((((uint64_t)JSVAL_TAG_MAX_DOUBLE)     << JSVAL_TAG_SHIFT) | 0xFFFFFFFF)
+#define JSVAL_SHIFTED_TAG_INT32           (((uint64_t)JSVAL_TAG_INT32)           << JSVAL_TAG_SHIFT)
+#define JSVAL_SHIFTED_TAG_UNDEFINED       (((uint64_t)JSVAL_TAG_UNDEFINED)       << JSVAL_TAG_SHIFT)
+#define JSVAL_SHIFTED_TAG_STRING          (((uint64_t)JSVAL_TAG_STRING)          << JSVAL_TAG_SHIFT)
+#define JSVAL_SHIFTED_TAG_SYMBOL          (((uint64_t)JSVAL_TAG_SYMBOL)          << JSVAL_TAG_SHIFT)
+#define JSVAL_SHIFTED_TAG_BOOLEAN         (((uint64_t)JSVAL_TAG_BOOLEAN)         << JSVAL_TAG_SHIFT)
+#define JSVAL_SHIFTED_TAG_MAGIC           (((uint64_t)JSVAL_TAG_MAGIC)           << JSVAL_TAG_SHIFT)
+#define JSVAL_SHIFTED_TAG_NULL            (((uint64_t)JSVAL_TAG_NULL)            << JSVAL_TAG_SHIFT)
+#define JSVAL_SHIFTED_TAG_OBJECT          (((uint64_t)JSVAL_TAG_OBJECT)          << JSVAL_TAG_SHIFT)
+#define JSVAL_SHIFTED_TAG_PRIVATE_GCTHING (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT)
 
 #endif  /* JS_PUNBOX64 */
 #endif  /* !defined(__SUNPRO_CC) && !defined(__xlC__) */
 
 #if defined(JS_NUNBOX32)
 
 #define JSVAL_TYPE_TO_TAG(type)      ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
 
@@ -627,16 +635,39 @@ PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr)
 }
 
 static inline void*
 JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
 {
     return l.s.payload.ptr;
 }
 
+static inline jsval_layout
+PRIVATE_GCTHING_TO_JSVAL_IMPL(js::gc::Cell* cell)
+{
+    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
+               "Private GC thing Values must not be strings. Make a StringValue instead.");
+    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
+               "Private GC thing Values must not be symbols. Make a SymbolValue instead.");
+    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
+               "Private GC thing Values must not be objects. Make an ObjectValue instead.");
+
+    jsval_layout l;
+    MOZ_ASSERT(uintptr_t(cell) > 0x1000);
+    l.s.tag = JSVAL_TAG_PRIVATE_GCTHING;
+    l.s.payload.cell = ptr;
+    return l;
+}
+
+static inline bool
+JSVAL_IS_PRIVATE_GCTHING_IMPL(jsval_layout l)
+{
+    return l.s.tag == JSVAL_TAG_PRIVATE_GCTHING;
+}
+
 static inline bool
 JSVAL_IS_GCTHING_IMPL(jsval_layout l)
 {
     /* gcc sometimes generates signed < without explicit casts. */
     return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET;
 }
 
 static inline js::gc::Cell*
@@ -649,16 +680,18 @@ static inline uint32_t
 JSVAL_TRACE_KIND_IMPL(jsval_layout l)
 {
     static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
                   "Value type tags must correspond with JS::TraceKinds.");
     static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
                   "Value type tags must correspond with JS::TraceKinds.");
     static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
                   "Value type tags must correspond with JS::TraceKinds.");
+    if (MOZ_UNLIKELY(JSVAL_IS_PRIVATE_GCTHING_IMPL(l)))
+        return (uint32_t)JS::GCThingTraceKind(JSVAL_TO_GCTHING_IMPL(l));
     return l.s.tag & 0x03;
 }
 
 static inline bool
 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
 {
     return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32;
 }
@@ -868,16 +901,22 @@ OBJECT_TO_JSVAL_IMPL(JSObject* obj)
 
 static inline bool
 JSVAL_IS_NULL_IMPL(jsval_layout l)
 {
     return l.asBits == JSVAL_SHIFTED_TAG_NULL;
 }
 
 static inline bool
+JSVAL_IS_PRIVATE_GCTHING_IMPL(jsval_layout l)
+{
+    return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_PRIVATE_GCTHING;
+}
+
+static inline bool
 JSVAL_IS_GCTHING_IMPL(jsval_layout l)
 {
     return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
 }
 
 static inline js::gc::Cell*
 JSVAL_TO_GCTHING_IMPL(jsval_layout l)
 {
@@ -890,16 +929,18 @@ static inline uint32_t
 JSVAL_TRACE_KIND_IMPL(jsval_layout l)
 {
     static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
                   "Value type tags must correspond with JS::TraceKinds.");
     static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
                   "Value type tags must correspond with JS::TraceKinds.");
     static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
                   "Value type tags must correspond with JS::TraceKinds.");
+    if (MOZ_UNLIKELY(JSVAL_IS_PRIVATE_GCTHING_IMPL(l)))
+        return (uint32_t)JS::GCThingTraceKind(JSVAL_TO_GCTHING_IMPL(l));
     return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) & 0x03;
 }
 
 static inline jsval_layout
 PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr)
 {
     jsval_layout l;
     uint64_t ptrBits = (uint64_t)ptr;
@@ -911,16 +952,34 @@ PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr)
 
 static inline void*
 JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
 {
     MOZ_ASSERT((l.asBits & 0x8000000000000000LL) == 0);
     return (void*)(l.asBits << 1);
 }
 
+static inline jsval_layout
+PRIVATE_GCTHING_TO_JSVAL_IMPL(js::gc::Cell* cell)
+{
+    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
+               "Private GC thing Values must not be strings. Make a StringValue instead.");
+    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
+               "Private GC thing Values must not be symbols. Make a SymbolValue instead.");
+    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
+               "Private GC thing Values must not be objects. Make an ObjectValue instead.");
+
+    jsval_layout l;
+    uint64_t cellBits = (uint64_t)cell;
+    MOZ_ASSERT(uintptr_t(cellBits) > 0x1000);
+    MOZ_ASSERT((cellBits >> JSVAL_TAG_SHIFT) == 0);
+    l.asBits = cellBits | JSVAL_SHIFTED_TAG_PRIVATE_GCTHING;
+    return l;
+}
+
 static inline bool
 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
 {
     return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32);
 }
 
 static inline bool
 JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(jsval_layout l, bool b)
@@ -1337,16 +1396,33 @@ class Value
         setInt32(int32_t(ui));
     }
 
     uint32_t toPrivateUint32() const {
         return uint32_t(toInt32());
     }
 
     /*
+     * Private GC Thing API
+     *
+     * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit
+     * payload as private GC things. Such Values are considered isMarkable()
+     * and isGCThing(), and as such, automatically marked. Their traceKind()
+     * is gotten via their cells.
+     */
+
+    void setPrivateGCThing(js::gc::Cell* cell) {
+        data = PRIVATE_GCTHING_TO_JSVAL_IMPL(cell);
+    }
+
+    bool isPrivateGCThing() const {
+        return JSVAL_IS_PRIVATE_GCTHING_IMPL(data);
+    }
+
+    /*
      * An unmarked value is just a void* cast as a Value. Thus, the Value is
      * not safe for GC and must not be marked. This API avoids raw casts
      * and the ensuing strict-aliasing warnings.
      */
 
     void setUnmarkedPtr(void* ptr) {
         data.asPtr = ptr;
     }
@@ -1678,16 +1754,24 @@ PrivateValue(void* ptr)
 static inline Value
 PrivateUint32Value(uint32_t ui)
 {
     Value v;
     v.setPrivateUint32(ui);
     return v;
 }
 
+static inline Value
+PrivateGCThingValue(js::gc::Cell* cell)
+{
+    Value v;
+    v.setPrivateGCThing(cell);
+    return v;
+}
+
 inline bool
 SameType(const Value& lhs, const Value& rhs)
 {
     return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data);
 }
 
 } // namespace JS
 
@@ -1796,16 +1880,17 @@ class MutableValueOperations : public Va
     void setBoolean(bool b) { value().setBoolean(b); }
     void setMagic(JSWhyMagic why) { value().setMagic(why); }
     bool setNumber(uint32_t ui) { return value().setNumber(ui); }
     bool setNumber(double d) { return value().setNumber(d); }
     void setString(JSString* str) { this->value().setString(str); }
     void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); }
     void setObject(JSObject& obj) { this->value().setObject(obj); }
     void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); }
+    void setPrivateGCThing(js::gc::Cell* cell) { this->value().setPrivateGCThing(cell); }
 };
 
 /*
  * Augment the generic Heap<T> interface when T = Value with
  * type-querying, value-extracting, and mutating operations.
  */
 template <>
 class HeapBase<JS::Value> : public ValueOperations<JS::Heap<JS::Value> >
@@ -1824,16 +1909,17 @@ class HeapBase<JS::Value> : public Value
     void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); }
     void setDouble(double d) { setBarriered(JS::DoubleValue(d)); }
     void setNaN() { setDouble(JS::GenericNaN()); }
     void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); }
     void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); }
     void setString(JSString* str) { setBarriered(JS::StringValue(str)); }
     void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); }
     void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); }
+    void setPrivateGCThing(js::gc::Cell* cell) { setBarriered(JS::PrivateGCThingValue(cell)); }
 
     bool setNumber(uint32_t ui) {
         if (ui > JSVAL_INT_MAX) {
             setDouble((double)ui);
             return false;
         } else {
             setInt32((int32_t)ui);
             return true;
@@ -1885,16 +1971,18 @@ DispatchTyped(F f, const JS::Value& val,
   -> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
 {
     if (val.isString())
         return f(val.toString(), mozilla::Forward<Args>(args)...);
     if (val.isObject())
         return f(&val.toObject(), mozilla::Forward<Args>(args)...);
     if (val.isSymbol())
         return f(val.toSymbol(), mozilla::Forward<Args>(args)...);
+    if (MOZ_UNLIKELY(val.isPrivateGCThing()))
+        return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...);
     MOZ_ASSERT(!val.isMarkable());
     return F::defaultValue(val);
 }
 
 template <class S> struct VoidDefaultAdaptor { static void defaultValue(S) {} };
 template <class S> struct IdentityDefaultAdaptor { static S defaultValue(const S& v) {return v;} };
 template <class S, bool v> struct BoolDefaultAdaptor { static bool defaultValue(S) { return v; } };
 
--- a/js/src/gc/Barrier.cpp
+++ b/js/src/gc/Barrier.cpp
@@ -75,30 +75,39 @@ CurrentThreadIsHandlingInitFailure()
 
 template <typename S>
 template <typename T>
 void
 ReadBarrierFunctor<S>::operator()(T* t)
 {
     InternalBarrierMethods<T*>::readBarrier(t);
 }
-template void ReadBarrierFunctor<JS::Value>::operator()<JS::Symbol>(JS::Symbol*);
-template void ReadBarrierFunctor<JS::Value>::operator()<JSObject>(JSObject*);
-template void ReadBarrierFunctor<JS::Value>::operator()<JSString>(JSString*);
+
+// All GC things may be held in a Value, either publicly or as a private GC
+// thing.
+#define JS_EXPAND_DEF(name, type, _) \
+template void ReadBarrierFunctor<JS::Value>::operator()<type>(type*);
+JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
+#undef JS_EXPAND_DEF
 
 template <typename S>
 template <typename T>
 void
 PreBarrierFunctor<S>::operator()(T* t)
 {
     InternalBarrierMethods<T*>::preBarrier(t);
 }
-template void PreBarrierFunctor<JS::Value>::operator()<JS::Symbol>(JS::Symbol*);
-template void PreBarrierFunctor<JS::Value>::operator()<JSObject>(JSObject*);
-template void PreBarrierFunctor<JS::Value>::operator()<JSString>(JSString*);
+
+// All GC things may be held in a Value, either publicly or as a private GC
+// thing.
+#define JS_EXPAND_DEF(name, type, _) \
+template void PreBarrierFunctor<JS::Value>::operator()<type>(type*);
+JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
+#undef JS_EXPAND_DEF
+
 template void PreBarrierFunctor<jsid>::operator()<JS::Symbol>(JS::Symbol*);
 template void PreBarrierFunctor<jsid>::operator()<JSString>(JSString*);
 
 template <typename T>
 /* static */ HashNumber
 MovableCellHasher<T>::hash(const Lookup& l)
 {
     if (!l)
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -256,17 +256,17 @@ struct InternalBarrierMethods<T*>
 
     static void preBarrier(T* v) { T::writeBarrierPre(v); }
 
     static void postBarrier(T** vp, T* prev, T* next) { T::writeBarrierPost(vp, prev, next); }
 
     static void readBarrier(T* v) { T::readBarrier(v); }
 };
 
-template <typename S> struct PreBarrierFunctor : VoidDefaultAdaptor<S> {
+template <typename S> struct PreBarrierFunctor : public VoidDefaultAdaptor<S> {
     template <typename T> void operator()(T* t);
 };
 
 template <typename S> struct ReadBarrierFunctor : public VoidDefaultAdaptor<S> {
     template <typename T> void operator()(T* t);
 };
 
 template <>
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2016,17 +2016,17 @@ TenuringTracer::traverse(JSObject** objp
     if (IsInsideNursery(*objp) && !nursery().getForwardedPointer(objp))
         *objp = moveToTenured(*objp);
 }
 
 template <typename S>
 struct TenuringTraversalFunctor : public IdentityDefaultAdaptor<S> {
     template <typename T> S operator()(T* t, TenuringTracer* trc) {
         trc->traverse(&t);
-        return js::gc::RewrapTaggedPointer<S, T*>::wrap(t);
+        return js::gc::RewrapTaggedPointer<S, T>::wrap(t);
     }
 };
 
 template <typename T>
 void
 TenuringTracer::traverse(T* thingp)
 {
     *thingp = DispatchTyped(TenuringTraversalFunctor<T>(), *thingp, this);
@@ -2422,17 +2422,17 @@ IsMarkedInternal(JSObject** thingp)
     }
     return IsMarkedInternalCommon(thingp);
 }
 
 template <typename S>
 struct IsMarkedFunctor : public IdentityDefaultAdaptor<S> {
     template <typename T> S operator()(T* t, bool* rv) {
         *rv = IsMarkedInternal(&t);
-        return js::gc::RewrapTaggedPointer<S, T*>::wrap(t);
+        return js::gc::RewrapTaggedPointer<S, T>::wrap(t);
     }
 };
 
 template <typename T>
 static bool
 IsMarkedInternal(T* thingp)
 {
     bool rv = true;
@@ -2481,17 +2481,17 @@ IsAboutToBeFinalizedInternal(T** thingp)
 
     return false;
 }
 
 template <typename S>
 struct IsAboutToBeFinalizedFunctor : public IdentityDefaultAdaptor<S> {
     template <typename T> S operator()(T* t, bool* rv) {
         *rv = IsAboutToBeFinalizedInternal(&t);
-        return js::gc::RewrapTaggedPointer<S, T*>::wrap(t);
+        return js::gc::RewrapTaggedPointer<S, T>::wrap(t);
     }
 };
 
 template <typename T>
 static bool
 IsAboutToBeFinalizedInternal(T* thingp)
 {
     bool rv = false;
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -415,24 +415,44 @@ IsNullTaggedPointer(void* p)
 }
 
 // Wrap a GC thing pointer into a new Value or jsid. The type system enforces
 // that the thing pointer is a wrappable type.
 template <typename S, typename T>
 struct RewrapTaggedPointer{};
 #define DECLARE_REWRAP(S, T, method, prefix) \
     template <> struct RewrapTaggedPointer<S, T> { \
-        static S wrap(T thing) { return method ( prefix thing ); } \
+        static S wrap(T* thing) { return method ( prefix thing ); } \
     }
-DECLARE_REWRAP(JS::Value, JSObject*, JS::ObjectOrNullValue, );
-DECLARE_REWRAP(JS::Value, JSString*, JS::StringValue, );
-DECLARE_REWRAP(JS::Value, JS::Symbol*, JS::SymbolValue, );
-DECLARE_REWRAP(jsid, JSString*, NON_INTEGER_ATOM_TO_JSID, (JSAtom*));
-DECLARE_REWRAP(jsid, JS::Symbol*, SYMBOL_TO_JSID, );
-DECLARE_REWRAP(js::TaggedProto, JSObject*, js::TaggedProto, );
+DECLARE_REWRAP(JS::Value, JSObject, JS::ObjectOrNullValue, );
+DECLARE_REWRAP(JS::Value, JSString, JS::StringValue, );
+DECLARE_REWRAP(JS::Value, JS::Symbol, JS::SymbolValue, );
+DECLARE_REWRAP(jsid, JSString, NON_INTEGER_ATOM_TO_JSID, (JSAtom*));
+DECLARE_REWRAP(jsid, JS::Symbol, SYMBOL_TO_JSID, );
+DECLARE_REWRAP(js::TaggedProto, JSObject, js::TaggedProto, );
+#undef DECLARE_REWRAP
+
+template <typename T>
+struct IsPrivateGCThingInValue
+  : public mozilla::EnableIf<mozilla::IsBaseOf<Cell, T>::value &&
+                             !mozilla::IsBaseOf<JSObject, T>::value &&
+                             !mozilla::IsBaseOf<JSString, T>::value &&
+                             !mozilla::IsBaseOf<JS::Symbol, T>::value, T>
+{
+    static_assert(!mozilla::IsSame<Cell, T>::value && !mozilla::IsSame<TenuredCell, T>::value,
+                  "T must not be Cell or TenuredCell");
+};
+
+template <typename T>
+struct RewrapTaggedPointer<Value, T>
+{
+    static Value wrap(typename IsPrivateGCThingInValue<T>::Type* thing) {
+        return JS::PrivateGCThingValue(thing);
+    }
+};
 
 } /* namespace gc */
 
 bool
 UnmarkGrayShapeRecursively(Shape* shape);
 
 template<typename T>
 void
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -54,17 +54,17 @@ DoCallback(JS::CallbackTracer* trc, T* t
 #define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(name, type, _) \
     template type* DoCallback<type*>(JS::CallbackTracer*, type**, const char*);
 JS_FOR_EACH_TRACEKIND(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS);
 #undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
 
 template <typename S>
 struct DoCallbackFunctor : public IdentityDefaultAdaptor<S> {
     template <typename T> S operator()(T* t, JS::CallbackTracer* trc, const char* name) {
-        return js::gc::RewrapTaggedPointer<S, T*>::wrap(DoCallback(trc, &t, name));
+        return js::gc::RewrapTaggedPointer<S, T>::wrap(DoCallback(trc, &t, name));
     }
 };
 
 template <>
 Value
 DoCallback<Value>(JS::CallbackTracer* trc, Value* vp, const char* name)
 {
     *vp = DispatchTyped(DoCallbackFunctor<Value>(), *vp, trc, name);
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -728,17 +728,17 @@ class ICGetElemNativeCompiler : public I
     bool emitCheckKey(MacroAssembler& masm, Label& failure);
     bool emitCallNative(MacroAssembler& masm, Register objReg);
     bool emitCallScripted(MacroAssembler& masm, Register objReg);
     bool generateStubCode(MacroAssembler& masm);
 
   protected:
     virtual int32_t getKey() const {
         MOZ_ASSERT(static_cast<int32_t>(acctype_) <= 7);
-        MOZ_ASSERT(static_cast<int32_t>(unboxedType_) <= 8);
+        MOZ_ASSERT(static_cast<int32_t>(unboxedType_) <= 15);
         return static_cast<int32_t>(engine_) |
               (static_cast<int32_t>(kind) << 1) |
               (static_cast<int32_t>(needsAtomize_) << 17) |
               (static_cast<int32_t>(acctype_) << 18) |
               (static_cast<int32_t>(unboxedType_) << 21) |
               (static_cast<int32_t>(mozilla::IsSame<JS::Symbol*, T>::value) << 25) |
               (HeapReceiverGuard::keyBits(obj_) << 26);
     }
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -63,16 +63,17 @@ UNIFIED_SOURCES += [
     'testNewObject.cpp',
     'testNewTargetInvokeConstructor.cpp',
     'testNullRoot.cpp',
     'testObjectEmulatingUndefined.cpp',
     'testOOM.cpp',
     'testParseJSON.cpp',
     'testPersistentRooted.cpp',
     'testPreserveJitCode.cpp',
+    'testPrivateGCThingValue.cpp',
     'testProfileStrings.cpp',
     'testPropCache.cpp',
     'testRegExp.cpp',
     'testResolveRecursion.cpp',
     'tests.cpp',
     'testSameValue.cpp',
     'testSavedStacks.cpp',
     'testScriptInfo.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testPrivateGCThingValue.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+* vim: set ts=8 sts=4 et sw=4 tw=99:
+*/
+/* 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 "jsapi.h"
+
+#include "js/HeapAPI.h"
+#include "jsapi-tests/tests.h"
+
+class TestTracer : public JS::CallbackTracer
+{
+    void onChild(const JS::GCCellPtr& thing) override {
+        if (thing.asCell() == expectedCell && thing.kind() == expectedKind)
+            found = true;
+    }
+
+  public:
+    js::gc::Cell* expectedCell;
+    JS::TraceKind expectedKind;
+    bool found;
+
+    explicit TestTracer(JSContext* cx)
+      : JS::CallbackTracer(JS_GetRuntime(cx)),
+        found(false)
+    { }
+};
+
+static const JSClass TestClass = {
+    "TestClass",
+    JSCLASS_HAS_RESERVED_SLOTS(1)
+};
+
+BEGIN_TEST(testPrivateGCThingValue)
+{
+    JS::RootedObject obj(cx, JS_NewObject(cx, &TestClass));
+    CHECK(obj);
+
+    // Make a JSScript to stick into a PrivateGCThingValue.
+    JS::RootedScript script(cx);
+    const char code[] = "'objet petit a'";
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__);
+    CHECK(JS_CompileScript(cx, code, sizeof(code) - 1, options, &script));
+    JS_SetReservedSlot(obj, 0, PrivateGCThingValue(script));
+
+    TestTracer trc(cx);
+    trc.expectedCell = script;
+    trc.expectedKind = JS::TraceKind::Script;
+    JS::TraceChildren(&trc, JS::GCCellPtr(obj, JS::TraceKind::Object));
+    CHECK(trc.found);
+
+    return true;
+}
+END_TEST(testPrivateGCThingValue)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6537,8 +6537,15 @@ JS::CopyAsyncStack(JSContext* cx, JS::Ha
     return true;
 }
 
 JS_PUBLIC_API(Zone*)
 JS::GetObjectZone(JSObject* obj)
 {
     return obj->zone();
 }
+
+JS_PUBLIC_API(JS::TraceKind)
+JS::GCThingTraceKind(js::gc::Cell* thing)
+{
+    MOZ_ASSERT(thing);
+    return thing->getTraceKind();
+}
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -576,23 +576,16 @@ js::ZoneGlobalsAreAllGray(JS::Zone* zone
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
         JSObject* obj = comp->maybeGlobal();
         if (!obj || !JS::ObjectIsMarkedGray(obj))
             return false;
     }
     return true;
 }
 
-JS_FRIEND_API(JS::TraceKind)
-js::GCThingTraceKind(void* thing)
-{
-    MOZ_ASSERT(thing);
-    return static_cast<js::gc::Cell*>(thing)->getTraceKind();
-}
-
 JS_FRIEND_API(void)
 js::VisitGrayWrapperTargets(Zone* zone, GCThingCallback callback, void* closure)
 {
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
         for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
             gc::Cell* thing = e.front().key().wrapped;
             if (thing->isTenured() && thing->asTenured().isMarked(gc::GRAY))
                 callback(closure, JS::GCCellPtr(thing, thing->asTenured().getTraceKind()));
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -502,19 +502,16 @@ typedef void
 (*GCThingCallback)(void* closure, JS::GCCellPtr thing);
 
 extern JS_FRIEND_API(void)
 VisitGrayWrapperTargets(JS::Zone* zone, GCThingCallback callback, void* closure);
 
 extern JS_FRIEND_API(JSObject*)
 GetWeakmapKeyDelegate(JSObject* key);
 
-JS_FRIEND_API(JS::TraceKind)
-GCThingTraceKind(void* thing);
-
 /**
  * Invoke cellCallback on every gray JS_OBJECT in the given zone.
  */
 extern JS_FRIEND_API(void)
 IterateGrayObjects(JS::Zone* zone, GCThingCallback cellCallback, void* data);
 
 #ifdef JS_HAS_CTYPES
 extern JS_FRIEND_API(size_t)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -7412,16 +7412,18 @@ JS::GCCellPtr::GCCellPtr(const Value& v)
   : ptr(0)
 {
     if (v.isString())
         ptr = checkedCast(v.toString(), JS::TraceKind::String);
     else if (v.isObject())
         ptr = checkedCast(&v.toObject(), JS::TraceKind::Object);
     else if (v.isSymbol())
         ptr = checkedCast(v.toSymbol(), JS::TraceKind::Symbol);
+    else if (v.isPrivateGCThing())
+        ptr = checkedCast(v.toGCThing(), v.toGCThing()->getTraceKind());
     else
         ptr = checkedCast(nullptr, JS::TraceKind::Null);
 }
 
 JS::TraceKind
 JS::GCCellPtr::outOfLineKind() const
 {
     MOZ_ASSERT((ptr & OutOfLineTraceKindMask) == OutOfLineTraceKindMask);
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1140,17 +1140,17 @@ Forwarded(T* t)
 {
     RelocationOverlay* overlay = RelocationOverlay::fromCell(t);
     MOZ_ASSERT(overlay->isForwarded());
     return reinterpret_cast<T*>(overlay->forwardingAddress());
 }
 
 struct ForwardedFunctor : public IdentityDefaultAdaptor<Value> {
     template <typename T> inline Value operator()(T* t) {
-        return js::gc::RewrapTaggedPointer<Value, T*>::wrap(Forwarded(t));
+        return js::gc::RewrapTaggedPointer<Value, T>::wrap(Forwarded(t));
     }
 };
 
 inline Value
 Forwarded(const JS::Value& value)
 {
     return DispatchTyped(ForwardedFunctor(), value);
 }
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -294,17 +294,17 @@ CheckParticipatesInCycleCollection(JS::G
 NS_IMETHODIMP
 JSGCThingParticipant::Traverse(void* aPtr,
                                nsCycleCollectionTraversalCallback& aCb)
 {
   auto runtime = reinterpret_cast<CycleCollectedJSRuntime*>(
     reinterpret_cast<char*>(this) - offsetof(CycleCollectedJSRuntime,
                                              mGCThingCycleCollectorGlobal));
 
-  JS::GCCellPtr cellPtr(aPtr, js::GCThingTraceKind(aPtr));
+  JS::GCCellPtr cellPtr(aPtr, JS::GCThingTraceKind(aPtr));
   runtime->TraverseGCThing(CycleCollectedJSRuntime::TRAVERSE_FULL, cellPtr, aCb);
   return NS_OK;
 }
 
 // NB: This is only used to initialize the participant in
 // CycleCollectedJSRuntime. It should never be used directly.
 static JSGCThingParticipant sGCThingCycleCollectorGlobal;
 
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -3071,17 +3071,17 @@ nsCycleCollector::ScanIncrementalRoots()
     // If a GCed object was added to the graph with a refcount of zero, and is
     // now marked black by the GC, it was probably gray before and was exposed
     // to active JS, so it may have been stored somewhere, so it needs to be
     // treated as live.
     if (pi->IsGrayJS() && MOZ_LIKELY(hasJSRuntime)) {
       // If the object is still marked gray by the GC, nothing could have gotten
       // hold of it, so it isn't an incremental root.
       if (pi->mParticipant == jsParticipant) {
-        JS::GCCellPtr ptr(pi->mPointer, js::GCThingTraceKind(pi->mPointer));
+        JS::GCCellPtr ptr(pi->mPointer, JS::GCThingTraceKind(pi->mPointer));
         if (GCThingIsGrayCCThing(ptr)) {
           continue;
         }
       } else if (pi->mParticipant == zoneParticipant) {
         JS::Zone* zone = static_cast<JS::Zone*>(pi->mPointer);
         if (js::ZoneGlobalsAreAllGray(zone)) {
           continue;
         }
@@ -3286,17 +3286,17 @@ nsCycleCollector::CollectWhite()
       if (pinfo->IsGrayJS()) {
         MOZ_ASSERT(mJSRuntime);
         ++numWhiteGCed;
         JS::Zone* zone;
         if (MOZ_UNLIKELY(pinfo->mParticipant == zoneParticipant)) {
           ++numWhiteJSZones;
           zone = static_cast<JS::Zone*>(pinfo->mPointer);
         } else {
-          JS::GCCellPtr ptr(pinfo->mPointer, js::GCThingTraceKind(pinfo->mPointer));
+          JS::GCCellPtr ptr(pinfo->mPointer, JS::GCThingTraceKind(pinfo->mPointer));
           zone = JS::GetTenuredGCThingZone(ptr);
         }
         mJSRuntime->AddZoneWaitingForGC(zone);
       } else {
         whiteNodes.InfallibleAppend(pinfo);
         pinfo->mParticipant->Root(pinfo->mPointer);
         ++numWhiteNodes;
       }