Bug 1020690 - Type exact stack rooting machinery. r=sfink
☠☠ backed out by b2e6b3caa5a2 ☠ ☠
authorJon Coppeard <jcoppeard@mozilla.com>
Thu, 05 Jun 2014 10:38:00 -0400
changeset 206093 846ee7c7debfc1405079b2f981e061b7ec5598b3
parent 206092 f0e12744b2a9833e0ad283b7411f02f13f884a7d
child 206094 c0323d9a7ea32be54faf04fcd522ebb5a399127b
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1020690
milestone32.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 1020690 - Type exact stack rooting machinery. r=sfink
js/public/RootingAPI.h
js/src/NamespaceImports.h
js/src/gc/RootMarking.cpp
js/src/jsapi.h
js/src/jscntxt.cpp
js/src/jsinfer.h
js/src/jspubtd.h
js/src/jsscript.h
js/src/vm/Shape.h
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -629,21 +629,27 @@ class InternalHandle<T*>
       : holder(reinterpret_cast<void * const *>(&js::NullPtr::constNullValue)),
         offset(uintptr_t(field))
     {}
 
     void operator=(InternalHandle<T*> other) MOZ_DELETE;
 };
 
 /*
- * By default, pointers should use the inheritance hierarchy to find their
+ * By default, things should use the inheritance hierarchy to find their
  * ThingRootKind. Some pointer types are explicitly set in jspubtd.h so that
  * Rooted<T> may be used without the class definition being available.
  */
 template <typename T>
+struct RootKind
+{
+    static ThingRootKind rootKind() { return T::rootKind(); }
+};
+
+template <typename T>
 struct RootKind<T *>
 {
     static ThingRootKind rootKind() { return T::rootKind(); }
 };
 
 template <typename T>
 struct GCMethods<T *>
 {
@@ -787,17 +793,17 @@ class MOZ_STACK_CLASS Rooted : public js
 #ifdef JSGC_TRACK_EXACT_ROOTS
     ~Rooted() {
         MOZ_ASSERT(*stack == reinterpret_cast<Rooted<void*>*>(this));
         *stack = prev;
     }
 #endif
 
 #ifdef JSGC_TRACK_EXACT_ROOTS
-    Rooted<T> *previous() { return prev; }
+    Rooted<T> *previous() { return reinterpret_cast<Rooted<T>*>(prev); }
 #endif
 
     /*
      * Important: Return a reference here so passing a Rooted<T> to
      * something that takes a |const T&| is not a GC hazard.
      */
     operator const T&() const { return ptr; }
     T operator->() const { return ptr; }
@@ -822,17 +828,22 @@ class MOZ_STACK_CLASS Rooted : public js
         ptr = value;
     }
 
     bool operator!=(const T &other) const { return ptr != other; }
     bool operator==(const T &other) const { return ptr == other; }
 
   private:
 #ifdef JSGC_TRACK_EXACT_ROOTS
-    Rooted<void*> **stack, *prev;
+    /*
+     * These need to be templated on void* to avoid aliasing issues between, for
+     * example, Rooted<JSObject> and Rooted<JSFunction>, which use the same
+     * stack head pointer for different classes.
+     */
+    Rooted<void *> **stack, *prev;
 #endif
 
     /*
      * |ptr| must be the last field in Rooted because the analysis treats all
      * Rooted as Rooted<void*> during the analysis. See bug 829372.
      */
     T ptr;
 
@@ -858,71 +869,16 @@ namespace js {
 template <>
 class RootedBase<JSObject*>
 {
   public:
     template <class U>
     JS::Handle<U*> as() const;
 };
 
-
-/*
- * RootedGeneric<T> allows a class to instantiate its own Rooted type by
- * including the following two methods:
- *
- *    static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; }
- *    void trace(JSTracer *trc);
- *
- * The trace() method must trace all of the class's fields.
- *
- * Implementation:
- *
- * RootedGeneric<T> works by placing a pointer to its 'rooter' field into the
- * usual list of rooters when it is instantiated. When marking, it backs up
- * from this pointer to find a vtable containing a type-appropriate trace()
- * method.
- */
-template <typename GCType>
-class JS_PUBLIC_API(RootedGeneric)
-{
-  public:
-    JS::Rooted<GCType> rooter;
-
-    explicit RootedGeneric(js::ContextFriendFields *cx)
-        : rooter(cx)
-    {
-    }
-
-    RootedGeneric(js::ContextFriendFields *cx, const GCType &initial)
-        : rooter(cx, initial)
-    {
-    }
-
-    virtual inline void trace(JSTracer *trc);
-
-    operator const GCType&() const { return rooter.get(); }
-    GCType operator->() const { return rooter.get(); }
-};
-
-template <typename GCType>
-inline void RootedGeneric<GCType>::trace(JSTracer *trc)
-{
-    rooter->trace(trc);
-}
-
-// We will instantiate RootedGeneric<void*> in RootMarking.cpp, and MSVC will
-// notice that void*s have no trace() method defined on them and complain (even
-// though it's never called.) MSVC's complaint is not unreasonable, so
-// specialize for void*.
-template <>
-inline void RootedGeneric<void*>::trace(JSTracer *trc)
-{
-    MOZ_ASSUME_UNREACHABLE("RootedGeneric<void*>::trace()");
-}
-
 /* Interface substitute for Rooted<T> which does not root the variable's memory. */
 template <typename T>
 class FakeRooted : public RootedBase<T>
 {
   public:
     template <typename CX>
     FakeRooted(CX *cx
                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -31,16 +31,17 @@ class AutoScriptVector;
 class AutoValueVector;
 
 class AutoIdArray;
 
 class JS_PUBLIC_API(AutoGCRooter);
 template <typename T> class AutoVectorRooter;
 template<typename K, typename V> class AutoHashMapRooter;
 template<typename T> class AutoHashSetRooter;
+template<typename T> class RootedGeneric;
 
 class MOZ_STACK_CLASS SourceBufferHolder;
 
 class HandleValueArray;
 
 class JS_PUBLIC_API(AutoCheckCannotGC);
 
 }
@@ -78,16 +79,17 @@ using JS::AutoScriptVector;
 using JS::AutoValueVector;
 
 using JS::AutoIdArray;
 
 using JS::AutoGCRooter;
 using JS::AutoHashMapRooter;
 using JS::AutoHashSetRooter;
 using JS::AutoVectorRooter;
+using JS::RootedGeneric;
 
 using JS::CallArgs;
 using JS::CallNonGenericMethod;
 using JS::CallReceiver;
 using JS::CompileOptions;
 using JS::IsAcceptableThis;
 using JS::NativeImpl;
 using JS::OwningCompileOptions;
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -35,69 +35,87 @@ using namespace js::gc;
 
 using mozilla::ArrayEnd;
 
 typedef RootedValueMap::Range RootRange;
 typedef RootedValueMap::Entry RootEntry;
 typedef RootedValueMap::Enum RootEnum;
 
 #ifdef JSGC_USE_EXACT_ROOTING
-static inline void
-MarkExactStackRoot(JSTracer *trc, Rooted<void*> *rooter, ThingRootKind kind)
+static void
+MarkBindingsRoot(JSTracer *trc, Bindings *bindings, const char *name)
+{
+    bindings->trace(trc);
+}
+
+static void
+MarkPropertyDescriptorRoot(JSTracer *trc, JSPropertyDescriptor *pd, const char *name)
 {
-    void **addr = (void **)rooter->address();
-    if (IsNullTaggedPointer(*addr))
-        return;
+    pd->trace(trc);
+}
 
-    if (kind == THING_ROOT_OBJECT && *addr == TaggedProto::LazyProto)
-        return;
+template <class T>
+static inline bool
+IgnoreExactRoot(T *thingp)
+{
+    return false;
+}
 
-    switch (kind) {
-      case THING_ROOT_OBJECT:      MarkObjectRoot(trc, (JSObject **)addr, "exact-object"); break;
-      case THING_ROOT_STRING:      MarkStringRoot(trc, (JSString **)addr, "exact-string"); break;
-      case THING_ROOT_SCRIPT:      MarkScriptRoot(trc, (JSScript **)addr, "exact-script"); break;
-      case THING_ROOT_LAZY_SCRIPT: MarkLazyScriptRoot(trc, (LazyScript **)addr, "exact-lazy-script"); break;
-      case THING_ROOT_SHAPE:       MarkShapeRoot(trc, (Shape **)addr, "exact-shape"); break;
-      case THING_ROOT_BASE_SHAPE:  MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact-baseshape"); break;
-      case THING_ROOT_TYPE:        MarkTypeRoot(trc, (types::Type *)addr, "exact-type"); break;
-      case THING_ROOT_TYPE_OBJECT: MarkTypeObjectRoot(trc, (types::TypeObject **)addr, "exact-typeobject"); break;
-      case THING_ROOT_JIT_CODE:    MarkJitCodeRoot(trc, (jit::JitCode **)addr, "exact-jitcode"); break;
-      case THING_ROOT_VALUE:       MarkValueRoot(trc, (Value *)addr, "exact-value"); break;
-      case THING_ROOT_ID:          MarkIdRoot(trc, (jsid *)addr, "exact-id"); break;
-      case THING_ROOT_BINDINGS:    ((Bindings *)addr)->trace(trc); break;
-      case THING_ROOT_PROPERTY_DESCRIPTOR: ((JSPropertyDescriptor *)addr)->trace(trc); break;
-      case THING_ROOT_CUSTOM: {
-          // 'rooter' is a member within a class containing a vtable. Back up
-          // to the vtable and call trace() through it.
-          const size_t rooterOffset = offsetof(RootedGeneric<void*>, rooter);
-          reinterpret_cast< RootedGeneric<void*>* >(uintptr_t(rooter) - rooterOffset)->trace(trc);
-          break;
-      }
-      default: MOZ_ASSUME_UNREACHABLE("Invalid THING_ROOT kind"); break;
+template <class T>
+inline bool
+IgnoreExactRoot(T **thingp)
+{
+    return IsNullTaggedPointer(*thingp);
+}
+
+template <>
+inline bool
+IgnoreExactRoot(JSObject **thingp)
+{
+    return IsNullTaggedPointer(*thingp) || *thingp == TaggedProto::LazyProto;
+}
+
+template <class T, void (MarkFunc)(JSTracer *trc, T *ref, const char *name), class Source>
+static inline void
+MarkExactStackRootList(JSTracer *trc, Source *s, const char *name)
+{
+    Rooted<T> *rooter = s->template gcRooters<T>();
+    while (rooter) {
+        T *addr = rooter->address();
+        if (!IgnoreExactRoot(addr))
+            MarkFunc(trc, addr, name);
+        rooter = rooter->previous();
     }
 }
 
+template <class T, void (MarkFunc)(JSTracer *trc, T *ref, const char *name)>
 static inline void
-MarkExactStackRootList(JSTracer *trc, Rooted<void*> *rooter, ThingRootKind kind)
+MarkExactStackRootsForType(JSTracer *trc, const char *name = nullptr)
 {
-    while (rooter) {
-        MarkExactStackRoot(trc, rooter, kind);
-        rooter = rooter->previous();
-    }
+    for (ContextIter cx(trc->runtime()); !cx.done(); cx.next())
+        MarkExactStackRootList<T, MarkFunc>(trc, cx.get(), name);
+    MarkExactStackRootList<T, MarkFunc>(trc, &trc->runtime()->mainThread, name);
 }
 
 static void
 MarkExactStackRoots(JSTracer *trc)
 {
-    for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
-        for (ContextIter cx(trc->runtime()); !cx.done(); cx.next())
-            MarkExactStackRootList(trc, cx->thingGCRooters[i], ThingRootKind(i));
-
-        MarkExactStackRootList(trc, trc->runtime()->mainThread.thingGCRooters[i], ThingRootKind(i));
-    }
+    MarkExactStackRootsForType<JSObject *, MarkObjectRoot>(trc, "exact-object");
+    MarkExactStackRootsForType<Shape *, MarkShapeRoot>(trc, "exact-shape");
+    MarkExactStackRootsForType<BaseShape *, MarkBaseShapeRoot>(trc, "exact-baseshape");
+    MarkExactStackRootsForType<types::TypeObject *, MarkTypeObjectRoot>(trc, "exact-typeobject");
+    MarkExactStackRootsForType<JSString *, MarkStringRoot>(trc, "exact-string");
+    MarkExactStackRootsForType<jit::JitCode *, MarkJitCodeRoot>(trc, "exact-jitcode");
+    MarkExactStackRootsForType<JSScript *, MarkScriptRoot>(trc, "exact-script");
+    MarkExactStackRootsForType<LazyScript *, MarkLazyScriptRoot>(trc, "exact-lazy-script");
+    MarkExactStackRootsForType<jsid, MarkIdRoot>(trc, "exact-id");
+    MarkExactStackRootsForType<Value, MarkValueRoot>(trc, "exact-value");
+    MarkExactStackRootsForType<types::Type, MarkTypeRoot>(trc, "exact-type");
+    MarkExactStackRootsForType<Bindings, MarkBindingsRoot>(trc);
+    MarkExactStackRootsForType<JSPropertyDescriptor, MarkPropertyDescriptorRoot>(trc);
 }
 #endif /* JSGC_USE_EXACT_ROOTING */
 
 enum ConservativeGCTest
 {
     CGCT_VALID,
     CGCT_LOWBITSET, /* excluded because one of the low bits was set */
     CGCT_NOTARENA,  /* not within arena range in a chunk */
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -586,16 +586,53 @@ class JS_PUBLIC_API(CustomAutoRooter) : 
   protected:
     /* Supplied by derived class to trace roots. */
     virtual void trace(JSTracer *trc) = 0;
 
   private:
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
+/*
+ * RootedGeneric<T> allows a class to instantiate its own Rooted type by
+ * including the method:
+ *
+ *    void trace(JSTracer *trc);
+ *
+ * The trace() method must trace all of the class's fields.
+ */
+template <class T>
+class RootedGeneric : private CustomAutoRooter
+{
+  public:
+    template <typename CX>
+    explicit RootedGeneric(CX *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : CustomAutoRooter(cx)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+
+    template <typename CX>
+    explicit RootedGeneric(CX *cx, const T& initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : CustomAutoRooter(cx), value(initial)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+
+    operator const T&() const { return value; }
+    T operator->() const { return value; }
+
+  private:
+    virtual void trace(JSTracer *trc) { value->trace(trc); }
+
+    T value;
+
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 /* A handle to an array of rooted values. */
 class HandleValueArray
 {
     const size_t length_;
     const Value * const elements_;
 
     HandleValueArray(size_t len, const Value *elements) : length_(len), elements_(elements) {}
 
@@ -2873,16 +2910,18 @@ struct JSPropertyDescriptor {
     JSStrictPropertyOp setter;
     JS::Value          value;
 
     JSPropertyDescriptor()
       : obj(nullptr), attrs(0), getter(nullptr), setter(nullptr), value(JSVAL_VOID)
     {}
 
     void trace(JSTracer *trc);
+
+    static js::ThingRootKind rootKind() { return js::THING_ROOT_PROPERTY_DESCRIPTOR; }
 };
 
 namespace JS {
 
 template <typename Outer>
 class PropertyDescriptorOperations
 {
     const JSPropertyDescriptor * desc() const { return static_cast<const Outer*>(this)->extract(); }
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -226,20 +226,17 @@ js::DestroyContext(JSContext *cx, Destro
     JSRuntime *rt = cx->runtime();
     JS_AbortIfWrongThread(rt);
 
 #ifdef JS_THREADSAFE
     if (cx->outstandingRequests != 0)
         MOZ_CRASH();
 #endif
 
-#if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG)
-    for (int i = 0; i < THING_ROOT_LIMIT; ++i)
-        JS_ASSERT(cx->thingGCRooters[i] == nullptr);
-#endif
+    cx->checkNoGCRooters();
 
     if (mode != DCM_NEW_FAILED) {
         if (JSContextCallback cxCallback = rt->cxCallback) {
             /*
              * JSCONTEXT_DESTROY callback is not allowed to fail and must
              * return true.
              */
             JS_ALWAYS_TRUE(cxCallback(cx, JSCONTEXT_DESTROY,
@@ -260,16 +257,24 @@ js::DestroyContext(JSContext *cx, Destro
     if (mode == DCM_FORCE_GC) {
         JS_ASSERT(!rt->isHeapBusy());
         JS::PrepareForFullGC(rt);
         GC(rt, GC_NORMAL, JS::gcreason::DESTROY_CONTEXT);
     }
     js_delete_poison(cx);
 }
 
+void
+ContextFriendFields::checkNoGCRooters() {
+#if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG)
+    for (int i = 0; i < THING_ROOT_LIMIT; ++i)
+        JS_ASSERT(thingGCRooters[i] == nullptr);
+#endif
+}
+
 bool
 AutoResolving::alreadyStartedSlow() const
 {
     JS_ASSERT(link);
     AutoResolving *cursor = link;
     do {
         JS_ASSERT(this != cursor);
         if (object.get() == cursor->object && id.get() == cursor->id && kind == cursor->kind)
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -304,16 +304,18 @@ class Type
     static inline Type PrimitiveType(JSValueType type) {
         JS_ASSERT(type < JSVAL_TYPE_UNKNOWN);
         return Type(type);
     }
 
     static inline Type ObjectType(JSObject *obj);
     static inline Type ObjectType(TypeObject *obj);
     static inline Type ObjectType(TypeObjectKey *obj);
+
+    static js::ThingRootKind rootKind() { return js::THING_ROOT_TYPE; }
 };
 
 /* Get the type of a jsval, or zero for an unknown special value. */
 inline Type GetValueType(const Value &val);
 
 /*
  * Get the type of a possibly optimized out value. This generally only
  * happens on unconditional type monitors on bailing out of Ion, such as
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -274,17 +274,16 @@ enum ThingRootKind
     THING_ROOT_JIT_CODE,
     THING_ROOT_SCRIPT,
     THING_ROOT_LAZY_SCRIPT,
     THING_ROOT_ID,
     THING_ROOT_VALUE,
     THING_ROOT_TYPE,
     THING_ROOT_BINDINGS,
     THING_ROOT_PROPERTY_DESCRIPTOR,
-    THING_ROOT_CUSTOM,
     THING_ROOT_LIMIT
 };
 
 /*
  * This list enumerates the different types of conceptual stacks we have in
  * SpiderMonkey. In reality, they all share the C stack, but we allow different
  * stack limits depending on the type of code running.
  */
@@ -342,29 +341,41 @@ struct ContextFriendFields
         return reinterpret_cast<const ContextFriendFields *>(cx);
     }
 
     static ContextFriendFields *get(JSContext *cx) {
         return reinterpret_cast<ContextFriendFields *>(cx);
     }
 
 #ifdef JSGC_TRACK_EXACT_ROOTS
+  private:
     /*
      * Stack allocated GC roots for stack GC heap pointers, which may be
      * overwritten if moved during a GC.
      */
     JS::Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
+
+  public:
+    template <class T>
+    inline JS::Rooted<T> *gcRooters() {
+        js::ThingRootKind kind = RootKind<T>::rootKind();
+        return reinterpret_cast<JS::Rooted<T> *>(thingGCRooters[kind]);
+    }
+
 #endif
 
+    void checkNoGCRooters();
+
     /* Stack of thread-stack-allocated GC roots. */
     JS::AutoGCRooter   *autoGCRooters;
 
     friend JSRuntime *GetRuntime(const JSContext *cx);
     friend JSCompartment *GetContextCompartment(const JSContext *cx);
     friend JS::Zone *GetContextZone(const JSContext *cx);
+    template <typename T> friend class JS::Rooted;
 };
 
 /*
  * Inlinable accessors for JSContext.
  *
  * - These must not be available on the more restricted superclasses of
  *   JSContext, so we can't simply define them on ContextFriendFields.
  *
@@ -409,21 +420,29 @@ struct PerThreadDataFriendFields
         } mainThread;
     };
 
   public:
 
     PerThreadDataFriendFields();
 
 #ifdef JSGC_TRACK_EXACT_ROOTS
+  private:
     /*
      * Stack allocated GC roots for stack GC heap pointers, which may be
      * overwritten if moved during a GC.
      */
     JS::Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
+
+  public:
+    template <class T>
+    inline JS::Rooted<T> *gcRooters() {
+        js::ThingRootKind kind = RootKind<T>::rootKind();
+        return reinterpret_cast<JS::Rooted<T> *>(thingGCRooters[kind]);
+    }
 #endif
 
     /* Limit pointer for checking native stack consumption. */
     uintptr_t nativeStackLimit[StackKindCount];
 
     static const size_t RuntimeMainThreadOffset = offsetof(RuntimeDummy, mainThread);
 
     static inline PerThreadDataFriendFields *get(js::PerThreadData *pt) {
@@ -438,13 +457,15 @@ struct PerThreadDataFriendFields
     }
 
     static inline const PerThreadDataFriendFields *getMainThread(const JSRuntime *rt) {
         // mainThread must always appear directly after |JS::shadow::Runtime|.
         // Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp|
         return reinterpret_cast<const PerThreadDataFriendFields *>(
             reinterpret_cast<const char*>(rt) + RuntimeMainThreadOffset);
     }
+
+    template <typename T> friend class JS::Rooted;
 };
 
 } /* namespace js */
 
 #endif /* jspubtd_h */
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -261,16 +261,17 @@ class Bindings
     /* Return whether this scope has any aliased bindings. */
     bool hasAnyAliasedBindings() const {
         if (!callObjShape_)
             return false;
 
         return !callObjShape_->isEmptyShape();
     }
 
+    static js::ThingRootKind rootKind() { return js::THING_ROOT_BINDINGS; }
     void trace(JSTracer *trc);
 };
 
 template <>
 struct GCMethods<Bindings> {
     static Bindings initial();
     static ThingRootKind kind() { return THING_ROOT_BINDINGS; }
     static bool poisoned(const Bindings &bindings) {
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -848,17 +848,16 @@ struct StackBaseShape
         this->rawGetter = rawGetter;
         this->rawSetter = rawSetter;
     }
 
     static inline HashNumber hash(const StackBaseShape *lookup);
     static inline bool match(UnownedBaseShape *key, const StackBaseShape *lookup);
 
     // For RootedGeneric<StackBaseShape*>
-    static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; }
     void trace(JSTracer *trc);
 };
 
 inline
 BaseShape::BaseShape(const StackBaseShape &base)
 {
     mozilla::PodZero(this);
     this->clasp_ = base.clasp;
@@ -1500,17 +1499,16 @@ struct StackShape
         /* Accumulate from least to most random so the low bits are most random. */
         hash = mozilla::RotateLeft(hash, 4) ^ attrs;
         hash = mozilla::RotateLeft(hash, 4) ^ slot_;
         hash = mozilla::RotateLeft(hash, 4) ^ JSID_BITS(propid);
         return hash;
     }
 
     // For RootedGeneric<StackShape*>
-    static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; }
     void trace(JSTracer *trc);
 };
 
 } /* namespace js */
 
 /* js::Shape pointer tag bit indicating a collision. */
 #define SHAPE_COLLISION                 (uintptr_t(1))
 #define SHAPE_REMOVED                   ((js::Shape *) SHAPE_COLLISION)