Bug 1268805 - Implement PrivateGCThingValue. (r=terrence)
authorShu-yu Guo <shu@rfrn.org>
Fri, 29 Apr 2016 18:10:07 -0700
changeset 295594 fdea8d099dbd8fee22f222f92bc784af46292239
parent 295593 b622cbd9ba13d01abcb1d04684dcb39c22a08590
child 295595 774c838c19e217e177ba22876d57a344b54c33e4
push id30226
push usercbook@mozilla.com
push dateMon, 02 May 2016 09:26:03 +0000
treeherdermozilla-central@77cead2cd203 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1268805
milestone49.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 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(void* 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 = cell;
+    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(void* thing)
+{
+    MOZ_ASSERT(thing);
+    return static_cast<js::gc::Cell*>(thing)->getTraceKind();
+}
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -582,23 +582,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
@@ -505,19 +505,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;
       }