Bug 1220310 - Generalize GC container trace function dispatch as GCPolicy; r=sfink
authorTerrence Cole <terrence@mozilla.com>
Tue, 03 Nov 2015 07:08:05 -0800
changeset 271953 ba5c3654f4854fc4d80532105b7ef4729b991bd9
parent 271952 e99e265f741778c5247e866128144bb20077162b
child 271954 d5d3bf67dd1be22b541710ccff7f5e9614052ffc
push id67818
push usertcole@mozilla.com
push dateTue, 10 Nov 2015 19:18:19 +0000
treeherdermozilla-inbound@ba5c3654f485 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1220310
milestone45.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 1220310 - Generalize GC container trace function dispatch as GCPolicy; r=sfink
js/public/TraceableHashTable.h
js/public/TraceableVector.h
js/public/TracingAPI.h
js/src/ds/TraceableFifo.h
js/src/gc/Tracer.h
js/src/vm/Debugger.h
--- a/js/public/TraceableHashTable.h
+++ b/js/public/TraceableHashTable.h
@@ -8,51 +8,58 @@
 #define gc_HashTable_h
 
 #include "js/HashTable.h"
 #include "js/RootingAPI.h"
 #include "js/TracingAPI.h"
 
 namespace js {
 
+// Define a reasonable default GC policy for GC-aware Maps.
+template <typename Key, typename Value>
+struct DefaultMapGCPolicy {
+    using KeyPolicy = DefaultGCPolicy<Key>;
+    using ValuePolicy = DefaultGCPolicy<Value>;
+};
+
 // A TraceableHashMap is a HashMap with an additional trace method that knows
 // how to visit all keys and values in the table. HashMaps that contain GC
 // pointers that must be traced to be kept alive will generally want to use
 // this TraceableHashMap specializeation in lieu of HashMap.
 //
 // Most types of GC pointers as keys and values can be traced with no extra
-// infrastructure.  For structs and non-gc-pointer members, ensure that there
-// is a specialization of DefaultTracer<T> with an appropriate trace method
-// available to handle the custom type.
+// infrastructure. For structs and non-gc-pointer members, ensure that there
+// is a specialization of DefaultGCPolicy<T> with an appropriate trace method
+// available to handle the custom type. Generic helpers can be found in
+// js/public/TracingAPI.h.
 //
 // Note that although this HashMap's trace will deal correctly with moved keys,
 // it does not itself know when to barrier or trace keys. To function properly
 // it must either be used with Rooted, or barriered and traced manually.
 template <typename Key,
           typename Value,
           typename HashPolicy = DefaultHasher<Key>,
           typename AllocPolicy = TempAllocPolicy,
-          typename KeyTraceFunc = DefaultTracer<Key>,
-          typename ValueTraceFunc = DefaultTracer<Value>>
+          typename GCPolicy = DefaultMapGCPolicy<Key, Value>>
 class TraceableHashMap : public HashMap<Key, Value, HashPolicy, AllocPolicy>,
                          public JS::Traceable
 {
     using Base = HashMap<Key, Value, HashPolicy, AllocPolicy>;
 
   public:
     explicit TraceableHashMap(AllocPolicy a = AllocPolicy()) : Base(a)  {}
 
     static void trace(TraceableHashMap* map, JSTracer* trc) { map->trace(trc); }
     void trace(JSTracer* trc) {
         if (!this->initialized())
             return;
         for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
-            ValueTraceFunc::trace(trc, &e.front().value(), "hashmap value");
+            GCPolicy::ValuePolicy::trace(trc, &e.front().value(), "hashmap value");
             Key key = e.front().key();
-            KeyTraceFunc::trace(trc, &key, "hashmap key");
+            GCPolicy::KeyPolicy::trace(trc, &key, "hashmap key");
             if (key != e.front().key())
                 e.rekeyFront(key);
         }
     }
 
     // TraceableHashMap is movable
     TraceableHashMap(TraceableHashMap&& rhs) : Base(mozilla::Forward<TraceableHashMap>(rhs)) {}
     void operator=(TraceableHashMap&& rhs) {
@@ -132,65 +139,65 @@ class MutableTraceableHashMapOperations
     }
 
     template<typename KeyInput, typename ValueInput>
     bool putNew(KeyInput&& k, ValueInput&& v) {
         return map().putNew(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
     }
 };
 
-template <typename A, typename B, typename C, typename D, typename E, typename F>
-class RootedBase<TraceableHashMap<A,B,C,D,E,F>>
-  : public MutableTraceableHashMapOperations<JS::Rooted<TraceableHashMap<A,B,C,D,E,F>>, A,B,C,D,E,F>
+template <typename A, typename B, typename C, typename D, typename E>
+class RootedBase<TraceableHashMap<A,B,C,D,E>>
+  : public MutableTraceableHashMapOperations<JS::Rooted<TraceableHashMap<A,B,C,D,E>>, A,B,C,D,E>
 {};
 
-template <typename A, typename B, typename C, typename D, typename E, typename F>
-class MutableHandleBase<TraceableHashMap<A,B,C,D,E,F>>
-  : public MutableTraceableHashMapOperations<JS::MutableHandle<TraceableHashMap<A,B,C,D,E,F>>,
-                                             A,B,C,D,E,F>
+template <typename A, typename B, typename C, typename D, typename E>
+class MutableHandleBase<TraceableHashMap<A,B,C,D,E>>
+  : public MutableTraceableHashMapOperations<JS::MutableHandle<TraceableHashMap<A,B,C,D,E>>,
+                                             A,B,C,D,E>
 {};
 
-template <typename A, typename B, typename C, typename D, typename E, typename F>
-class HandleBase<TraceableHashMap<A,B,C,D,E,F>>
-  : public TraceableHashMapOperations<JS::Handle<TraceableHashMap<A,B,C,D,E,F>>, A,B,C,D,E,F>
+template <typename A, typename B, typename C, typename D, typename E>
+class HandleBase<TraceableHashMap<A,B,C,D,E>>
+  : public TraceableHashMapOperations<JS::Handle<TraceableHashMap<A,B,C,D,E>>, A,B,C,D,E>
 {};
 
 // A TraceableHashSet is a HashSet with an additional trace method that knows
-// how to visit all set element.  HashSets that contain GC pointers that must
+// how to visit all set elements. HashSets that contain GC pointers that must
 // be traced to be kept alive will generally want to use this TraceableHashSet
 // specializeation in lieu of HashSet.
 //
-// Most types of GC pointers can be traced with no extra infrastructure.  For
+// Most types of GC pointers can be traced with no extra infrastructure. For
 // structs and non-gc-pointer members, ensure that there is a specialization of
-// DefaultTracer<T> with an appropriate trace method available to handle the
-// custom type.
+// DefaultGCPolicy<T> with an appropriate trace method available to handle the
+// custom type. Generic helpers can be found in js/public/TracingAPI.h.
 //
 // Note that although this HashSet's trace will deal correctly with moved
-// elements, it does not itself know when to barrier or trace elements.  To
+// elements, it does not itself know when to barrier or trace elements. To
 // function properly it must either be used with Rooted or barriered and traced
 // manually.
 template <typename T,
           typename HashPolicy = DefaultHasher<T>,
           typename AllocPolicy = TempAllocPolicy,
-          typename ElemTraceFunc = DefaultTracer<T>>
+          typename GCPolicy = DefaultGCPolicy<T>>
 class TraceableHashSet : public HashSet<T, HashPolicy, AllocPolicy>,
                          public JS::Traceable
 {
     using Base = HashSet<T, HashPolicy, AllocPolicy>;
 
   public:
     explicit TraceableHashSet(AllocPolicy a = AllocPolicy()) : Base(a)  {}
 
     static void trace(TraceableHashSet* set, JSTracer* trc) { set->trace(trc); }
     void trace(JSTracer* trc) {
         if (!this->initialized())
             return;
         for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
             T elem = e.front();
-            ElemTraceFunc::trace(trc, &elem, "hashset element");
+            GCPolicy::trace(trc, &elem, "hashset element");
             if (elem != e.front())
                 e.rekeyFront(elem);
         }
     }
 
     // TraceableHashSet is movable
     TraceableHashSet(TraceableHashSet&& rhs) : Base(mozilla::Forward<TraceableHashSet>(rhs)) {}
     void operator=(TraceableHashSet&& rhs) {
@@ -268,49 +275,50 @@ class MutableTraceableHashSetOperations
     }
 
     template<typename TInput>
     bool putNew(const Lookup& l, TInput&& t) {
         return set().putNew(l, mozilla::Forward<TInput>(t));
     }
 };
 
-template <typename T, typename HP, typename AP, typename TF>
-class RootedBase<TraceableHashSet<T, HP, AP, TF>>
-  : public MutableTraceableHashSetOperations<JS::Rooted<TraceableHashSet<T, HP, AP, TF>>, T, HP, AP, TF>
+template <typename T, typename HP, typename AP, typename GP>
+class RootedBase<TraceableHashSet<T, HP, AP, GP>>
+  : public MutableTraceableHashSetOperations<JS::Rooted<TraceableHashSet<T, HP, AP, GP>>,
+                                             T, HP, AP, GP>
 {
-    using Set = TraceableHashSet<T, HP, AP, TF>;
+    using Set = TraceableHashSet<T, HP, AP, GP>;
 
-    friend class TraceableHashSetOperations<JS::Rooted<Set>, T, HP, AP, TF>;
+    friend class TraceableHashSetOperations<JS::Rooted<Set>, T, HP, AP, GP>;
     const Set& extract() const { return *static_cast<const JS::Rooted<Set>*>(this)->address(); }
 
-    friend class MutableTraceableHashSetOperations<JS::Rooted<Set>, T, HP, AP, TF>;
+    friend class MutableTraceableHashSetOperations<JS::Rooted<Set>, T, HP, AP, GP>;
     Set& extract() { return *static_cast<JS::Rooted<Set>*>(this)->address(); }
 };
 
-template <typename T, typename HP, typename AP, typename TF>
-class MutableHandleBase<TraceableHashSet<T, HP, AP, TF>>
-  : public MutableTraceableHashSetOperations<JS::MutableHandle<TraceableHashSet<T, HP, AP, TF>>,
-                                             T, HP, AP, TF>
+template <typename T, typename HP, typename AP, typename GP>
+class MutableHandleBase<TraceableHashSet<T, HP, AP, GP>>
+  : public MutableTraceableHashSetOperations<JS::MutableHandle<TraceableHashSet<T, HP, AP, GP>>,
+                                             T, HP, AP, GP>
 {
-    using Set = TraceableHashSet<T, HP, AP, TF>;
+    using Set = TraceableHashSet<T, HP, AP, GP>;
 
-    friend class TraceableHashSetOperations<JS::MutableHandle<Set>, T, HP, AP, TF>;
+    friend class TraceableHashSetOperations<JS::MutableHandle<Set>, T, HP, AP, GP>;
     const Set& extract() const {
         return *static_cast<const JS::MutableHandle<Set>*>(this)->address();
     }
 
-    friend class MutableTraceableHashSetOperations<JS::MutableHandle<Set>, T, HP, AP, TF>;
+    friend class MutableTraceableHashSetOperations<JS::MutableHandle<Set>, T, HP, AP, GP>;
     Set& extract() { return *static_cast<JS::MutableHandle<Set>*>(this)->address(); }
 };
 
-template <typename T, typename HP, typename AP, typename TF>
-class HandleBase<TraceableHashSet<T, HP, AP, TF>>
-  : public TraceableHashSetOperations<JS::Handle<TraceableHashSet<T, HP, AP, TF>>, T, HP, AP, TF>
+template <typename T, typename HP, typename AP, typename GP>
+class HandleBase<TraceableHashSet<T, HP, AP, GP>>
+  : public TraceableHashSetOperations<JS::Handle<TraceableHashSet<T, HP, AP, GP>>, T, HP, AP, GP>
 {
-    using Set = TraceableHashSet<T, HP, AP, TF>;
-    friend class TraceableHashSetOperations<JS::Handle<Set>, T, HP, AP, TF>;
+    using Set = TraceableHashSet<T, HP, AP, GP>;
+    friend class TraceableHashSetOperations<JS::Handle<Set>, T, HP, AP, GP>;
     const Set& extract() const { return *static_cast<const JS::Handle<Set>*>(this)->address(); }
 };
 
 } /* namespace js */
 
 #endif /* gc_HashTable_h */
--- a/js/public/TraceableVector.h
+++ b/js/public/TraceableVector.h
@@ -17,53 +17,54 @@ namespace js {
 
 // A TraceableVector is a Vector with an additional trace method that knows how
 // to visit all of the items stored in the Vector. For vectors that contain GC
 // things, this is usually more convenient than manually iterating and marking
 // the contents.
 //
 // Most types of GC pointers as keys and values can be traced with no extra
 // infrastructure.  For structs and non-gc-pointer members, ensure that there
-// is a specialization of DefaultTracer<T> with an appropriate trace method
-// available to handle the custom type.
+// is a specialization of DefaultGCPolicy<T> with an appropriate trace method
+// available to handle the custom type. Generic helpers can be found in
+// js/public/TracingAPI.h.
 //
 // Note that although this Vector's trace will deal correctly with moved items,
 // it does not itself know when to barrier or trace items. To function properly
 // it must either be used with Rooted, or barriered and traced manually.
 template <typename T,
           size_t MinInlineCapacity = 0,
           typename AllocPolicy = TempAllocPolicy,
-          typename TraceFunc = DefaultTracer<T>>
+          typename GCPolicy = DefaultGCPolicy<T>>
 class TraceableVector
   : public mozilla::VectorBase<T,
                                MinInlineCapacity,
                                AllocPolicy,
-                               TraceableVector<T, MinInlineCapacity, AllocPolicy, TraceFunc>>,
+                               TraceableVector<T, MinInlineCapacity, AllocPolicy, GCPolicy>>,
     public JS::Traceable
 {
     using Base = mozilla::VectorBase<T, MinInlineCapacity, AllocPolicy, TraceableVector>;
 
   public:
     explicit TraceableVector(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
     TraceableVector(TraceableVector&& vec) : Base(mozilla::Forward<TraceableVector>(vec)) {}
     TraceableVector& operator=(TraceableVector&& vec) {
         return Base::operator=(mozilla::Forward<TraceableVector>(vec));
     }
 
     static void trace(TraceableVector* vec, JSTracer* trc) { vec->trace(trc); }
     void trace(JSTracer* trc) {
         for (size_t i = 0; i < this->length(); ++i)
-            TraceFunc::trace(trc, &Base::operator[](i), "vector element");
+            GCPolicy::trace(trc, &Base::operator[](i), "vector element");
     }
 };
 
-template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename TraceFunc>
+template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename GCPolicy>
 class TraceableVectorOperations
 {
-    using Vec = TraceableVector<T, Capacity, AllocPolicy, TraceFunc>;
+    using Vec = TraceableVector<T, Capacity, AllocPolicy, GCPolicy>;
     const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
 
   public:
     const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
     size_t length() const { return vec().length(); }
     bool empty() const { return vec().empty(); }
     size_t capacity() const { return vec().capacity(); }
     const T* begin() const { return vec().begin(); }
@@ -71,21 +72,21 @@ class TraceableVectorOperations
     const T& back() const { return vec().back(); }
     bool canAppendWithoutRealloc(size_t aNeeded) const { return vec().canAppendWithoutRealloc(); }
 
     JS::Handle<T> operator[](size_t aIndex) const {
         return JS::Handle<T>::fromMarkedLocation(&vec().operator[](aIndex));
     }
 };
 
-template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename TraceFunc>
+template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename GCPolicy>
 class MutableTraceableVectorOperations
-  : public TraceableVectorOperations<Outer, T, Capacity, AllocPolicy, TraceFunc>
+  : public TraceableVectorOperations<Outer, T, Capacity, AllocPolicy, GCPolicy>
 {
-    using Vec = TraceableVector<T, Capacity, AllocPolicy, TraceFunc>;
+    using Vec = TraceableVector<T, Capacity, AllocPolicy, GCPolicy>;
     const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
     Vec& vec() { return static_cast<Outer*>(this)->get(); }
 
   public:
     const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
     AllocPolicy& allocPolicy() { return vec().allocPolicy(); }
     const T* begin() const { return vec().begin(); }
     T* begin() { return vec().begin(); }
@@ -136,33 +137,33 @@ class MutableTraceableVectorOperations
     T popCopy() { return vec().popCopy(); }
     template<typename U> T* insert(T* aP, U&& aVal) {
         return vec().insert(aP, mozilla::Forward<U>(aVal));
     }
     void erase(T* aT) { vec().erase(aT); }
     void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); }
 };
 
-template <typename T, size_t N, typename AP, typename TP>
-class RootedBase<TraceableVector<T,N,AP,TP>>
-  : public MutableTraceableVectorOperations<JS::Rooted<TraceableVector<T,N,AP,TP>>, T,N,AP,TP>
+template <typename T, size_t N, typename AP, typename GP>
+class RootedBase<TraceableVector<T,N,AP,GP>>
+  : public MutableTraceableVectorOperations<JS::Rooted<TraceableVector<T,N,AP,GP>>, T,N,AP,GP>
 {};
 
-template <typename T, size_t N, typename AP, typename TP>
-class MutableHandleBase<TraceableVector<T,N,AP,TP>>
-  : public MutableTraceableVectorOperations<JS::MutableHandle<TraceableVector<T,N,AP,TP>>,
-                                            T,N,AP,TP>
+template <typename T, size_t N, typename AP, typename GP>
+class MutableHandleBase<TraceableVector<T,N,AP,GP>>
+  : public MutableTraceableVectorOperations<JS::MutableHandle<TraceableVector<T,N,AP,GP>>,
+                                            T,N,AP,GP>
 {};
 
-template <typename T, size_t N, typename AP, typename TP>
-class HandleBase<TraceableVector<T,N,AP,TP>>
-  : public TraceableVectorOperations<JS::Handle<TraceableVector<T,N,AP,TP>>, T,N,AP,TP>
+template <typename T, size_t N, typename AP, typename GP>
+class HandleBase<TraceableVector<T,N,AP,GP>>
+  : public TraceableVectorOperations<JS::Handle<TraceableVector<T,N,AP,GP>>, T,N,AP,GP>
 {};
 
-template <typename T, size_t N, typename AP, typename TP>
-class PersistentRootedBase<TraceableVector<T,N,AP,TP>>
-  : public MutableTraceableVectorOperations<JS::PersistentRooted<TraceableVector<T,N,AP,TP>>,
-                                            T,N,AP,TP>
+template <typename T, size_t N, typename AP, typename GP>
+class PersistentRootedBase<TraceableVector<T,N,AP,GP>>
+  : public MutableTraceableVectorOperations<JS::PersistentRooted<TraceableVector<T,N,AP,GP>>,
+                                            T,N,AP,GP>
 {};
 
 } // namespace js
 
 #endif // js_TraceableVector_h
--- a/js/public/TracingAPI.h
+++ b/js/public/TracingAPI.h
@@ -364,37 +364,50 @@ extern JS_PUBLIC_API(void)
 JS_TraceIncomingCCWs(JSTracer* trc, const JS::ZoneSet& zones);
 
 extern JS_PUBLIC_API(void)
 JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc,
                      void* thing, JS::TraceKind kind, bool includeDetails);
 
 namespace js {
 
-// Automates static dispatch for tracing for TraceableContainers.
-template <typename> struct DefaultTracer;
+// Automates static dispatch for GC interaction with TraceableContainers.
+template <typename>
+struct DefaultGCPolicy;
 
-// The default for non-pod (e.g. struct) types is to call the trace method.
+// This policy dispatches GC methods to a method on the type.
 template <typename T>
-struct DefaultTracer {
+struct StructGCPolicy {
     static void trace(JSTracer* trc, T* t, const char* name) {
+        // This is the default GC policy for storing GC things in containers.
         // If your build is failing here, it means you either need an
-        // implementation of DefaultTracer<T> for your type or, for container
-        // and structure types that contain GC pointers, a trace method.
+        // implementation of DefaultGCPolicy<T> for your type or, if this is
+        // the right policy for you, your struct or container is missing a
+        // trace method.
         t->trace(trc);
     }
 };
 
+// This policy ignores any GC interaction, e.g. for non-GC types.
+template <typename T>
+struct IgnoreGCPolicy {
+    static void trace(JSTracer* trc, uint32_t* id, const char* name) {}
+};
+
+// The default policy when no other more specific policy fits (e.g. for a
+// direct GC pointer), is to assume a struct type that implements the needed
+// methods.
+template <typename T>
+struct DefaultGCPolicy : public StructGCPolicy<T> {};
+
 template <>
-struct DefaultTracer<jsid>
+struct DefaultGCPolicy<jsid>
 {
     static void trace(JSTracer* trc, jsid* id, const char* name) {
         JS_CallUnbarrieredIdTracer(trc, id, name);
     }
 };
 
-template <> struct DefaultTracer<uint32_t> {
-    static void trace(JSTracer* trc, uint32_t* id, const char* name) {}
-};
+template <> struct DefaultGCPolicy<uint32_t> : public IgnoreGCPolicy<uint32_t> {};
 
 } // namespace js
 
 #endif /* js_TracingAPI_h */
--- a/js/src/ds/TraceableFifo.h
+++ b/js/src/ds/TraceableFifo.h
@@ -4,38 +4,39 @@
  * 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/. */
 
 #ifndef js_TraceableFifo_h
 #define js_TraceableFifo_h
 
 #include "ds/Fifo.h"
 #include "js/RootingAPI.h"
+#include "js/TracingAPI.h"
 
 namespace js {
 
-template <typename> struct DefaultTracer;
-
 // A TraceableFifo is a Fifo with an additional trace method that knows how to
 // visit all of the items stored in the Fifo. For Fifos that contain GC things,
 // this is usually more convenient than manually iterating and marking the
 // contents.
 //
 // Most types of GC pointers as keys and values can be traced with no extra
 // infrastructure. For structs and non-gc-pointer members, ensure that there is
-// a specialization of DefaultTracer<T> with an appropriate trace method
-// available to handle the custom type.
+// a specialization of DefaultGCPolicy<T> with an appropriate trace method
+// available to handle the custom type. Generic helpers can be found in
+// js/public/TracingAPI.h. Generic helpers can be found in
+// js/public/TracingAPI.h.
 //
 // Note that although this Fifo's trace will deal correctly with moved items, it
 // does not itself know when to barrier or trace items. To function properly it
 // must either be used with Rooted, or barriered and traced manually.
 template <typename T,
           size_t MinInlineCapacity = 0,
           typename AllocPolicy = TempAllocPolicy,
-          typename TraceFunc = DefaultTracer<T>>
+          typename GCPolicy = DefaultGCPolicy<T>>
 class TraceableFifo
   : public js::Fifo<T, MinInlineCapacity, AllocPolicy>,
     public JS::Traceable
 {
     using Base = js::Fifo<T, MinInlineCapacity, AllocPolicy>;
 
   public:
     explicit TraceableFifo(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
@@ -43,39 +44,39 @@ class TraceableFifo
     TraceableFifo(TraceableFifo&& rhs) : Base(mozilla::Move(rhs)) { }
     TraceableFifo& operator=(TraceableFifo&& rhs) { return Base::operator=(mozilla::Move(rhs)); }
 
     TraceableFifo(const TraceableFifo&) = delete;
     TraceableFifo& operator=(const TraceableFifo&) = delete;
 
     static void trace(TraceableFifo* tf, JSTracer* trc) {
         for (size_t i = 0; i < tf->front_.length(); ++i)
-            TraceFunc::trace(trc, &tf->front_[i], "fifo element");
+            GCPolicy::trace(trc, &tf->front_[i], "fifo element");
         for (size_t i = 0; i < tf->rear_.length(); ++i)
-            TraceFunc::trace(trc, &tf->rear_[i], "fifo element");
+            GCPolicy::trace(trc, &tf->rear_[i], "fifo element");
     }
 };
 
-template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename TraceFunc>
+template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename GCPolicy>
 class TraceableFifoOperations
 {
-    using TF = TraceableFifo<T, Capacity, AllocPolicy, TraceFunc>;
+    using TF = TraceableFifo<T, Capacity, AllocPolicy, GCPolicy>;
     const TF& fifo() const { return static_cast<const Outer*>(this)->extract(); }
 
   public:
     size_t length() const { return fifo().length(); }
     bool empty() const { return fifo().empty(); }
     const T& front() const { return fifo().front(); }
 };
 
-template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename TraceFunc>
+template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename GCPolicy>
 class MutableTraceableFifoOperations
-  : public TraceableFifoOperations<Outer, T, Capacity, AllocPolicy, TraceFunc>
+  : public TraceableFifoOperations<Outer, T, Capacity, AllocPolicy, GCPolicy>
 {
-    using TF = TraceableFifo<T, Capacity, AllocPolicy, TraceFunc>;
+    using TF = TraceableFifo<T, Capacity, AllocPolicy, GCPolicy>;
     TF& fifo() { return static_cast<Outer*>(this)->extract(); }
 
   public:
     T& front() { return fifo().front(); }
 
     template<typename U> bool pushBack(U&& u) { return fifo().pushBack(mozilla::Forward<U>(u)); }
     template<typename... Args> bool emplaceBack(Args&&... args) {
         return fifo().emplaceBack(mozilla::Forward<Args...>(args...));
--- a/js/src/gc/Tracer.h
+++ b/js/src/gc/Tracer.h
@@ -133,26 +133,32 @@ namespace gc {
 // deep or infinite recursion.
 void
 TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape);
 void
 TraceCycleCollectorChildren(JS::CallbackTracer* trc, ObjectGroup* group);
 
 } // namespace gc
 
+// Define a default Policy for all pointer types. This may fail to link if this
+// policy gets used on a non-GC typed pointer by accident.
 template <typename T>
-struct DefaultTracer<T*>
+struct DefaultGCPolicy<T*>
 {
     static void trace(JSTracer* trc, T** t, const char* name) {
+        // If linking is failing here, it likely means that you need to define
+        // or use a non-default GC policy for your non-gc-pointer type.
         TraceManuallyBarrieredEdge(trc, t, name);
     }
 };
 
+// RelocatablePtr is only defined for GC pointer types, so this default policy
+// should work in all cases.
 template <typename T>
-struct DefaultTracer<RelocatablePtr<T*>>
+struct DefaultGCPolicy<RelocatablePtr<T*>>
 {
     static void trace(JSTracer* trc, RelocatablePtr<T*> t, const char* name) {
         TraceEdge(trc, t, name);
     }
 };
 
 } // namespace js
 
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -938,24 +938,24 @@ class Debugger : private mozilla::Linked
     JSObject* wrapSource(JSContext* cx, js::HandleScriptSource source);
 
   private:
     Debugger(const Debugger&) = delete;
     Debugger & operator=(const Debugger&) = delete;
 };
 
 template<>
-struct DefaultTracer<Debugger::TenurePromotionsLogEntry> {
+struct DefaultGCPolicy<Debugger::TenurePromotionsLogEntry> {
     static void trace(JSTracer* trc, Debugger::TenurePromotionsLogEntry* e, const char*) {
         Debugger::TenurePromotionsLogEntry::trace(e, trc);
     }
 };
 
 template<>
-struct DefaultTracer<Debugger::AllocationsLogEntry> {
+struct DefaultGCPolicy<Debugger::AllocationsLogEntry> {
     static void trace(JSTracer* trc, Debugger::AllocationsLogEntry* e, const char*) {
         Debugger::AllocationsLogEntry::trace(e, trc);
     }
 };
 
 class BreakpointSite {
     friend class Breakpoint;
     friend struct ::JSCompartment;