Bug 1170325 - Convert js::Vector into a template alias to mozilla::Vector with a single customized default argument. Also get rid of the CRTP support in mozilla::Vector (through mozilla::VectorBase) now that template aliasing is good enough, and make mozilla::Vector final so that people will use composition and not inheritance with it. (Inheritance plays poorly with movability and a few other things, in addition to messing up template argument deduction matching.) r=Waldo, patch sort of a tag-team between him and me
authorNick Fitzgerald <fitzgen@gmail.com>
Mon, 13 Jul 2015 12:42:52 -0700
changeset 309914 30044858f40c18b5059a0df89ab18eb455270286
parent 309913 139130c7ed7aa617f92abd31b5a89fcc582dc7b8
child 309915 748c27d6775f1b3b62e2029a0d750843ebfc355d
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo, patch
bugs1170325
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 1170325 - Convert js::Vector into a template alias to mozilla::Vector with a single customized default argument. Also get rid of the CRTP support in mozilla::Vector (through mozilla::VectorBase) now that template aliasing is good enough, and make mozilla::Vector final so that people will use composition and not inheritance with it. (Inheritance plays poorly with movability and a few other things, in addition to messing up template argument deduction matching.) r=Waldo, patch sort of a tag-team between him and me
gfx/layers/apz/src/AsyncPanZoomAnimation.h
gfx/layers/apz/src/AsyncPanZoomController.cpp
js/public/TraceableVector.h
js/public/Vector.h
js/src/asmjs/AsmJSModule.cpp
js/src/ctypes/CTypes.cpp
js/src/ctypes/CTypes.h
js/src/gc/GCRuntime.h
mfbt/Vector.h
toolkit/components/telemetry/ThreadHangStats.h
--- a/gfx/layers/apz/src/AsyncPanZoomAnimation.h
+++ b/gfx/layers/apz/src/AsyncPanZoomAnimation.h
@@ -38,24 +38,21 @@ public:
     if (aDelta.ToMilliseconds() <= 0) {
       return true;
     }
 
     return DoSample(aFrameMetrics, aDelta);
   }
 
   /**
-   * Get the deferred tasks in |mDeferredTasks|. See |mDeferredTasks|
-   * for more information.
-   * Clears |mDeferredTasks|.
+   * Get the deferred tasks in |mDeferredTasks| and place them in |aTasks|. See
+   * |mDeferredTasks| for more information.  Clears |mDeferredTasks|.
    */
-  Vector<Task*> TakeDeferredTasks() {
-    Vector<Task*> result;
-    mDeferredTasks.swap(result);
-    return result;
+  void TakeDeferredTasks(Vector<Task*>& aTasks) {
+    mDeferredTasks.swap(aTasks);
   }
 
   /**
    * Specifies how frequently (at most) we want to do repaints during the
    * animation sequence. TimeDuration::Forever() will cause it to only repaint
    * at the end of the animation.
    */
   TimeDuration mRepaintInterval;
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2875,17 +2875,17 @@ bool AsyncPanZoomController::UpdateAnima
   if (mLastSampleTime == aSampleTime) {
     return false;
   }
   TimeDuration sampleTimeDelta = aSampleTime - mLastSampleTime;
   mLastSampleTime = aSampleTime;
 
   if (mAnimation) {
     bool continueAnimation = mAnimation->Sample(mFrameMetrics, sampleTimeDelta);
-    *aOutDeferredTasks = mAnimation->TakeDeferredTasks();
+    mAnimation->TakeDeferredTasks(*aOutDeferredTasks);
     if (continueAnimation) {
       if (mPaintThrottler->TimeSinceLastRequest(aSampleTime) >
           mAnimation->mRepaintInterval) {
         RequestContentRepaint();
       }
     } else {
       mAnimation = nullptr;
       SetState(NOTHING);
--- a/js/public/TraceableVector.h
+++ b/js/public/TraceableVector.h
@@ -28,36 +28,106 @@ namespace js {
 //
 // 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 GCPolicy = DefaultGCPolicy<T>>
-class TraceableVector
-  : public mozilla::VectorBase<T,
-                               MinInlineCapacity,
-                               AllocPolicy,
-                               TraceableVector<T, MinInlineCapacity, AllocPolicy, GCPolicy>>,
-    public JS::Traceable
+class TraceableVector : public JS::Traceable
 {
-    using Base = mozilla::VectorBase<T, MinInlineCapacity, AllocPolicy, TraceableVector>;
+    mozilla::Vector<T, MinInlineCapacity, AllocPolicy> vector;
 
   public:
-    explicit TraceableVector(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
-    TraceableVector(TraceableVector&& vec) : Base(mozilla::Forward<TraceableVector>(vec)) {}
+    explicit TraceableVector(AllocPolicy alloc = AllocPolicy())
+      : vector(alloc)
+    {}
+
+    TraceableVector(TraceableVector&& vec)
+      : vector(mozilla::Move(vec.vector))
+    {}
+
     TraceableVector& operator=(TraceableVector&& vec) {
-        return Base::operator=(mozilla::Forward<TraceableVector>(vec));
+        vector = mozilla::Move(vec.vector);
+        return *this;
+    }
+
+    size_t length() const { return vector.length(); }
+    bool empty() const { return vector.empty(); }
+    size_t capacity() const { return vector.capacity(); }
+
+    T* begin() { return vector.begin(); }
+    const T* begin() const { return vector.begin(); }
+
+    T* end() { return vector.end(); }
+    const T* end() const { return vector.end(); }
+
+    T& operator[](size_t i) { return vector[i]; }
+    const T& operator[](size_t i) const { return vector[i]; }
+
+    T& back() { return vector.back(); }
+    const T& back() const { return vector.back(); }
+
+    bool initCapacity(size_t cap) { return vector.initCapacity(cap); }
+    bool reserve(size_t req) { return vector.reserve(req); }
+    void shrinkBy(size_t amount) { return vector.shrinkBy(amount); }
+    bool growBy(size_t amount) { return vector.growBy(amount); }
+    bool resize(size_t newLen) { return vector.resize(newLen); }
+
+    void clear() { return vector.clear(); }
+
+    template<typename U> bool append(U&& item) { return vector.append(mozilla::Forward<U>(item)); }
+
+    template<typename... Args>
+    bool
+    emplaceBack(Args&&... args) {
+        return vector.emplaceBack(mozilla::Forward<Args>(args)...);
+    }
+
+    template<typename U>
+    void infallibleAppend(U&& aU) {
+        return vector.infallibleAppend(mozilla::Forward<U>(aU));
+    }
+    void infallibleAppendN(const T& aT, size_t aN) {
+        return vector.infallibleAppendN(aT, aN);
+    }
+    template<typename U> void
+    infallibleAppend(const U* aBegin, const U* aEnd) {
+        return vector.infallibleAppend(aBegin, aEnd);
+    }
+    template<typename U> void infallibleAppend(const U* aBegin, size_t aLength) {
+        return vector.infallibleAppend(aBegin, aLength);
+    }
+
+    bool appendN(const T& val, size_t count) { return vector.appendN(val, count); }
+
+    template<typename U> bool append(const U* aBegin, const U* aEnd) {
+        return vector.append(aBegin, aEnd);
+    }
+    template<typename U> bool append(const U* aBegin, size_t aLength) {
+        return vector.append(aBegin, aLength);
+    }
+
+    void popBack() { return vector.popBack(); }
+    T popCopy() { return vector.popCopy(); }
+
+    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+        return vector.sizeOfExcludingThis(mallocSizeOf);
+    }
+
+    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+        return vector.sizeOfIncludingThis(mallocSizeOf);
     }
 
     static void trace(TraceableVector* vec, JSTracer* trc) { vec->trace(trc); }
+
     void trace(JSTracer* trc) {
-        for (size_t i = 0; i < this->length(); ++i)
-            GCPolicy::trace(trc, &Base::operator[](i), "vector element");
+        for (auto& elem : vector)
+            GCPolicy::trace(trc, &elem, "vector element");
     }
 };
 
 template <typename Outer, typename T, size_t Capacity, typename AllocPolicy, typename GCPolicy>
 class TraceableVectorOperations
 {
     using Vec = TraceableVector<T, Capacity, AllocPolicy, GCPolicy>;
     const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
@@ -109,18 +179,18 @@ class MutableTraceableVectorOperations
     void infallibleGrowByUninitialized(size_t aIncr) { vec().infallibleGrowByUninitialized(aIncr); }
     bool resizeUninitialized(size_t aNewLength) { return vec().resizeUninitialized(aNewLength); }
     void clear() { vec().clear(); }
     void clearAndFree() { vec().clearAndFree(); }
     template<typename U> bool append(U&& aU) { return vec().append(mozilla::Forward<U>(aU)); }
     template<typename... Args> bool emplaceBack(Args&&... aArgs) {
         return vec().emplaceBack(mozilla::Forward<Args...>(aArgs...));
     }
-    template<typename U, size_t O, class BP, class UV>
-    bool appendAll(const mozilla::VectorBase<U, O, BP, UV>& aU) { return vec().appendAll(aU); }
+    template<typename U, size_t O, class BP>
+    bool appendAll(const mozilla::Vector<U, O, BP>& aU) { return vec().appendAll(aU); }
     bool appendN(const T& aT, size_t aN) { return vec().appendN(aT, aN); }
     template<typename U> bool append(const U* aBegin, const U* aEnd) {
         return vec().append(aBegin, aEnd);
     }
     template<typename U> bool append(const U* aBegin, size_t aLength) {
         return vec().append(aBegin, aLength);
     }
     template<typename U> void infallibleAppend(U&& aU) {
--- a/js/public/Vector.h
+++ b/js/public/Vector.h
@@ -14,53 +14,38 @@
 #pragma warning(push)
 #pragma warning(disable:4345)
 #endif
 
 namespace js {
 
 class TempAllocPolicy;
 
-// If we had C++11 template aliases, we could just use this:
-//
-//   template <typename T,
-//             size_t MinInlineCapacity = 0,
-//             class AllocPolicy = TempAllocPolicy>
-//   using Vector = mozilla::Vector<T, MinInlineCapacity, AllocPolicy>;
-//
-// ...and get rid of all the CRTP madness in mozilla::Vector(Base).  But we
-// can't because compiler support's not up to snuff.  (Template aliases are in
-// gcc 4.7 and clang 3.0 and are expected to be in MSVC 2013.)  Instead, have a
-// completely separate class inheriting from mozilla::Vector, and throw CRTP at
-// the problem til things work.
-//
-// This workaround presents a couple issues.  First, because js::Vector is a
-// distinct type from mozilla::Vector, overload resolution, method calls, etc.
-// are affected.  *Hopefully* this won't be too bad in practice.  (A bunch of
-// places had to be fixed when mozilla::Vector was introduced, but it wasn't a
-// crazy number.)  Second, mozilla::Vector's interface has to be made subclass-
-// ready via CRTP -- or rather, via mozilla::VectorBase, which basically no one
-// should use.  :-)  Third, we have to redefine the constructors and the non-
-// inherited operators.  Blech.  Happily there aren't too many of these, so it
-// isn't the end of the world.
+namespace detail {
+
+template <typename T>
+struct TypeIsGCThing : mozilla::FalseType
+{};
+
+// Uncomment this once we actually can assert it:
+//template <>
+//struct TypeIsGCThing<JS::Value> : mozilla::TrueType
+//{};
+
+} // namespace detail
 
 template <typename T,
           size_t MinInlineCapacity = 0,
-          class AllocPolicy = TempAllocPolicy>
-class Vector
-  : public mozilla::VectorBase<T,
-                               MinInlineCapacity,
-                               AllocPolicy,
-                               Vector<T, MinInlineCapacity, AllocPolicy> >
-{
-    typedef typename mozilla::VectorBase<T, MinInlineCapacity, AllocPolicy, Vector> Base;
-
-  public:
-    explicit Vector(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
-    Vector(Vector&& vec) : Base(mozilla::Move(vec)) {}
-    Vector& operator=(Vector&& vec) {
-        return Base::operator=(mozilla::Move(vec));
-    }
-};
+          class AllocPolicy = TempAllocPolicy
+// 1800 is MSVC2013.  Optimistically assume MSVC2015 (1900) is fixed.
+// If you're porting to MSVC2015 and this doesn't work, extend the
+// condition to encompass that additional version (but *do* keep the
+// version-check so we know when MSVC's fixed).
+#if !defined(_MSC_VER) || (1800 <= _MSC_VER && _MSC_VER <= 1800)
+         // Don't use this with JS::Value!  Use JS::AutoValueVector instead.
+         , typename = typename mozilla::EnableIf<!detail::TypeIsGCThing<T>::value>::Type
+#endif
+         >
+using Vector = mozilla::Vector<T, MinInlineCapacity, AllocPolicy>;
 
 } // namespace js
 
 #endif /* js_Vector_h */
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -18,16 +18,17 @@
 
 #include "asmjs/AsmJSModule.h"
 
 #include "mozilla/BinarySearch.h"
 #include "mozilla/Compression.h"
 #include "mozilla/EnumeratedRange.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/TaggedAnonymousMemory.h"
+#include "mozilla/Vector.h"
 
 #include "jslibmath.h"
 #include "jsmath.h"
 #include "jsprf.h"
 
 #include "builtin/AtomicsObject.h"
 #include "frontend/Parser.h"
 #include "jit/IonCode.h"
@@ -1127,97 +1128,98 @@ bool
 AsmJSModule::Name::clone(ExclusiveContext* cx, Name* out) const
 {
     out->name_ = name_;
     return true;
 }
 
 template <class T, size_t N>
 size_t
-SerializedVectorSize(const Vector<T, N, SystemAllocPolicy>& vec)
+SerializedVectorSize(const mozilla::Vector<T, N, SystemAllocPolicy>& vec)
 {
     size_t size = sizeof(uint32_t);
     for (size_t i = 0; i < vec.length(); i++)
         size += vec[i].serializedSize();
     return size;
 }
 
 template <class T, size_t N>
 uint8_t*
-SerializeVector(uint8_t* cursor, const Vector<T, N, SystemAllocPolicy>& vec)
+SerializeVector(uint8_t* cursor, const mozilla::Vector<T, N, SystemAllocPolicy>& vec)
 {
     cursor = WriteScalar<uint32_t>(cursor, vec.length());
     for (size_t i = 0; i < vec.length(); i++)
         cursor = vec[i].serialize(cursor);
     return cursor;
 }
 
 template <class T, size_t N>
 const uint8_t*
-DeserializeVector(ExclusiveContext* cx, const uint8_t* cursor, Vector<T, N, SystemAllocPolicy>* vec)
+DeserializeVector(ExclusiveContext* cx, const uint8_t* cursor,
+                  mozilla::Vector<T, N, SystemAllocPolicy>* vec)
 {
     uint32_t length;
     cursor = ReadScalar<uint32_t>(cursor, &length);
     if (!vec->resize(length))
         return nullptr;
     for (size_t i = 0; i < vec->length(); i++) {
         if (!(cursor = (*vec)[i].deserialize(cx, cursor)))
             return nullptr;
     }
     return cursor;
 }
 
 template <class T, size_t N>
 bool
-CloneVector(ExclusiveContext* cx, const Vector<T, N, SystemAllocPolicy>& in,
-            Vector<T, N, SystemAllocPolicy>* out)
+CloneVector(ExclusiveContext* cx, const mozilla::Vector<T, N, SystemAllocPolicy>& in,
+            mozilla::Vector<T, N, SystemAllocPolicy>* out)
 {
     if (!out->resize(in.length()))
         return false;
     for (size_t i = 0; i < in.length(); i++) {
         if (!in[i].clone(cx, &(*out)[i]))
             return false;
     }
     return true;
 }
 
-template <class T, size_t N, class AllocPolicy, class ThisVector>
+template <class T, size_t N, class AllocPolicy>
 size_t
-SerializedPodVectorSize(const mozilla::VectorBase<T, N, AllocPolicy, ThisVector>& vec)
+SerializedPodVectorSize(const mozilla::Vector<T, N, AllocPolicy>& vec)
 {
     return sizeof(uint32_t) +
            vec.length() * sizeof(T);
 }
 
-template <class T, size_t N, class AllocPolicy, class ThisVector>
+template <class T, size_t N, class AllocPolicy>
 uint8_t*
-SerializePodVector(uint8_t* cursor, const mozilla::VectorBase<T, N, AllocPolicy, ThisVector>& vec)
+SerializePodVector(uint8_t* cursor, const mozilla::Vector<T, N, AllocPolicy>& vec)
 {
     cursor = WriteScalar<uint32_t>(cursor, vec.length());
     cursor = WriteBytes(cursor, vec.begin(), vec.length() * sizeof(T));
     return cursor;
 }
 
-template <class T, size_t N, class AllocPolicy, class ThisVector>
+template <class T, size_t N, class AllocPolicy>
 const uint8_t*
 DeserializePodVector(ExclusiveContext* cx, const uint8_t* cursor,
-                     mozilla::VectorBase<T, N, AllocPolicy, ThisVector>* vec)
+                     mozilla::Vector<T, N, AllocPolicy>* vec)
 {
     uint32_t length;
     cursor = ReadScalar<uint32_t>(cursor, &length);
     if (!vec->resize(length))
         return nullptr;
     cursor = ReadBytes(cursor, vec->begin(), length * sizeof(T));
     return cursor;
 }
 
 template <class T, size_t N>
 bool
-ClonePodVector(ExclusiveContext* cx, const Vector<T, N, SystemAllocPolicy>& in,
-               Vector<T, N, SystemAllocPolicy>* out)
+ClonePodVector(ExclusiveContext* cx, const mozilla::Vector<T, N, SystemAllocPolicy>& in,
+               mozilla::Vector<T, N, SystemAllocPolicy>* out)
 {
     if (!out->resize(in.length()))
         return false;
     PodCopy(out->begin(), in.begin(), in.length());
     return true;
 }
 
 size_t
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -4,16 +4,17 @@
  * 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 "ctypes/CTypes.h"
 
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/NumericLimits.h"
+#include "mozilla/Vector.h"
 
 #include <math.h>
 #include <stdint.h>
 
 #if defined(XP_WIN)
 #include <float.h>
 #endif
 
@@ -35,16 +36,17 @@
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsnum.h"
 #include "jsprf.h"
 
 #include "builtin/TypedObject.h"
 #include "ctypes/Library.h"
 #include "gc/Zone.h"
+#include "js/Vector.h"
 
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
 using namespace std;
 using mozilla::NumericLimits;
 
 using JS::AutoCheckCannotGC;
@@ -2653,17 +2655,17 @@ jsvalToPtrExplicit(JSContext* cx, Value 
       return uint64_t(*result) == i;
     }
   }
   return false;
 }
 
 template<class IntegerType, class CharType, size_t N, class AP>
 void
-IntegerToString(IntegerType i, int radix, Vector<CharType, N, AP>& result)
+IntegerToString(IntegerType i, int radix, mozilla::Vector<CharType, N, AP>& result)
 {
   JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
 
   // The buffer must be big enough for all the bits of IntegerType to fit,
   // in base-2, including '-'.
   CharType buffer[sizeof(IntegerType) * 8 + 1];
   CharType* end = buffer + sizeof(buffer) / sizeof(CharType);
   CharType* cp = end;
@@ -3649,17 +3651,17 @@ BuildTypeSource(JSContext* cx,
       AppendString(result, ")");
       break;
     }
 
     AppendString(result, ", [");
 
     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
     size_t length = fields->count();
-    Array<const FieldInfoHash::Entry*, 64> fieldsArray;
+    Vector<const FieldInfoHash::Entry*, 64, SystemAllocPolicy> fieldsArray;
     if (!fieldsArray.resize(length))
       break;
 
     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
       fieldsArray[r.front().value().mIndex] = &r.front();
 
     for (size_t i = 0; i < length; ++i) {
       const FieldInfoHash::Entry* entry = fieldsArray[i];
@@ -3807,17 +3809,17 @@ BuildDataSource(JSContext* cx,
       // a sequence of arguments to the StructType constructor.
       AppendString(result, "{");
     }
 
     // Serialize each field of the struct recursively. Each field must
     // be able to ImplicitConvert successfully.
     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
     size_t length = fields->count();
-    Array<const FieldInfoHash::Entry*, 64> fieldsArray;
+    Vector<const FieldInfoHash::Entry*, 64, SystemAllocPolicy> fieldsArray;
     if (!fieldsArray.resize(length))
       return false;
 
     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
       fieldsArray[r.front().value().mIndex] = &r.front();
 
     for (size_t i = 0; i < length; ++i) {
       const FieldInfoHash::Entry* entry = fieldsArray[i];
@@ -6505,17 +6507,17 @@ FunctionType::ConstructData(JSContext* c
   // This permanently associates this object with the closure, and avoids
   // having to do things like reset SLOT_REFERENT when someone tries to
   // change the pointer value.
   // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter
   // could be called on a frozen object.
   return JS_FreezeObject(cx, dataObj);
 }
 
-typedef Array<AutoValue, 16> AutoValueAutoArray;
+typedef Vector<AutoValue, 16, SystemAllocPolicy> AutoValueAutoArray;
 
 static bool
 ConvertArgument(JSContext* cx,
                 HandleObject funObj,
                 unsigned argIndex,
                 HandleValue arg,
                 JSObject* type,
                 AutoValue* value,
--- a/js/src/ctypes/CTypes.h
+++ b/js/src/ctypes/CTypes.h
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #ifndef ctypes_CTypes_h
 #define ctypes_CTypes_h
 
 #include "mozilla/UniquePtr.h"
+#include "mozilla/Vector.h"
 
 #include "ffi.h"
 #include "jsalloc.h"
 #include "jsprf.h"
 #include "prlink.h"
 
 #include "ctypes/typedefs.h"
 #include "js/GCHashTable.h"
@@ -20,96 +21,88 @@
 
 namespace js {
 namespace ctypes {
 
 /*******************************************************************************
 ** Utility classes
 *******************************************************************************/
 
-// Container class for Vector, using SystemAllocPolicy.
-template<class T, size_t N = 0>
-class Array : public Vector<T, N, SystemAllocPolicy>
-{
-  static_assert(!mozilla::IsSame<T, JS::Value>::value,
-                "use JS::AutoValueVector instead");
-};
-
 // String and AutoString classes, based on Vector.
 typedef Vector<char16_t,  0, SystemAllocPolicy> String;
 typedef Vector<char16_t, 64, SystemAllocPolicy> AutoString;
 typedef Vector<char,      0, SystemAllocPolicy> CString;
 typedef Vector<char,     64, SystemAllocPolicy> AutoCString;
 
 // Convenience functions to append, insert, and compare Strings.
 template <class T, size_t N, class AP, size_t ArrayLength>
 void
-AppendString(Vector<T, N, AP>& v, const char (&array)[ArrayLength])
+AppendString(mozilla::Vector<T, N, AP>& v, const char (&array)[ArrayLength])
 {
   // Don't include the trailing '\0'.
   size_t alen = ArrayLength - 1;
   size_t vlen = v.length();
   if (!v.resize(vlen + alen))
     return;
 
   for (size_t i = 0; i < alen; ++i)
     v[i + vlen] = array[i];
 }
 
 template <class T, size_t N, class AP>
 void
-AppendChars(Vector<T, N, AP>& v, const char c, size_t count)
+AppendChars(mozilla::Vector<T, N, AP>& v, const char c, size_t count)
 {
   size_t vlen = v.length();
   if (!v.resize(vlen + count))
     return;
 
   for (size_t i = 0; i < count; ++i)
     v[i + vlen] = c;
 }
 
 template <class T, size_t N, class AP>
 void
-AppendUInt(Vector<T, N, AP>& v, unsigned n)
+AppendUInt(mozilla::Vector<T, N, AP>& v, unsigned n)
 {
   char array[16];
   size_t alen = JS_snprintf(array, 16, "%u", n);
   size_t vlen = v.length();
   if (!v.resize(vlen + alen))
     return;
 
   for (size_t i = 0; i < alen; ++i)
     v[i + vlen] = array[i];
 }
 
 template <class T, size_t N, size_t M, class AP>
 void
-AppendString(Vector<T, N, AP>& v, Vector<T, M, AP>& w)
+AppendString(mozilla::Vector<T, N, AP>& v, mozilla::Vector<T, M, AP>& w)
 {
   v.append(w.begin(), w.length());
 }
 
 template <size_t N, class AP>
 void
-AppendString(Vector<char16_t, N, AP>& v, JSString* str)
+AppendString(mozilla::Vector<char16_t, N, AP>& v, JSString* str)
 {
   MOZ_ASSERT(str);
   JSLinearString* linear = str->ensureLinear(nullptr);
   if (!linear)
     return;
   JS::AutoCheckCannotGC nogc;
   if (linear->hasLatin1Chars())
     v.append(linear->latin1Chars(nogc), linear->length());
   else
     v.append(linear->twoByteChars(nogc), linear->length());
 }
 
 template <size_t N, class AP>
 void
-AppendString(Vector<char, N, AP>& v, JSString* str)
+AppendString(mozilla::Vector<char, N, AP>& v, JSString* str)
 {
   MOZ_ASSERT(str);
   size_t vlen = v.length();
   size_t alen = str->length();
   if (!v.resize(vlen + alen))
     return;
 
   JSLinearString* linear = str->ensureLinear(nullptr);
@@ -125,17 +118,17 @@ AppendString(Vector<char, N, AP>& v, JSS
     const char16_t* chars = linear->twoByteChars(nogc);
     for (size_t i = 0; i < alen; ++i)
       v[i + vlen] = char(chars[i]);
   }
 }
 
 template <class T, size_t N, class AP, size_t ArrayLength>
 void
-PrependString(Vector<T, N, AP>& v, const char (&array)[ArrayLength])
+PrependString(mozilla::Vector<T, N, AP>& v, const char (&array)[ArrayLength])
 {
   // Don't include the trailing '\0'.
   size_t alen = ArrayLength - 1;
   size_t vlen = v.length();
   if (!v.resize(vlen + alen))
     return;
 
   // Move vector data forward. This is safe since we've already resized.
@@ -143,17 +136,17 @@ PrependString(Vector<T, N, AP>& v, const
 
   // Copy data to insert.
   for (size_t i = 0; i < alen; ++i)
     v[i] = array[i];
 }
 
 template <size_t N, class AP>
 void
-PrependString(Vector<char16_t, N, AP>& v, JSString* str)
+PrependString(mozilla::Vector<char16_t, N, AP>& v, JSString* str)
 {
   MOZ_ASSERT(str);
   size_t vlen = v.length();
   size_t alen = str->length();
   if (!v.resize(vlen + alen))
     return;
 
   JSLinearString* linear = str->ensureLinear(nullptr);
@@ -301,22 +294,22 @@ struct FunctionInfo
   // and ObjectValue. Stored as a JSObject* for ease of tracing.
   JS::Heap<JSObject*> mABI;
 
   // The CType of the value returned by the function.
   JS::Heap<JSObject*> mReturnType;
 
   // A fixed array of known parameter types, excluding any variadic
   // parameters (if mIsVariadic).
-  Array<JS::Heap<JSObject*> > mArgTypes;
+  Vector<JS::Heap<JSObject*>, 0, SystemAllocPolicy> mArgTypes;
 
   // A variable array of ffi_type*s corresponding to both known parameter
   // types and dynamic (variadic) parameter types. Longer than mArgTypes
   // only if mIsVariadic.
-  Array<ffi_type*> mFFITypes;
+  Vector<ffi_type*, 0, SystemAllocPolicy> mFFITypes;
 
   // Flag indicating whether the function behaves like a C function with
   // ... as the final formal parameter.
   bool mIsVariadic;
 };
 
 // Parameters necessary for invoking a JS function from a C closure.
 struct ClosureInfo
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -532,17 +532,17 @@ struct Callback {
       : op(nullptr), data(nullptr)
     {}
     Callback(F op, void* data)
       : op(op), data(data)
     {}
 };
 
 template<typename F>
-class CallbackVector : public Vector<Callback<F>, 4, SystemAllocPolicy> {};
+using CallbackVector = Vector<Callback<F>, 4, SystemAllocPolicy>;
 
 template <typename T, typename Iter0, typename Iter1>
 class ChainedIter
 {
     Iter0 iter0_;
     Iter1 iter1_;
 
   public:
--- a/mfbt/Vector.h
+++ b/mfbt/Vector.h
@@ -26,18 +26,18 @@
 /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4345)
 #endif
 
 namespace mozilla {
 
-template<typename T, size_t N, class AllocPolicy, class ThisVector>
-class VectorBase;
+template<typename T, size_t N, class AllocPolicy>
+class Vector;
 
 namespace detail {
 
 /*
  * Check that the given capacity wastes the minimal amount of space if
  * allocated on the heap. This means that aCapacity*sizeof(T) is as close to a
  * power-of-two as possible. growStorageBy() is responsible for ensuring this.
  */
@@ -47,17 +47,17 @@ static bool CapacityHasExcessSpace(size_
   size_t size = aCapacity * sizeof(T);
   return RoundUpPow2(size) - size >= sizeof(T);
 }
 
 /*
  * This template class provides a default implementation for vector operations
  * when the element type is not known to be a POD, as judged by IsPod.
  */
-template<typename T, size_t N, class AP, class ThisVector, bool IsPod>
+template<typename T, size_t N, class AP, bool IsPod>
 struct VectorImpl
 {
   /*
    * Constructs a default object in the uninitialized memory at *aDst.
    */
   MOZ_NONNULL(1)
   static inline void new_(T* aDst)
   {
@@ -133,17 +133,17 @@ struct VectorImpl
 
   /*
    * Grows the given buffer to have capacity aNewCap, preserving the objects
    * constructed in the range [begin, end) and updating aV. Assumes that (1)
    * aNewCap has not overflowed, and (2) multiplying aNewCap by sizeof(T) will
    * not overflow.
    */
   static inline bool
-  growTo(VectorBase<T, N, AP, ThisVector>& aV, size_t aNewCap)
+  growTo(Vector<T, N, AP>& aV, size_t aNewCap)
   {
     MOZ_ASSERT(!aV.usingInlineStorage());
     MOZ_ASSERT(!CapacityHasExcessSpace<T>(aNewCap));
     T* newbuf = aV.template pod_malloc<T>(aNewCap);
     if (MOZ_UNLIKELY(!newbuf)) {
       return false;
     }
     T* dst = newbuf;
@@ -160,18 +160,18 @@ struct VectorImpl
   }
 };
 
 /*
  * This partial template specialization provides a default implementation for
  * vector operations when the element type is known to be a POD, as judged by
  * IsPod.
  */
-template<typename T, size_t N, class AP, class ThisVector>
-struct VectorImpl<T, N, AP, ThisVector, true>
+template<typename T, size_t N, class AP>
+struct VectorImpl<T, N, AP, true>
 {
   static inline void new_(T* aDst)
   {
     *aDst = T();
   }
 
   template<typename U>
   static inline void new_(T* aDst, U&& aU)
@@ -224,17 +224,17 @@ struct VectorImpl<T, N, AP, ThisVector, 
   static inline void copyConstructN(T* aDst, size_t aN, const T& aT)
   {
     for (T* end = aDst + aN; aDst < end; ++aDst) {
       new_(aDst, aT);
     }
   }
 
   static inline bool
-  growTo(VectorBase<T, N, AP, ThisVector>& aV, size_t aNewCap)
+  growTo(Vector<T, N, AP>& aV, size_t aNewCap)
   {
     MOZ_ASSERT(!aV.usingInlineStorage());
     MOZ_ASSERT(!CapacityHasExcessSpace<T>(aNewCap));
     T* newbuf = aV.template pod_realloc<T>(aV.mBegin, aV.mCapacity, aNewCap);
     if (MOZ_UNLIKELY(!newbuf)) {
       return false;
     }
     aV.mBegin = newbuf;
@@ -246,30 +246,43 @@ struct VectorImpl<T, N, AP, ThisVector, 
 
 // A struct for TestVector.cpp to access private internal fields.
 // DO NOT DEFINE IN YOUR OWN CODE.
 struct VectorTesting;
 
 } // namespace detail
 
 /*
- * A CRTP base class for vector-like classes.  Unless you really really want
- * your own vector class -- and you almost certainly don't -- you should use
- * mozilla::Vector instead!
+ * STL-like container providing a short-lived, dynamic buffer.  Vector calls the
+ * constructors/destructors of all elements stored in its internal buffer, so
+ * non-PODs may be safely used.  Additionally, Vector will store the first N
+ * elements in-place before resorting to dynamic allocation.
  *
- * See mozilla::Vector for interface requirements.
+ * T requirements:
+ *  - default and copy constructible, assignable, destructible
+ *  - operations do not throw
+ * MinInlineCapacity requirements:
+ *  - any value, however, MinInlineCapacity is clamped to min/max values
+ * AllocPolicy:
+ *  - see "Allocation policies" in AllocPolicy.h (defaults to
+ *    mozilla::MallocAllocPolicy)
+ *
+ * Vector is not reentrant: T member functions called during Vector member
+ * functions must not call back into the same object!
  */
-template<typename T, size_t N, class AllocPolicy, class ThisVector>
-class VectorBase : private AllocPolicy
+template<typename T,
+         size_t MinInlineCapacity = 0,
+         class AllocPolicy = MallocAllocPolicy>
+class Vector final : private AllocPolicy
 {
   /* utilities */
 
   static const bool kElemIsPod = IsPod<T>::value;
-  typedef detail::VectorImpl<T, N, AllocPolicy, ThisVector, kElemIsPod> Impl;
-  friend struct detail::VectorImpl<T, N, AllocPolicy, ThisVector, kElemIsPod>;
+  typedef detail::VectorImpl<T, MinInlineCapacity, AllocPolicy, kElemIsPod> Impl;
+  friend struct detail::VectorImpl<T, MinInlineCapacity, AllocPolicy, kElemIsPod>;
 
   friend struct detail::VectorTesting;
 
   bool growStorageBy(size_t aIncr);
   bool convertToHeapStorage(size_t aNewCap);
 
   /* magic constants */
 
@@ -293,21 +306,21 @@ class VectorBase : private AllocPolicy
   };
   template<int Dummy>
   struct ElemSize<0, Dummy>
   {
     static const size_t value = 1;
   };
 
   static const size_t kInlineCapacity =
-    tl::Min<N, kMaxInlineBytes / ElemSize<N, 0>::value>::value;
+    tl::Min<MinInlineCapacity, kMaxInlineBytes / ElemSize<MinInlineCapacity, 0>::value>::value;
 
   /* Calculate inline buffer size; avoid 0-sized array. */
   static const size_t kInlineBytes =
-    tl::Max<1, kInlineCapacity * ElemSize<N, 0>::value>::value;
+    tl::Max<1, kInlineCapacity * ElemSize<MinInlineCapacity, 0>::value>::value;
 
   /* member data */
 
   /*
    * Pointer to the buffer, be it inline or heap-allocated. Only [mBegin,
    * mBegin + mLength) hold valid constructed T objects. The range [mBegin +
    * mLength, mBegin + mCapacity) holds uninitialized memory. The range
    * [mBegin + mLength, mBegin + mReserved) also holds uninitialized memory
@@ -333,17 +346,17 @@ class VectorBase : private AllocPolicy
   friend class ReentrancyGuard;
   bool mEntered;
 #endif
 
   /* private accessors */
 
   bool usingInlineStorage() const
   {
-    return mBegin == const_cast<VectorBase*>(this)->inlineStorage();
+    return mBegin == const_cast<Vector*>(this)->inlineStorage();
   }
 
   T* inlineStorage()
   {
     return static_cast<T*>(mStorage.addr());
   }
 
   T* beginNoCheck() const
@@ -374,38 +387,38 @@ class VectorBase : private AllocPolicy
     MOZ_ASSERT(mLength <= mReserved);
     MOZ_ASSERT(mReserved <= mCapacity);
     return mReserved;
   }
 #endif
 
   /* Append operations guaranteed to succeed due to pre-reserved space. */
   template<typename U> void internalAppend(U&& aU);
-  template<typename U, size_t O, class BP, class UV>
-  void internalAppendAll(const VectorBase<U, O, BP, UV>& aU);
+  template<typename U, size_t O, class BP>
+  void internalAppendAll(const Vector<U, O, BP>& aU);
   void internalAppendN(const T& aT, size_t aN);
   template<typename U> void internalAppend(const U* aBegin, size_t aLength);
 
 public:
-  static const size_t sMaxInlineStorage = N;
+  static const size_t sMaxInlineStorage = MinInlineCapacity;
 
   typedef T ElementType;
 
-  explicit VectorBase(AllocPolicy = AllocPolicy());
-  explicit VectorBase(ThisVector&&); /* Move constructor. */
-  ThisVector& operator=(ThisVector&&); /* Move assignment. */
-  ~VectorBase();
+  explicit Vector(AllocPolicy = AllocPolicy());
+  Vector(Vector&&); /* Move constructor. */
+  Vector& operator=(Vector&&); /* Move assignment. */
+  ~Vector();
 
   /* accessors */
 
   const AllocPolicy& allocPolicy() const { return *this; }
 
   AllocPolicy& allocPolicy() { return *this; }
 
-  enum { InlineLength = N };
+  enum { InlineLength = MinInlineCapacity };
 
   size_t length() const { return mLength; }
 
   bool empty() const { return mLength == 0; }
 
   size_t capacity() const { return mCapacity; }
 
   T* begin()
@@ -457,17 +470,17 @@ public:
   {
     MOZ_ASSERT(!mEntered);
     MOZ_ASSERT(!empty());
     return *(end() - 1);
   }
 
   class Range
   {
-    friend class VectorBase;
+    friend class Vector;
     T* mCur;
     T* mEnd;
     Range(T* aCur, T* aEnd)
       : mCur(aCur)
       , mEnd(aEnd)
     {
       MOZ_ASSERT(aCur <= aEnd);
     }
@@ -477,17 +490,17 @@ public:
     size_t remain() const { return PointerRangeSize(mCur, mEnd); }
     T& front() const { MOZ_ASSERT(!empty()); return *mCur; }
     void popFront() { MOZ_ASSERT(!empty()); ++mCur; }
     T popCopyFront() { MOZ_ASSERT(!empty()); return *mCur++; }
   };
 
   class ConstRange
   {
-    friend class VectorBase;
+    friend class Vector;
     const T* mCur;
     const T* mEnd;
     ConstRange(const T* aCur, const T* aEnd)
       : mCur(aCur)
       , mEnd(aEnd)
     {
       MOZ_ASSERT(aCur <= aEnd);
     }
@@ -571,18 +584,18 @@ public:
   bool emplaceBack(Args&&... aArgs)
   {
     if (!growByUninitialized(1))
       return false;
     new (&back()) T(Forward<Args>(aArgs)...);
     return true;
   }
 
-  template<typename U, size_t O, class BP, class UV>
-  bool appendAll(const VectorBase<U, O, BP, UV>& aU);
+  template<typename U, size_t O, class BP>
+  bool appendAll(const Vector<U, O, BP>& aU);
   bool appendN(const T& aT, size_t aN);
   template<typename U> bool append(const U* aBegin, const U* aEnd);
   template<typename U> bool append(const U* aBegin, size_t aLength);
 
   /*
    * Guaranteed-infallible append operations for use upon vectors whose
    * memory has been pre-reserved.  Don't use this if you haven't reserved the
    * memory!
@@ -673,55 +686,51 @@ public:
   size_t sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
 
   /**
    * Like sizeOfExcludingThis, but also measures the size of the vector
    * object (which must be heap-allocated) itself.
    */
   size_t sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
-  void swap(ThisVector& aOther);
+  void swap(Vector& aOther);
 
 private:
-  VectorBase(const VectorBase&) = delete;
-  void operator=(const VectorBase&) = delete;
-
-  /* Move-construct/assign only from our derived class, ThisVector. */
-  VectorBase(VectorBase&&) = delete;
-  void operator=(VectorBase&&) = delete;
+  Vector(const Vector&) = delete;
+  void operator=(const Vector&) = delete;
 };
 
 /* This does the re-entrancy check plus several other sanity checks. */
 #define MOZ_REENTRANCY_GUARD_ET_AL \
   ReentrancyGuard g(*this); \
   MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == kInlineCapacity); \
   MOZ_ASSERT(reserved() <= mCapacity); \
   MOZ_ASSERT(mLength <= reserved()); \
   MOZ_ASSERT(mLength <= mCapacity)
 
 /* Vector Implementation */
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_ALWAYS_INLINE
-VectorBase<T, N, AP, TV>::VectorBase(AP aAP)
+Vector<T, N, AP>::Vector(AP aAP)
   : AP(aAP)
   , mLength(0)
   , mCapacity(kInlineCapacity)
 #ifdef DEBUG
   , mReserved(0)
   , mEntered(false)
 #endif
 {
   mBegin = static_cast<T*>(mStorage.addr());
 }
 
 /* Move constructor. */
-template<typename T, size_t N, class AllocPolicy, class TV>
+template<typename T, size_t N, class AllocPolicy>
 MOZ_ALWAYS_INLINE
-VectorBase<T, N, AllocPolicy, TV>::VectorBase(TV&& aRhs)
+Vector<T, N, AllocPolicy>::Vector(Vector&& aRhs)
   : AllocPolicy(Move(aRhs))
 #ifdef DEBUG
   , mEntered(false)
 #endif
 {
   mLength = aRhs.mLength;
   mCapacity = aRhs.mCapacity;
 #ifdef DEBUG
@@ -747,46 +756,45 @@ VectorBase<T, N, AllocPolicy, TV>::Vecto
     aRhs.mLength = 0;
 #ifdef DEBUG
     aRhs.mReserved = 0;
 #endif
   }
 }
 
 /* Move assignment. */
-template<typename T, size_t N, class AP, class TV>
-MOZ_ALWAYS_INLINE TV&
-VectorBase<T, N, AP, TV>::operator=(TV&& aRhs)
+template<typename T, size_t N, class AP>
+MOZ_ALWAYS_INLINE Vector<T, N, AP>&
+Vector<T, N, AP>::operator=(Vector&& aRhs)
 {
   MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited");
-  TV* tv = static_cast<TV*>(this);
-  tv->~TV();
-  new(tv) TV(Move(aRhs));
-  return *tv;
+  this->~Vector();
+  new(this) Vector(Move(aRhs));
+  return *this;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_ALWAYS_INLINE
-VectorBase<T, N, AP, TV>::~VectorBase()
+Vector<T, N, AP>::~Vector()
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
   Impl::destroy(beginNoCheck(), endNoCheck());
   if (!usingInlineStorage()) {
     this->free_(beginNoCheck());
   }
 }
 
 /*
  * This function will create a new heap buffer with capacity aNewCap,
  * move all elements in the inline buffer to this new buffer,
  * and fail on OOM.
  */
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline bool
-VectorBase<T, N, AP, TV>::convertToHeapStorage(size_t aNewCap)
+Vector<T, N, AP>::convertToHeapStorage(size_t aNewCap)
 {
   MOZ_ASSERT(usingInlineStorage());
 
   /* Allocate buffer. */
   MOZ_ASSERT(!detail::CapacityHasExcessSpace<T>(aNewCap));
   T* newBuf = this->template pod_malloc<T>(aNewCap);
   if (MOZ_UNLIKELY(!newBuf)) {
     return false;
@@ -798,19 +806,19 @@ VectorBase<T, N, AP, TV>::convertToHeapS
 
   /* Switch in heap buffer. */
   mBegin = newBuf;
   /* mLength is unchanged. */
   mCapacity = aNewCap;
   return true;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_NEVER_INLINE bool
-VectorBase<T, N, AP, TV>::growStorageBy(size_t aIncr)
+Vector<T, N, AP>::growStorageBy(size_t aIncr)
 {
   MOZ_ASSERT(mLength + aIncr > mCapacity);
 
   /*
    * When choosing a new capacity, its size should is as close to 2**N bytes
    * as possible.  2**N-sized requests are best because they are unlikely to
    * be rounded up by the allocator.  Asking for a 2**N number of elements
    * isn't as good, because if sizeof(T) is not a power-of-two that would
@@ -880,19 +888,19 @@ VectorBase<T, N, AP, TV>::growStorageBy(
 convert:
     return convertToHeapStorage(newCap);
   }
 
 grow:
   return Impl::growTo(*this, newCap);
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline bool
-VectorBase<T, N, AP, TV>::initCapacity(size_t aRequest)
+Vector<T, N, AP>::initCapacity(size_t aRequest)
 {
   MOZ_ASSERT(empty());
   MOZ_ASSERT(usingInlineStorage());
   if (aRequest == 0) {
     return true;
   }
   T* newbuf = this->template pod_malloc<T>(aRequest);
   if (MOZ_UNLIKELY(!newbuf)) {
@@ -901,19 +909,19 @@ VectorBase<T, N, AP, TV>::initCapacity(s
   mBegin = newbuf;
   mCapacity = aRequest;
 #ifdef DEBUG
   mReserved = aRequest;
 #endif
   return true;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline bool
-VectorBase<T, N, AP, TV>::reserve(size_t aRequest)
+Vector<T, N, AP>::reserve(size_t aRequest)
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
   if (aRequest > mCapacity) {
     if (MOZ_UNLIKELY(!growStorageBy(aRequest - mLength))) {
       return false;
     }
   } else if (aRequest > N) {
     if (!allocPolicy().checkSimulatedOOM()) {
@@ -925,29 +933,29 @@ VectorBase<T, N, AP, TV>::reserve(size_t
     mReserved = aRequest;
   }
   MOZ_ASSERT(mLength <= mReserved);
   MOZ_ASSERT(mReserved <= mCapacity);
 #endif
   return true;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline void
-VectorBase<T, N, AP, TV>::shrinkBy(size_t aIncr)
+Vector<T, N, AP>::shrinkBy(size_t aIncr)
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
   MOZ_ASSERT(aIncr <= mLength);
   Impl::destroy(endNoCheck() - aIncr, endNoCheck());
   mLength -= aIncr;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_ALWAYS_INLINE bool
-VectorBase<T, N, AP, TV>::growBy(size_t aIncr)
+Vector<T, N, AP>::growBy(size_t aIncr)
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
   if (aIncr > mCapacity - mLength) {
     if (MOZ_UNLIKELY(!growStorageBy(aIncr))) {
       return false;
     }
   } else if (aIncr + mLength > N) {
     if (!allocPolicy().checkSimulatedOOM()) {
@@ -961,127 +969,126 @@ VectorBase<T, N, AP, TV>::growBy(size_t 
 #ifdef DEBUG
   if (mLength > mReserved) {
     mReserved = mLength;
   }
 #endif
   return true;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_ALWAYS_INLINE bool
-VectorBase<T, N, AP, TV>::growByUninitialized(size_t aIncr)
+Vector<T, N, AP>::growByUninitialized(size_t aIncr)
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
   if (aIncr > mCapacity - mLength) {
     if (MOZ_UNLIKELY(!growStorageBy(aIncr))) {
       return false;
     }
   } else if (aIncr + mLength > N) {
     if (!allocPolicy().checkSimulatedOOM()) {
       return false;
     }
   }
   infallibleGrowByUninitialized(aIncr);
   return true;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_ALWAYS_INLINE void
-VectorBase<T, N, AP, TV>::infallibleGrowByUninitialized(size_t aIncr)
+Vector<T, N, AP>::infallibleGrowByUninitialized(size_t aIncr)
 {
   MOZ_ASSERT(mLength + aIncr <= mCapacity);
   mLength += aIncr;
 #ifdef DEBUG
   if (mLength > mReserved) {
     mReserved = mLength;
   }
 #endif
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline bool
-VectorBase<T, N, AP, TV>::resize(size_t aNewLength)
+Vector<T, N, AP>::resize(size_t aNewLength)
 {
   size_t curLength = mLength;
   if (aNewLength > curLength) {
     return growBy(aNewLength - curLength);
   }
   shrinkBy(curLength - aNewLength);
   return true;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_ALWAYS_INLINE bool
-VectorBase<T, N, AP, TV>::resizeUninitialized(size_t aNewLength)
+Vector<T, N, AP>::resizeUninitialized(size_t aNewLength)
 {
   size_t curLength = mLength;
   if (aNewLength > curLength) {
     return growByUninitialized(aNewLength - curLength);
   }
   shrinkBy(curLength - aNewLength);
   return true;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline void
-VectorBase<T, N, AP, TV>::clear()
+Vector<T, N, AP>::clear()
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
   Impl::destroy(beginNoCheck(), endNoCheck());
   mLength = 0;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline void
-VectorBase<T, N, AP, TV>::clearAndFree()
+Vector<T, N, AP>::clearAndFree()
 {
   clear();
 
   if (usingInlineStorage()) {
     return;
   }
   this->free_(beginNoCheck());
   mBegin = static_cast<T*>(mStorage.addr());
   mCapacity = kInlineCapacity;
 #ifdef DEBUG
   mReserved = 0;
 #endif
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline bool
-VectorBase<T, N, AP, TV>::canAppendWithoutRealloc(size_t aNeeded) const
+Vector<T, N, AP>::canAppendWithoutRealloc(size_t aNeeded) const
 {
   return mLength + aNeeded <= mCapacity;
 }
 
-template<typename T, size_t N, class AP, class TV>
-template<typename U, size_t O, class BP, class UV>
+template<typename T, size_t N, class AP>
+template<typename U, size_t O, class BP>
 MOZ_ALWAYS_INLINE void
-VectorBase<T, N, AP, TV>::internalAppendAll(
-  const VectorBase<U, O, BP, UV>& aOther)
+Vector<T, N, AP>::internalAppendAll(const Vector<U, O, BP>& aOther)
 {
   internalAppend(aOther.begin(), aOther.length());
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 template<typename U>
 MOZ_ALWAYS_INLINE void
-VectorBase<T, N, AP, TV>::internalAppend(U&& aU)
+Vector<T, N, AP>::internalAppend(U&& aU)
 {
   MOZ_ASSERT(mLength + 1 <= mReserved);
   MOZ_ASSERT(mReserved <= mCapacity);
   Impl::new_(endNoCheck(), Forward<U>(aU));
   ++mLength;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_ALWAYS_INLINE bool
-VectorBase<T, N, AP, TV>::appendN(const T& aT, size_t aNeeded)
+Vector<T, N, AP>::appendN(const T& aT, size_t aNeeded)
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
   if (mLength + aNeeded > mCapacity) {
     if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
       return false;
     }
   } else if (mLength + aNeeded > N) {
     if (!allocPolicy().checkSimulatedOOM())
@@ -1091,30 +1098,30 @@ VectorBase<T, N, AP, TV>::appendN(const 
   if (mLength + aNeeded > mReserved) {
     mReserved = mLength + aNeeded;
   }
 #endif
   internalAppendN(aT, aNeeded);
   return true;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_ALWAYS_INLINE void
-VectorBase<T, N, AP, TV>::internalAppendN(const T& aT, size_t aNeeded)
+Vector<T, N, AP>::internalAppendN(const T& aT, size_t aNeeded)
 {
   MOZ_ASSERT(mLength + aNeeded <= mReserved);
   MOZ_ASSERT(mReserved <= mCapacity);
   Impl::copyConstructN(endNoCheck(), aNeeded, aT);
   mLength += aNeeded;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 template<typename U>
 inline T*
-VectorBase<T, N, AP, TV>::insert(T* aP, U&& aVal)
+Vector<T, N, AP>::insert(T* aP, U&& aVal)
 {
   MOZ_ASSERT(begin() <= aP);
   MOZ_ASSERT(aP <= end());
   size_t pos = aP - begin();
   MOZ_ASSERT(pos <= mLength);
   size_t oldLength = mLength;
   if (pos == oldLength) {
     if (!append(Forward<U>(aVal))) {
@@ -1128,46 +1135,46 @@ VectorBase<T, N, AP, TV>::insert(T* aP, 
     for (size_t i = oldLength; i > pos; --i) {
       (*this)[i] = Move((*this)[i - 1]);
     }
     (*this)[pos] = Forward<U>(aVal);
   }
   return begin() + pos;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline void
-VectorBase<T, N, AP, TV>::erase(T* aIt)
+Vector<T, N, AP>::erase(T* aIt)
 {
   MOZ_ASSERT(begin() <= aIt);
   MOZ_ASSERT(aIt < end());
   while (aIt + 1 < end()) {
     *aIt = Move(*(aIt + 1));
     ++aIt;
   }
   popBack();
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline void
-VectorBase<T, N, AP, TV>::erase(T* aBegin, T* aEnd)
+Vector<T, N, AP>::erase(T* aBegin, T* aEnd)
 {
   MOZ_ASSERT(begin() <= aBegin);
   MOZ_ASSERT(aBegin <= aEnd);
   MOZ_ASSERT(aEnd <= end());
   while (aEnd < end()) {
     *aBegin++ = Move(*aEnd++);
   }
   shrinkBy(aEnd - aBegin);
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 template<typename U>
 MOZ_ALWAYS_INLINE bool
-VectorBase<T, N, AP, TV>::append(const U* aInsBegin, const U* aInsEnd)
+Vector<T, N, AP>::append(const U* aInsBegin, const U* aInsEnd)
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
   size_t aNeeded = PointerRangeSize(aInsBegin, aInsEnd);
   if (mLength + aNeeded > mCapacity) {
     if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
       return false;
     }
   } else if (mLength + aNeeded > N) {
@@ -1178,31 +1185,31 @@ VectorBase<T, N, AP, TV>::append(const U
   if (mLength + aNeeded > mReserved) {
     mReserved = mLength + aNeeded;
   }
 #endif
   internalAppend(aInsBegin, aNeeded);
   return true;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 template<typename U>
 MOZ_ALWAYS_INLINE void
-VectorBase<T, N, AP, TV>::internalAppend(const U* aInsBegin, size_t aInsLength)
+Vector<T, N, AP>::internalAppend(const U* aInsBegin, size_t aInsLength)
 {
   MOZ_ASSERT(mLength + aInsLength <= mReserved);
   MOZ_ASSERT(mReserved <= mCapacity);
   Impl::copyConstruct(endNoCheck(), aInsBegin, aInsBegin + aInsLength);
   mLength += aInsLength;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 template<typename U>
 MOZ_ALWAYS_INLINE bool
-VectorBase<T, N, AP, TV>::append(U&& aU)
+Vector<T, N, AP>::append(U&& aU)
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
   if (mLength == mCapacity) {
     if (MOZ_UNLIKELY(!growStorageBy(1))) {
       return false;
     }
   } else if (mLength + 1 > N) {
     if (!allocPolicy().checkSimulatedOOM())
@@ -1212,54 +1219,54 @@ VectorBase<T, N, AP, TV>::append(U&& aU)
   if (mLength + 1 > mReserved) {
     mReserved = mLength + 1;
   }
 #endif
   internalAppend(Forward<U>(aU));
   return true;
 }
 
-template<typename T, size_t N, class AP, class TV>
-template<typename U, size_t O, class BP, class UV>
+template<typename T, size_t N, class AP>
+template<typename U, size_t O, class BP>
 MOZ_ALWAYS_INLINE bool
-VectorBase<T, N, AP, TV>::appendAll(const VectorBase<U, O, BP, UV>& aOther)
+Vector<T, N, AP>::appendAll(const Vector<U, O, BP>& aOther)
 {
   return append(aOther.begin(), aOther.length());
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 template<class U>
 MOZ_ALWAYS_INLINE bool
-VectorBase<T, N, AP, TV>::append(const U* aInsBegin, size_t aInsLength)
+Vector<T, N, AP>::append(const U* aInsBegin, size_t aInsLength)
 {
   return append(aInsBegin, aInsBegin + aInsLength);
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_ALWAYS_INLINE void
-VectorBase<T, N, AP, TV>::popBack()
+Vector<T, N, AP>::popBack()
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
   MOZ_ASSERT(!empty());
   --mLength;
   endNoCheck()->~T();
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 MOZ_ALWAYS_INLINE T
-VectorBase<T, N, AP, TV>::popCopy()
+Vector<T, N, AP>::popCopy()
 {
   T ret = back();
   popBack();
   return ret;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline T*
-VectorBase<T, N, AP, TV>::extractRawBuffer()
+Vector<T, N, AP>::extractRawBuffer()
 {
   T* ret;
   if (usingInlineStorage()) {
     ret = this->template pod_malloc<T>(mLength);
     if (!ret) {
       return nullptr;
     }
     Impl::copyConstruct(ret, beginNoCheck(), endNoCheck());
@@ -1273,19 +1280,19 @@ VectorBase<T, N, AP, TV>::extractRawBuff
     mCapacity = kInlineCapacity;
 #ifdef DEBUG
     mReserved = 0;
 #endif
   }
   return ret;
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline void
-VectorBase<T, N, AP, TV>::replaceRawBuffer(T* aP, size_t aLength)
+Vector<T, N, AP>::replaceRawBuffer(T* aP, size_t aLength)
 {
   MOZ_REENTRANCY_GUARD_ET_AL;
 
   /* Destroy what we have. */
   Impl::destroy(beginNoCheck(), endNoCheck());
   if (!usingInlineStorage()) {
     this->free_(beginNoCheck());
   }
@@ -1308,33 +1315,33 @@ VectorBase<T, N, AP, TV>::replaceRawBuff
     mLength = aLength;
     mCapacity = aLength;
   }
 #ifdef DEBUG
   mReserved = aLength;
 #endif
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline size_t
-VectorBase<T, N, AP, TV>::sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
+Vector<T, N, AP>::sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
   return usingInlineStorage() ? 0 : aMallocSizeOf(beginNoCheck());
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline size_t
-VectorBase<T, N, AP, TV>::sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+Vector<T, N, AP>::sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this) + sizeOfExcludingThis(aMallocSizeOf);
 }
 
-template<typename T, size_t N, class AP, class TV>
+template<typename T, size_t N, class AP>
 inline void
-VectorBase<T, N, AP, TV>::swap(TV& aOther)
+Vector<T, N, AP>::swap(Vector& aOther)
 {
   static_assert(N == 0,
                 "still need to implement this for N != 0");
 
   // This only works when inline storage is always empty.
   if (!usingInlineStorage() && aOther.usingInlineStorage()) {
     aOther.mBegin = mBegin;
     mBegin = inlineStorage();
@@ -1349,53 +1356,15 @@ VectorBase<T, N, AP, TV>::swap(TV& aOthe
 
   Swap(mLength, aOther.mLength);
   Swap(mCapacity, aOther.mCapacity);
 #ifdef DEBUG
   Swap(mReserved, aOther.mReserved);
 #endif
 }
 
-/*
- * STL-like container providing a short-lived, dynamic buffer.  Vector calls the
- * constructors/destructors of all elements stored in its internal buffer, so
- * non-PODs may be safely used.  Additionally, Vector will store the first N
- * elements in-place before resorting to dynamic allocation.
- *
- * T requirements:
- *  - default and copy constructible, assignable, destructible
- *  - operations do not throw
- * N requirements:
- *  - any value, however, N is clamped to min/max values
- * AllocPolicy:
- *  - see "Allocation policies" in AllocPolicy.h (defaults to
- *    mozilla::MallocAllocPolicy)
- *
- * Vector is not reentrant: T member functions called during Vector member
- * functions must not call back into the same object!
- */
-template<typename T,
-         size_t MinInlineCapacity = 0,
-         class AllocPolicy = MallocAllocPolicy>
-class Vector
-  : public VectorBase<T,
-                      MinInlineCapacity,
-                      AllocPolicy,
-                      Vector<T, MinInlineCapacity, AllocPolicy> >
-{
-  typedef VectorBase<T, MinInlineCapacity, AllocPolicy, Vector> Base;
-
-public:
-  explicit Vector(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
-  Vector(Vector&& vec) : Base(Move(vec)) {}
-  Vector& operator=(Vector&& aOther)
-  {
-    return Base::operator=(Move(aOther));
-  }
-};
-
 } // namespace mozilla
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 #endif /* mozilla_Vector_h */
--- a/toolkit/components/telemetry/ThreadHangStats.h
+++ b/toolkit/components/telemetry/ThreadHangStats.h
@@ -42,30 +42,34 @@ public:
     MOZ_ASSERT(aBucket < ArrayLength(*this));
     return (1u << (aBucket + 1u)) - 1u;
   }
   void Add(PRIntervalTime aTime);
 };
 
 /* HangStack stores an array of const char pointers,
    with optional internal storage for strings. */
-class HangStack : public mozilla::Vector<const char*, 8>
+class HangStack
 {
+public:
+  static const size_t sMaxInlineStorage = 8;
+
 private:
-  typedef mozilla::Vector<const char*, 8> Base;
+  typedef mozilla::Vector<const char*, sMaxInlineStorage> Impl;
+  Impl mImpl;
 
   // Stack entries can either be a static const char*
   // or a pointer to within this buffer.
   mozilla::Vector<char, 0> mBuffer;
 
 public:
   HangStack() { }
 
   HangStack(HangStack&& aOther)
-    : Base(mozilla::Move(aOther))
+    : mImpl(mozilla::Move(aOther.mImpl))
     , mBuffer(mozilla::Move(aOther.mBuffer))
   {
   }
 
   bool operator==(const HangStack& aOther) const {
     for (size_t i = 0; i < length(); i++) {
       if (!IsSameAsEntry(operator[](i), aOther[i])) {
         return false;
@@ -73,18 +77,44 @@ public:
     }
     return true;
   }
 
   bool operator!=(const HangStack& aOther) const {
     return !operator==(aOther);
   }
 
+  const char*& operator[](size_t aIndex) {
+    return mImpl[aIndex];
+  }
+
+  const char* const& operator[](size_t aIndex) const {
+    return mImpl[aIndex];
+  }
+
+  size_t capacity() const { return mImpl.capacity(); }
+  size_t length() const { return mImpl.length(); }
+  bool empty() const { return mImpl.empty(); }
+  bool canAppendWithoutRealloc(size_t aNeeded) const {
+    return mImpl.canAppendWithoutRealloc(aNeeded);
+  }
+  void infallibleAppend(const char* aEntry) { mImpl.infallibleAppend(aEntry); }
+  bool reserve(size_t aRequest) { return mImpl.reserve(aRequest); }
+  const char** begin() { return mImpl.begin(); }
+  const char* const* begin() const { return mImpl.begin(); }
+  const char** end() { return mImpl.end(); }
+  const char* const* end() const { return mImpl.end(); }
+  const char*& back() { return mImpl.back(); }
+  void erase(const char** aEntry) { mImpl.erase(aEntry); }
+  void erase(const char** aBegin, const char** aEnd) {
+    mImpl.erase(aBegin, aEnd);
+  }
+
   void clear() {
-    Base::clear();
+    mImpl.clear();
     mBuffer.clear();
   }
 
   bool IsInBuffer(const char* aEntry) const {
     return aEntry >= mBuffer.begin() && aEntry < mBuffer.end();
   }
 
   bool IsSameAsEntry(const char* aEntry, const char* aOther) const {