Bug 1282795 - Declare JS::ubi::Concrete<T>::concreteTypeName within every JS::ubi::Concrete specialization to avoid use-before-declaration warnings related to templates. r=jimb
☠☠ backed out by 015a827edf56 ☠ ☠
authorJeff Walden <jwalden@mit.edu>
Tue, 05 Jul 2016 17:41:12 -0700
changeset 304051 2620e5ba1067b251c31fc29ef6f507db97ac3ffb
parent 304050 c23ae65921f0402f3c1fe91458583877be14c452
child 304052 015a827edf567ce10c866c655aa6d7759d5871f7
push id30410
push userkwierso@gmail.com
push dateFri, 08 Jul 2016 00:15:43 +0000
treeherdermozilla-central@4e3c16ea8fce [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs1282795
milestone50.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 1282795 - Declare JS::ubi::Concrete<T>::concreteTypeName within every JS::ubi::Concrete specialization to avoid use-before-declaration warnings related to templates. r=jimb
devtools/shared/heapsnapshot/DeserializedNode.h
js/public/UbiNode.h
js/src/jit/IonCode.h
js/src/jsapi-tests/testUbiNode.cpp
js/src/jsobj.cpp
js/src/jsscript.h
js/src/vm/Shape.h
js/src/vm/String.cpp
js/src/vm/TypeInference.h
js/src/vm/UbiNode.cpp
--- a/devtools/shared/heapsnapshot/DeserializedNode.h
+++ b/devtools/shared/heapsnapshot/DeserializedNode.h
@@ -239,27 +239,25 @@ struct DeserializedStackFrame::HashPolic
 
 namespace JS {
 namespace ubi {
 
 using mozilla::devtools::DeserializedNode;
 using mozilla::devtools::DeserializedStackFrame;
 
 template<>
-struct Concrete<DeserializedNode> : public Base
+class Concrete<DeserializedNode> : public Base
 {
 protected:
   explicit Concrete(DeserializedNode* ptr) : Base(ptr) { }
   DeserializedNode& get() const {
     return *static_cast<DeserializedNode*>(ptr);
   }
 
 public:
-  static const char16_t concreteTypeName[];
-
   static void construct(void* storage, DeserializedNode* ptr) {
     new (storage) Concrete(ptr);
   }
 
   CoarseType coarseType() const final { return get().coarseType; }
   Id identifier() const override { return get().id; }
   bool isLive() const override { return false; }
   const char16_t* typeName() const override;
@@ -268,16 +266,18 @@ public:
   const char* scriptFilename() const final { return get().scriptFilename; }
 
   bool hasAllocationStack() const override { return get().allocationStack.isSome(); }
   StackFrame allocationStack() const override;
 
   // We ignore the `bool wantNames` parameter because we can't control whether
   // the core dump was serialized with edge names or not.
   js::UniquePtr<EdgeRange> edges(JSRuntime* rt, bool) const override;
+
+  static const char16_t concreteTypeName[];
 };
 
 template<>
 class ConcreteStackFrame<DeserializedStackFrame> : public BaseStackFrame
 {
 protected:
   explicit ConcreteStackFrame(DeserializedStackFrame* ptr)
     : BaseStackFrame(ptr)
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -636,38 +636,38 @@ class Base {
     virtual const char* scriptFilename() const { return nullptr; }
 
   private:
     Base(const Base& rhs) = delete;
     Base& operator=(const Base& rhs) = delete;
 };
 
 // A traits template with a specialization for each referent type that
-// ubi::Node supports. The specialization must be the concrete subclass of
-// Base that represents a pointer to the referent type. It must also
-// include the members described here.
+// ubi::Node supports. The specialization must be the concrete subclass of Base
+// that represents a pointer to the referent type. It must include these
+// members:
+//
+//    // The specific char16_t array returned by Concrete<T>::typeName().
+//    static const char16_t concreteTypeName[];
+//
+//    // Construct an instance of this concrete class in |storage| referring
+//    // to |referent|. Implementations typically use a placement 'new'.
+//    //
+//    // In some cases, |referent| will contain dynamic type information that
+//    // identifies it a some more specific subclass of |Referent|. For
+//    // example, when |Referent| is |JSObject|, then |referent->getClass()|
+//    // could tell us that it's actually a JSFunction. Similarly, if
+//    // |Referent| is |nsISupports|, we would like a ubi::Node that knows its
+//    // final implementation type.
+//    //
+//    // So we delegate the actual construction to this specialization, which
+//    // knows Referent's details.
+//    static void construct(void* storage, Referent* referent);
 template<typename Referent>
-struct Concrete {
-    // The specific char16_t array returned by Concrete<T>::typeName.
-    static const char16_t concreteTypeName[];
-
-    // Construct an instance of this concrete class in |storage| referring
-    // to |referent|. Implementations typically use a placement 'new'.
-    //
-    // In some cases, |referent| will contain dynamic type information that
-    // identifies it a some more specific subclass of |Referent|. For example,
-    // when |Referent| is |JSObject|, then |referent->getClass()| could tell us
-    // that it's actually a JSFunction. Similarly, if |Referent| is
-    // |nsISupports|, we would like a ubi::Node that knows its final
-    // implementation type.
-    //
-    // So, we delegate the actual construction to this specialization, which
-    // knows Referent's details.
-    static void construct(void* storage, Referent* referent);
-};
+class Concrete;
 
 // A container for a Base instance; all members simply forward to the contained
 // instance.  This container allows us to pass ubi::Node instances by value.
 class Node {
     // Storage in which we allocate Base subclasses.
     mozilla::AlignedStorage2<Base> storage;
     Base* base() { return storage.addr(); }
     const Base* base() const { return storage.addr(); }
@@ -989,43 +989,42 @@ class MOZ_STACK_CLASS RootList {
     // edgeName.
     MOZ_MUST_USE bool addRoot(Node node, const char16_t* edgeName = nullptr);
 };
 
 
 /*** Concrete classes for ubi::Node referent types ************************************************/
 
 template<>
-struct Concrete<RootList> : public Base {
-    js::UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override;
-    const char16_t* typeName() const override { return concreteTypeName; }
-
+class Concrete<RootList> : public Base {
   protected:
     explicit Concrete(RootList* ptr) : Base(ptr) { }
     RootList& get() const { return *static_cast<RootList*>(ptr); }
 
   public:
+    static void construct(void* storage, RootList* ptr) { new (storage) Concrete(ptr); }
+
+    js::UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override;
+
+    const char16_t* typeName() const override { return concreteTypeName; }
     static const char16_t concreteTypeName[];
-    static void construct(void* storage, RootList* ptr) { new (storage) Concrete(ptr); }
 };
 
 // A reusable ubi::Concrete specialization base class for types supported by
 // JS::TraceChildren.
 template<typename Referent>
 class TracerConcrete : public Base {
-    const char16_t* typeName() const override { return concreteTypeName; }
     js::UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override;
     JS::Zone* zone() const override;
 
   protected:
     explicit TracerConcrete(Referent* ptr) : Base(ptr) { }
     Referent& get() const { return *static_cast<Referent*>(ptr); }
 
   public:
-    static const char16_t concreteTypeName[];
     static void construct(void* storage, Referent* ptr) { new (storage) TracerConcrete(ptr); }
 };
 
 // For JS::TraceChildren-based types that have a 'compartment' method.
 template<typename Referent>
 class TracerConcreteWithCompartment : public TracerConcrete<Referent> {
     typedef TracerConcrete<Referent> TracerBase;
     JSCompartment* compartment() const override;
@@ -1037,90 +1036,103 @@ class TracerConcreteWithCompartment : pu
     static void construct(void* storage, Referent* ptr) {
         new (storage) TracerConcreteWithCompartment(ptr);
     }
 };
 
 // Define specializations for some commonly-used public JSAPI types.
 // These can use the generic templates above.
 template<>
-struct Concrete<JS::Symbol> : TracerConcrete<JS::Symbol> {
-    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
-
+class Concrete<JS::Symbol> : TracerConcrete<JS::Symbol> {
   protected:
     explicit Concrete(JS::Symbol* ptr) : TracerConcrete(ptr) { }
 
   public:
     static void construct(void* storage, JS::Symbol* ptr) {
         new (storage) Concrete(ptr);
     }
+
+    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+    const char16_t* typeName() const override { return concreteTypeName; }
+    static const char16_t concreteTypeName[];
 };
 
-template<> struct Concrete<JSScript> : TracerConcreteWithCompartment<JSScript> {
-    CoarseType coarseType() const final { return CoarseType::Script; }
-    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
-    const char* scriptFilename() const final;
-
+template<>
+class Concrete<JSScript> : TracerConcreteWithCompartment<JSScript> {
   protected:
     explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment<JSScript>(ptr) { }
 
   public:
     static void construct(void *storage, JSScript *ptr) { new (storage) Concrete(ptr); }
+
+    CoarseType coarseType() const final { return CoarseType::Script; }
+    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+    const char* scriptFilename() const final;
+
+    const char16_t* typeName() const override { return concreteTypeName; }
+    static const char16_t concreteTypeName[];
 };
 
 // The JSObject specialization.
 template<>
 class Concrete<JSObject> : public TracerConcreteWithCompartment<JSObject> {
+  protected:
+    explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) { }
+
+  public:
+    static void construct(void* storage, JSObject* ptr) {
+        new (storage) Concrete(ptr);
+    }
+
     const char* jsObjectClassName() const override;
     MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName)
         const override;
     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
 
     bool hasAllocationStack() const override;
     StackFrame allocationStack() const override;
 
     CoarseType coarseType() const final { return CoarseType::Object; }
 
-  protected:
-    explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) { }
-
-  public:
-    static void construct(void* storage, JSObject* ptr) {
-        new (storage) Concrete(ptr);
-    }
+    const char16_t* typeName() const override { return concreteTypeName; }
+    static const char16_t concreteTypeName[];
 };
 
 // For JSString, we extend the generic template with a 'size' implementation.
-template<> struct Concrete<JSString> : TracerConcrete<JSString> {
-    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
-
-    CoarseType coarseType() const final { return CoarseType::String; }
-
+template<>
+class Concrete<JSString> : TracerConcrete<JSString> {
   protected:
     explicit Concrete(JSString *ptr) : TracerConcrete<JSString>(ptr) { }
 
   public:
     static void construct(void *storage, JSString *ptr) { new (storage) Concrete(ptr); }
+
+    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+    CoarseType coarseType() const final { return CoarseType::String; }
+
+    const char16_t* typeName() const override { return concreteTypeName; }
+    static const char16_t concreteTypeName[];
 };
 
 // The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts.
 template<>
 class Concrete<void> : public Base {
     const char16_t* typeName() const override;
     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
     js::UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override;
     JS::Zone* zone() const override;
     JSCompartment* compartment() const override;
     CoarseType coarseType() const final;
 
     explicit Concrete(void* ptr) : Base(ptr) { }
 
   public:
     static void construct(void* storage, void* ptr) { new (storage) Concrete(ptr); }
-    static const char16_t concreteTypeName[];
 };
 
 
 } // namespace ubi
 } // namespace JS
 
 namespace js {
 
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -783,31 +783,34 @@ IsMarked(const jit::VMFunction*)
 
 } // namespace js
 
 // JS::ubi::Nodes can point to js::jit::JitCode instances; they're js::gc::Cell
 // instances with no associated compartment.
 namespace JS {
 namespace ubi {
 template<>
-struct Concrete<js::jit::JitCode> : TracerConcrete<js::jit::JitCode> {
+class Concrete<js::jit::JitCode> : TracerConcrete<js::jit::JitCode> {
+  protected:
+    explicit Concrete(js::jit::JitCode *ptr) : TracerConcrete<js::jit::JitCode>(ptr) { }
+
+  public:
+    static void construct(void *storage, js::jit::JitCode *ptr) { new (storage) Concrete(ptr); }
+
     CoarseType coarseType() const final { return CoarseType::Script; }
 
     Size size(mozilla::MallocSizeOf mallocSizeOf) const override {
         Size size = js::gc::Arena::thingSize(get().asTenured().getAllocKind());
         size += get().bufferSize();
         size += get().headerSize();
         return size;
     }
 
-  protected:
-    explicit Concrete(js::jit::JitCode *ptr) : TracerConcrete<js::jit::JitCode>(ptr) { }
-
-  public:
-    static void construct(void *storage, js::jit::JitCode *ptr) { new (storage) Concrete(ptr); }
+    const char16_t* typeName() const override { return concreteTypeName; }
+    static const char16_t concreteTypeName[];
 };
 
 } // namespace ubi
 
 template <>
 struct DeletePolicy<js::jit::IonScript>
 {
     explicit DeletePolicy(JSRuntime* rt) : rt_(rt) {}
--- a/js/src/jsapi-tests/testUbiNode.cpp
+++ b/js/src/jsapi-tests/testUbiNode.cpp
@@ -36,34 +36,35 @@ struct FakeNode
         return edges.emplaceBack(nullptr, node);
     }
 };
 
 namespace JS {
 namespace ubi {
 
 template<>
-struct Concrete<FakeNode> : public Base
+class Concrete<FakeNode> : public Base
 {
-    static const char16_t concreteTypeName[];
-    const char16_t* typeName() const override { return concreteTypeName; }
+  protected:
+    explicit Concrete(FakeNode* ptr) : Base(ptr) { }
+    FakeNode& get() const { return *static_cast<FakeNode*>(ptr); }
+
+  public:
+    static void construct(void* storage, FakeNode* ptr) { new (storage) Concrete(ptr); }
 
     UniquePtr<EdgeRange> edges(JSRuntime* rt, bool wantNames) const override {
         return UniquePtr<EdgeRange>(js_new<PreComputedEdgeRange>(get().edges));
     }
 
     Node::Size size(mozilla::MallocSizeOf) const override {
         return 1;
     }
 
-    static void construct(void* storage, FakeNode* ptr) { new (storage) Concrete(ptr); }
-
-  protected:
-    explicit Concrete(FakeNode* ptr) : Base(ptr) { }
-    FakeNode& get() const { return *static_cast<FakeNode*>(ptr); }
+    static const char16_t concreteTypeName[];
+    const char16_t* typeName() const override { return concreteTypeName; }
 };
 
 const char16_t Concrete<FakeNode>::concreteTypeName[] = MOZ_UTF16("FakeNode");
 
 } // namespace ubi
 } // namespace JS
 
 // ubi::Node::zone works
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3826,18 +3826,17 @@ JS::ubi::Concrete<JSObject>::size(mozill
     if (!obj.isTenured())
         return obj.sizeOfIncludingThisInNursery();
 
     JS::ClassInfo info;
     obj.addSizeOfExcludingThis(mallocSizeOf, &info);
     return obj.tenuredSizeOfThis() + info.sizeOfAllThings();
 }
 
-template<> const char16_t JS::ubi::TracerConcrete<JSObject>::concreteTypeName[] =
-    MOZ_UTF16("JSObject");
+const char16_t JS::ubi::Concrete<JSObject>::concreteTypeName[] = MOZ_UTF16("JSObject");
 
 void
 JSObject::traceChildren(JSTracer* trc)
 {
     TraceEdge(trc, &group_, "group");
 
     const Class* clasp = group_->clasp();
     if (clasp->isNative()) {
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -2547,23 +2547,26 @@ CloneGlobalScript(JSContext* cx, Handle<
 
 } /* namespace js */
 
 // JS::ubi::Nodes can point to js::LazyScripts; they're js::gc::Cell instances
 // with no associated compartment.
 namespace JS {
 namespace ubi {
 template<>
-struct Concrete<js::LazyScript> : TracerConcrete<js::LazyScript> {
-    CoarseType coarseType() const final { return CoarseType::Script; }
-    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
-    const char* scriptFilename() const final;
-
+class Concrete<js::LazyScript> : TracerConcrete<js::LazyScript> {
   protected:
     explicit Concrete(js::LazyScript *ptr) : TracerConcrete<js::LazyScript>(ptr) { }
 
   public:
     static void construct(void *storage, js::LazyScript *ptr) { new (storage) Concrete(ptr); }
+
+    CoarseType coarseType() const final { return CoarseType::Script; }
+    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+    const char* scriptFilename() const final;
+
+    const char16_t* typeName() const override { return concreteTypeName; }
+    static const char16_t concreteTypeName[];
 };
 } // namespace ubi
 } // namespace JS
 
 #endif /* jsscript_h */
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -533,17 +533,17 @@ class Shape : public gc::TenuredCell
     friend class ::JSFunction;
     friend class Bindings;
     friend class NativeObject;
     friend class PropertyTree;
     friend class StaticBlockScope;
     friend class TenuringTracer;
     friend struct StackBaseShape;
     friend struct StackShape;
-    friend struct JS::ubi::Concrete<Shape>;
+    friend class JS::ubi::Concrete<Shape>;
     friend class js::gc::RelocationOverlay;
 
   protected:
     GCPtrBaseShape base_;
     PreBarrieredId propid_;
 
     enum SlotInfo : uint32_t
     {
@@ -1454,32 +1454,40 @@ ReshapeForAllocKind(JSContext* cx, Shape
 #pragma warning(pop)
 #endif
 
 // JS::ubi::Nodes can point to Shapes and BaseShapes; they're js::gc::Cell
 // instances that occupy a compartment.
 namespace JS {
 namespace ubi {
 
-template<> struct Concrete<js::Shape> : TracerConcreteWithCompartment<js::Shape> {
-    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
-
+template<>
+class Concrete<js::Shape> : TracerConcreteWithCompartment<js::Shape> {
   protected:
     explicit Concrete(js::Shape *ptr) : TracerConcreteWithCompartment<js::Shape>(ptr) { }
 
   public:
     static void construct(void *storage, js::Shape *ptr) { new (storage) Concrete(ptr); }
+
+    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+    const char16_t* typeName() const override { return concreteTypeName; }
+    static const char16_t concreteTypeName[];
 };
 
-template<> struct Concrete<js::BaseShape> : TracerConcreteWithCompartment<js::BaseShape> {
-    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
-
+template<>
+class Concrete<js::BaseShape> : TracerConcreteWithCompartment<js::BaseShape> {
   protected:
     explicit Concrete(js::BaseShape *ptr) : TracerConcreteWithCompartment<js::BaseShape>(ptr) { }
 
   public:
     static void construct(void *storage, js::BaseShape *ptr) { new (storage) Concrete(ptr); }
+
+    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+    const char16_t* typeName() const override { return concreteTypeName; }
+    static const char16_t concreteTypeName[];
 };
 
 } // namespace ubi
 } // namespace JS
 
 #endif /* vm_Shape_h */
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -77,18 +77,17 @@ JS::ubi::Concrete<JSString>::size(mozill
     // We can't use mallocSizeof on things in the nursery. At the moment,
     // strings are never in the nursery, but that may change.
     MOZ_ASSERT(!IsInsideNursery(&str));
     size += str.sizeOfExcludingThis(mallocSizeOf);
 
     return size;
 }
 
-template<> const char16_t JS::ubi::TracerConcrete<JSString>::concreteTypeName[] =
-    MOZ_UTF16("JSString");
+const char16_t JS::ubi::Concrete<JSString>::concreteTypeName[] = MOZ_UTF16("JSString");
 
 #ifdef DEBUG
 
 template <typename CharT>
 /*static */ void
 JSString::dumpChars(const CharT* s, size_t n, FILE* fp)
 {
     if (n == SIZE_MAX) {
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -1320,22 +1320,25 @@ PrintTypes(JSContext* cx, JSCompartment*
 } /* namespace js */
 
 // JS::ubi::Nodes can point to object groups; they're js::gc::Cell instances
 // with no associated compartment.
 namespace JS {
 namespace ubi {
 
 template<>
-struct Concrete<js::ObjectGroup> : TracerConcrete<js::ObjectGroup> {
-    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
-
+class Concrete<js::ObjectGroup> : TracerConcrete<js::ObjectGroup> {
   protected:
     explicit Concrete(js::ObjectGroup *ptr) : TracerConcrete<js::ObjectGroup>(ptr) { }
 
   public:
     static void construct(void *storage, js::ObjectGroup *ptr) { new (storage) Concrete(ptr); }
+
+    Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+    const char16_t* typeName() const override { return concreteTypeName; }
+    static const char16_t concreteTypeName[];
 };
 
 } // namespace ubi
 } // namespace JS
 
 #endif /* vm_TypeInference_h */
--- a/js/src/vm/UbiNode.cpp
+++ b/js/src/vm/UbiNode.cpp
@@ -366,47 +366,24 @@ Concrete<JSObject>::jsObjectConstructorN
     mozilla::Range<char16_t> chars(outName.get(), size);
     if (!JS_CopyStringChars(cx, chars, name))
         return false;
 
     outName[len] = '\0';
     return true;
 }
 
-template<> const char16_t TracerConcrete<JS::Symbol>::concreteTypeName[] =
-    MOZ_UTF16("JS::Symbol");
-template<> const char16_t TracerConcrete<JSScript>::concreteTypeName[] =
-    MOZ_UTF16("JSScript");
-template<> const char16_t TracerConcrete<js::LazyScript>::concreteTypeName[] =
-    MOZ_UTF16("js::LazyScript");
-template<> const char16_t TracerConcrete<js::jit::JitCode>::concreteTypeName[] =
-    MOZ_UTF16("js::jit::JitCode");
-template<> const char16_t TracerConcrete<js::Shape>::concreteTypeName[] =
-    MOZ_UTF16("js::Shape");
-template<> const char16_t TracerConcrete<js::BaseShape>::concreteTypeName[] =
-    MOZ_UTF16("js::BaseShape");
-template<> const char16_t TracerConcrete<js::ObjectGroup>::concreteTypeName[] =
-    MOZ_UTF16("js::ObjectGroup");
-
+const char16_t Concrete<JS::Symbol>::concreteTypeName[] = MOZ_UTF16("JS::Symbol");
+const char16_t Concrete<JSScript>::concreteTypeName[] = MOZ_UTF16("JSScript");
+const char16_t Concrete<js::LazyScript>::concreteTypeName[] = MOZ_UTF16("js::LazyScript");
+const char16_t Concrete<js::jit::JitCode>::concreteTypeName[] = MOZ_UTF16("js::jit::JitCode");
+const char16_t Concrete<js::Shape>::concreteTypeName[] = MOZ_UTF16("js::Shape");
+const char16_t Concrete<js::BaseShape>::concreteTypeName[] = MOZ_UTF16("js::BaseShape");
+const char16_t Concrete<js::ObjectGroup>::concreteTypeName[] = MOZ_UTF16("js::ObjectGroup");
 
-// Instantiate all the TracerConcrete and templates here, where
-// we have the member functions' definitions in scope.
-namespace JS {
-namespace ubi {
-template class TracerConcreteWithCompartment<JSObject>;
-template class TracerConcrete<JSString>;
-template class TracerConcrete<JS::Symbol>;
-template class TracerConcreteWithCompartment<JSScript>;
-template class TracerConcrete<js::LazyScript>;
-template class TracerConcrete<js::jit::JitCode>;
-template class TracerConcreteWithCompartment<js::Shape>;
-template class TracerConcreteWithCompartment<js::BaseShape>;
-template class TracerConcrete<js::ObjectGroup>;
-} // namespace ubi
-} // namespace JS
 
 namespace JS {
 namespace ubi {
 
 RootList::RootList(JSRuntime* rt, Maybe<AutoCheckCannotGC>& noGC, bool wantNames /* = false */)
   : noGC(noGC),
     rt(rt),
     edges(),