Bug 891177 - Implement mozilla/Vector.h, and make js/Vector.h implement js::Vector using mozilla::Vector's implementation of the functionality. r=terrence
authorJeff Walden <jwalden@mit.edu>
Tue, 09 Jul 2013 16:33:29 -0700
changeset 138949 7e972bc6d0f40d8546ed91ef22932682bcaa75dd
parent 138948 8abf922fb3ea4bb8af617666c64d165b9154eedd
child 138950 ca50803b5e55bab19e40ae4d8b58fe24de98a3ff
push id31182
push userjwalden@mit.edu
push dateThu, 18 Jul 2013 04:57:32 +0000
treeherdermozilla-inbound@7e972bc6d0f4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs891177
milestone25.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 891177 - Implement mozilla/Vector.h, and make js/Vector.h implement js::Vector using mozilla::Vector's implementation of the functionality. r=terrence
dom/camera/GonkCameraControl.cpp
js/public/MemoryMetrics.h
js/public/Vector.h
js/src/assembler/assembler/AbstractMacroAssembler.h
js/src/frontend/TokenStream.cpp
js/src/gc/Verifier.cpp
js/src/ion/AsmJS.cpp
js/src/ion/AsmJSModule.h
js/src/ion/IonAnalysis.h
js/src/ion/RegisterAllocator.h
js/src/jsapi.h
js/src/jsproxy.cpp
js/src/yarr/wtfbridge.h
mfbt/Vector.h
mfbt/exported_headers.mk
widget/gonk/nsAppShell.cpp
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -1049,17 +1049,17 @@ nsGonkCameraControl::TakePictureError()
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to dispatch takePicture() onError callback to main thread!");
   }
 }
 
 void
 nsGonkCameraControl::SetPreviewSize(uint32_t aWidth, uint32_t aHeight)
 {
-  Vector<Size> previewSizes;
+  android::Vector<Size> previewSizes;
   uint32_t bestWidth = aWidth;
   uint32_t bestHeight = aHeight;
   uint32_t minSizeDelta = UINT32_MAX;
   uint32_t delta;
   Size size;
 
   mParams.getSupportedPreviewSizes(previewSizes);
 
@@ -1432,17 +1432,17 @@ nsGonkCameraControl::GetRecorderProfileM
   return profileMgr.forget();
 }
 
 nsresult
 nsGonkCameraControl::GetVideoSizes(nsTArray<idl::CameraSize>& aVideoSizes)
 {
   aVideoSizes.Clear();
 
-  Vector<Size> sizes;
+  android::Vector<Size> sizes;
   mParams.getSupportedVideoSizes(sizes);
   if (sizes.size() == 0) {
     DOM_CAMERA_LOGI("Camera doesn't support video independent of the preview\n");
     mParams.getSupportedPreviewSizes(sizes);
   }
 
   if (sizes.size() == 0) {
     DOM_CAMERA_LOGW("Camera doesn't report any supported video sizes at all\n");
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -174,17 +174,17 @@ struct ZoneStats
         gcHeapTypeObjects(other.gcHeapTypeObjects),
         gcHeapIonCodes(other.gcHeapIonCodes),
         stringCharsNonHuge(other.stringCharsNonHuge),
         lazyScripts(other.lazyScripts),
         typeObjects(other.typeObjects),
         typePool(other.typePool),
         hugeStrings()
     {
-        hugeStrings.append(other.hugeStrings);
+        hugeStrings.appendAll(other.hugeStrings);
     }
 
     // Add other's numbers to this object's numbers.
     void add(ZoneStats &other) {
         #define ADD(x)  this->x += other.x
 
         ADD(gcHeapArenaAdmin);
         ADD(gcHeapUnusedGcThings);
@@ -197,17 +197,17 @@ struct ZoneStats
 
         ADD(stringCharsNonHuge);
         ADD(lazyScripts);
         ADD(typeObjects);
         ADD(typePool);
 
         #undef ADD
 
-        hugeStrings.append(other.hugeStrings);
+        hugeStrings.appendAll(other.hugeStrings);
     }
 
     // This field can be used by embedders.
     void   *extra;
 
     size_t gcHeapArenaAdmin;
     size_t gcHeapUnusedGcThings;
 
--- a/js/public/Vector.h
+++ b/js/public/Vector.h
@@ -2,1114 +2,65 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef js_Vector_h
 #define js_Vector_h
 
-#include "mozilla/Assertions.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/MathAlgorithms.h"
-#include "mozilla/MemoryReporting.h"
-#include "mozilla/Move.h"
-#include "mozilla/ReentrancyGuard.h"
-#include "mozilla/TemplateLib.h"
-#include "mozilla/TypeTraits.h"
-#include "mozilla/Util.h"
+#include "mozilla/Vector.h"
 
 /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4345)
 #endif
 
 namespace js {
 
 class TempAllocPolicy;
 
-template <class T,
+// 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.
+
+template <typename T,
           size_t MinInlineCapacity = 0,
           class AllocPolicy = TempAllocPolicy>
-class Vector;
-
-/*
- * Check that the given capacity wastes the minimal amount of space if
- * allocated on the heap.  This means that cap*sizeof(T) is as close to a
- * power-of-two as possible.  growStorageBy() is responsible for ensuring
- * this.
- */
-template <typename T>
-static bool CapacityHasExcessSpace(size_t cap)
-{
-    size_t size = cap * sizeof(T);
-    return mozilla::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 <class T, size_t N, class AP, bool IsPod>
-struct VectorImpl
+class Vector
+  : public mozilla::VectorBase<T,
+                               MinInlineCapacity,
+                               AllocPolicy,
+                               Vector<T, MinInlineCapacity, AllocPolicy> >
 {
-    /* Destroys constructed objects in the range [begin, end). */
-    static inline void destroy(T *begin, T *end) {
-        for (T *p = begin; p != end; ++p)
-            p->~T();
-    }
-
-    /* Constructs objects in the uninitialized range [begin, end). */
-    static inline void initialize(T *begin, T *end) {
-        for (T *p = begin; p != end; ++p)
-            new(p) T();
-    }
-
-    /*
-     * Copy-constructs objects in the uninitialized range
-     * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
-     */
-    template <class U>
-    static inline void copyConstruct(T *dst, const U *srcbeg, const U *srcend) {
-        for (const U *p = srcbeg; p != srcend; ++p, ++dst)
-            new(dst) T(*p);
-    }
-
-    /*
-     * Move-constructs objects in the uninitialized range
-     * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
-     */
-    template <class U>
-    static inline void moveConstruct(T *dst, const U *srcbeg, const U *srcend) {
-        for (const U *p = srcbeg; p != srcend; ++p, ++dst)
-            new(dst) T(mozilla::Move(*p));
-    }
-
-    /*
-     * Copy-constructs objects in the uninitialized range [dst, dst+n) from the
-     * same object u.
-     */
-    template <class U>
-    static inline void copyConstructN(T *dst, size_t n, const U &u) {
-        for (T *end = dst + n; dst != end; ++dst)
-            new(dst) T(u);
-    }
+    typedef typename mozilla::VectorBase<T, MinInlineCapacity, AllocPolicy, Vector> Base;
 
-    /*
-     * Grows the given buffer to have capacity newCap, preserving the objects
-     * constructed in the range [begin, end) and updating v. Assumes that (1)
-     * newCap has not overflowed, and (2) multiplying newCap by sizeof(T) will
-     * not overflow.
-     */
-    static inline bool growTo(Vector<T,N,AP> &v, size_t newCap) {
-        MOZ_ASSERT(!v.usingInlineStorage());
-        MOZ_ASSERT(!CapacityHasExcessSpace<T>(newCap));
-        T *newbuf = reinterpret_cast<T *>(v.malloc_(newCap * sizeof(T)));
-        if (!newbuf)
-            return false;
-        for (T *dst = newbuf, *src = v.beginNoCheck(); src != v.endNoCheck(); ++dst, ++src)
-            new(dst) T(mozilla::Move(*src));
-        VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck());
-        v.free_(v.mBegin);
-        v.mBegin = newbuf;
-        /* v.mLength is unchanged. */
-        v.mCapacity = newCap;
-        return true;
-    }
-};
-
-/*
- * 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 <class T, size_t N, class AP>
-struct VectorImpl<T, N, AP, true>
-{
-    static inline void destroy(T *, T *) {}
-
-    static inline void initialize(T *begin, T *end) {
-        /*
-         * You would think that memset would be a big win (or even break even)
-         * when we know T is a POD. But currently it's not. This is probably
-         * because |append| tends to be given small ranges and memset requires
-         * a function call that doesn't get inlined.
-         *
-         * memset(begin, 0, sizeof(T) * (end-begin));
-         */
-        for (T *p = begin; p != end; ++p)
-            new(p) T();
-    }
-
-    template <class U>
-    static inline void copyConstruct(T *dst, const U *srcbeg, const U *srcend) {
-        /*
-         * See above memset comment. Also, notice that copyConstruct is
-         * currently templated (T != U), so memcpy won't work without
-         * requiring T == U.
-         *
-         * memcpy(dst, srcbeg, sizeof(T) * (srcend - srcbeg));
-         */
-        for (const U *p = srcbeg; p != srcend; ++p, ++dst)
-            *dst = *p;
-    }
-
-    template <class U>
-    static inline void moveConstruct(T *dst, const U *srcbeg, const U *srcend) {
-        copyConstruct(dst, srcbeg, srcend);
-    }
-
-    static inline void copyConstructN(T *dst, size_t n, const T &t) {
-        for (T *p = dst, *end = dst + n; p != end; ++p)
-            *p = t;
-    }
-
-    static inline bool growTo(Vector<T,N,AP> &v, size_t newCap) {
-        MOZ_ASSERT(!v.usingInlineStorage());
-        MOZ_ASSERT(!CapacityHasExcessSpace<T>(newCap));
-        size_t oldSize = sizeof(T) * v.mCapacity;
-        size_t newSize = sizeof(T) * newCap;
-        T *newbuf = reinterpret_cast<T *>(v.realloc_(v.mBegin, oldSize, newSize));
-        if (!newbuf)
-            return false;
-        v.mBegin = newbuf;
-        /* v.mLength is unchanged. */
-        v.mCapacity = newCap;
-        return true;
+  public:
+    Vector(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
+    Vector(mozilla::MoveRef<Vector> vec) : Base(vec) {}
+    Vector &operator=(mozilla::MoveRef<Vector> vec) {
+        return Base::operator=(vec);
     }
 };
 
-/*
- * JS-friendly, 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 jsalloc.h (default js::TempAllocPolicy)
- *
- * N.B: Vector is not reentrant: T member functions called during Vector member
- *      functions must not call back into the same object.
- */
-template <class T, size_t N, class AllocPolicy>
-class Vector : private AllocPolicy
-{
-    // typedef typename tl::StaticAssert<!tl::IsPostBarrieredType<T>::result>::result _;
-
-    /* utilities */
-
-    static const bool sElemIsPod = mozilla::IsPod<T>::value;
-    typedef VectorImpl<T, N, AllocPolicy, sElemIsPod> Impl;
-    friend struct VectorImpl<T, N, AllocPolicy, sElemIsPod>;
-
-    bool growStorageBy(size_t incr);
-    bool convertToHeapStorage(size_t newCap);
-
-    /* magic constants */
-
-    static const int sMaxInlineBytes = 1024;
-
-    /* compute constants */
-
-    /*
-     * Consider element size to be 1 for buffer sizing if there are
-     * 0 inline elements. This allows us to compile when the definition
-     * of the element type is not visible here.
-     *
-     * Explicit specialization is only allowed at namespace scope, so
-     * in order to keep everything here, we use a dummy template
-     * parameter with partial specialization.
-     */
-    template <int M, int Dummy>
-    struct ElemSize {
-        static const size_t value = sizeof(T);
-    };
-    template <int Dummy>
-    struct ElemSize<0, Dummy> {
-        static const size_t value = 1;
-    };
-
-    static const size_t sInlineCapacity =
-        mozilla::tl::Min<N, sMaxInlineBytes / ElemSize<N, 0>::value>::value;
-
-    /* Calculate inline buffer size; avoid 0-sized array. */
-    static const size_t sInlineBytes =
-        mozilla::tl::Max<1, sInlineCapacity * ElemSize<N, 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
-     * previously allocated by a call to reserve().
-     */
-    T *mBegin;
-    size_t mLength;     /* Number of elements in the Vector. */
-    size_t mCapacity;   /* Max number of elements storable in the Vector without resizing. */
-#ifdef DEBUG
-    size_t mReserved;   /* Max elements of reserved or used space in this vector. */
-#endif
-
-    mozilla::AlignedStorage<sInlineBytes> storage;
-
-#ifdef DEBUG
-    friend class mozilla::ReentrancyGuard;
-    bool entered;
-#endif
-
-    Vector(const Vector &) MOZ_DELETE;
-    Vector &operator=(const Vector &) MOZ_DELETE;
-
-    /* private accessors */
-
-    bool usingInlineStorage() const {
-        return mBegin == inlineStorage();
-    }
-
-    T *inlineStorage() const {
-        return (T *)storage.addr();
-    }
-
-    T *beginNoCheck() const {
-        return mBegin;
-    }
-
-    T *endNoCheck() {
-        return mBegin + mLength;
-    }
-
-    const T *endNoCheck() const {
-        return mBegin + mLength;
-    }
-
-#ifdef DEBUG
-    size_t reserved() const {
-        MOZ_ASSERT(mReserved <= mCapacity);
-        MOZ_ASSERT(mLength <= mReserved);
-        return mReserved;
-    }
-#endif
-
-    /* Append operations guaranteed to succeed due to pre-reserved space. */
-    template <class U> void internalAppend(U u);
-    void internalAppendN(const T &t, size_t n);
-    template <class U> void internalAppend(const U *begin, size_t length);
-    template <class U, size_t O, class BP> void internalAppend(const Vector<U,O,BP> &other);
-
-  public:
-    static const size_t sMaxInlineStorage = N;
-
-    typedef T ElementType;
-
-    Vector(AllocPolicy = AllocPolicy());
-    Vector(mozilla::MoveRef<Vector>); /* Move constructor. */
-    Vector &operator=(mozilla::MoveRef<Vector>); /* Move assignment. */
-    ~Vector();
-
-    /* accessors */
-
-    const AllocPolicy &allocPolicy() const {
-        return *this;
-    }
-
-    AllocPolicy &allocPolicy() {
-        return *this;
-    }
-
-    enum { InlineLength = N };
-
-    size_t length() const {
-        return mLength;
-    }
-
-    bool empty() const {
-        return mLength == 0;
-    }
-
-    size_t capacity() const {
-        return mCapacity;
-    }
-
-    T *begin() {
-        MOZ_ASSERT(!entered);
-        return mBegin;
-    }
-
-    const T *begin() const {
-        MOZ_ASSERT(!entered);
-        return mBegin;
-    }
-
-    T *end() {
-        MOZ_ASSERT(!entered);
-        return mBegin + mLength;
-    }
-
-    const T *end() const {
-        MOZ_ASSERT(!entered);
-        return mBegin + mLength;
-    }
-
-    T &operator[](size_t i) {
-        MOZ_ASSERT(!entered);
-        MOZ_ASSERT(i < mLength);
-        return begin()[i];
-    }
-
-    const T &operator[](size_t i) const {
-        MOZ_ASSERT(!entered);
-        MOZ_ASSERT(i < mLength);
-        return begin()[i];
-    }
-
-    T &back() {
-        MOZ_ASSERT(!entered);
-        MOZ_ASSERT(!empty());
-        return *(end() - 1);
-    }
-
-    const T &back() const {
-        MOZ_ASSERT(!entered);
-        MOZ_ASSERT(!empty());
-        return *(end() - 1);
-    }
-
-    class Range {
-        friend class Vector;
-        T *cur_, *end_;
-        Range(T *cur, T *end) : cur_(cur), end_(end) {}
-      public:
-        Range() {}
-        bool empty() const { return cur_ == end_; }
-        size_t remain() const { return end_ - cur_; }
-        T &front() const { return *cur_; }
-        void popFront() { MOZ_ASSERT(!empty()); ++cur_; }
-        T popCopyFront() { MOZ_ASSERT(!empty()); return *cur_++; }
-    };
-
-    Range all() {
-        return Range(begin(), end());
-    }
-
-    /* mutators */
-
-    /* Given that the Vector is empty and has no inline storage, grow to |capacity|. */
-    bool initCapacity(size_t request);
-
-    /* If reserve(length() + N) succeeds, the N next appends are guaranteed to succeed. */
-    bool reserve(size_t request);
-
-    /*
-     * Destroy elements in the range [end() - incr, end()). Does not deallocate
-     * or unreserve storage for those elements.
-     */
-    void shrinkBy(size_t incr);
-
-    /* Grow the vector by incr elements. */
-    bool growBy(size_t incr);
-
-    /* Call shrinkBy or growBy based on whether newSize > length(). */
-    bool resize(size_t newLength);
-
-    /* Leave new elements as uninitialized memory. */
-    bool growByUninitialized(size_t incr);
-    bool resizeUninitialized(size_t newLength);
-
-    /* Shorthand for shrinkBy(length()). */
-    void clear();
-
-    /* Clears and releases any heap-allocated storage. */
-    void clearAndFree();
-
-    /* If true, appending |needed| elements will not call realloc(). */
-    bool canAppendWithoutRealloc(size_t needed) const;
-
-    /*
-     * Potentially fallible append operations.
-     *
-     * The function templates that take an unspecified type U require a
-     * const T & or a MoveRef<T>. The MoveRef<T> variants move their
-     * operands into the vector, instead of copying them. If they fail, the
-     * operand is left unmoved.
-     */
-    template <class U> bool append(U t);
-    bool appendN(const T &t, size_t n);
-    template <class U> bool append(const U *begin, const U *end);
-    template <class U> bool append(const U *begin, size_t length);
-    template <class U, size_t O, class BP> bool append(const Vector<U,O,BP> &other);
-
-    /*
-     * Guaranteed-infallible append operations for use upon vectors whose
-     * memory has been pre-reserved.
-     */
-    template <class U> void infallibleAppend(const U &u) {
-        internalAppend(u);
-    }
-    void infallibleAppendN(const T &t, size_t n) {
-        internalAppendN(t, n);
-    }
-    template <class U> void infallibleAppend(const U *aBegin, const U *aEnd) {
-        internalAppend(aBegin, mozilla::PointerRangeSize(aBegin, aEnd));
-    }
-    template <class U> void infallibleAppend(const U *aBegin, size_t aLength) {
-        internalAppend(aBegin, aLength);
-    }
-    template <class U, size_t O, class BP> void infallibleAppend(const Vector<U,O,BP> &other) {
-        internalAppend(other);
-    }
-
-    void popBack();
-
-    T popCopy();
-
-    /*
-     * Transfers ownership of the internal buffer used by Vector to the caller.
-     * After this call, the Vector is empty. Since the returned buffer may need
-     * to be allocated (if the elements are currently stored in-place), the
-     * call can fail, returning NULL.
-     *
-     * N.B. Although a T*, only the range [0, length()) is constructed.
-     */
-    T *extractRawBuffer();
-
-    /*
-     * Transfer ownership of an array of objects into the Vector.
-     * N.B. This call assumes that there are no uninitialized elements in the
-     *      passed array.
-     */
-    void replaceRawBuffer(T *p, size_t length);
-
-    /*
-     * Places |val| at position |p|, shifting existing elements from |p|
-     * onward one position higher.  On success, |p| should not be reused
-     * because it will be a dangling pointer if reallocation of the vector
-     * storage occurred;  the return value should be used instead.  On failure,
-     * NULL is returned.
-     *
-     * Example usage:
-     *
-     *   if (!(p = vec.insert(p, val)))
-     *       <handle failure>
-     *   <keep working with p>
-     */
-    T *insert(T *p, const T &val);
-
-    /*
-     * Removes the element |t|, which must fall in the bounds [begin, end),
-     * shifting existing elements from |t + 1| onward one position lower.
-     */
-    void erase(T *t);
-
-    /*
-     * Measure the size of the Vector's heap-allocated storage.
-     */
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
-
-    /*
-     * Like sizeOfExcludingThis, but also measures the size of the Vector
-     * object (which must be heap-allocated) itself.
-     */
-    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
-
-    void swap(Vector &other);
-};
-
-/* This does the re-entrancy check plus several other sanity checks. */
-#define REENTRANCY_GUARD_ET_AL \
-    mozilla::ReentrancyGuard g(*this); \
-    MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == sInlineCapacity); \
-    MOZ_ASSERT(reserved() <= mCapacity); \
-    MOZ_ASSERT(mLength <= reserved()); \
-    MOZ_ASSERT(mLength <= mCapacity)
-
-/* Vector Implementation */
-
-template <class T, size_t N, class AllocPolicy>
-MOZ_ALWAYS_INLINE
-Vector<T,N,AllocPolicy>::Vector(AllocPolicy ap)
-  : AllocPolicy(ap), mBegin((T *)storage.addr()), mLength(0),
-    mCapacity(sInlineCapacity)
-#ifdef DEBUG
-  , mReserved(sInlineCapacity), entered(false)
-#endif
-{}
-
-/* Move constructor. */
-template <class T, size_t N, class AllocPolicy>
-MOZ_ALWAYS_INLINE
-Vector<T, N, AllocPolicy>::Vector(mozilla::MoveRef<Vector> rhs)
-    : AllocPolicy(rhs)
-#ifdef DEBUG
-    , entered(false)
-#endif
-{
-    mLength = rhs->mLength;
-    mCapacity = rhs->mCapacity;
-#ifdef DEBUG
-    mReserved = rhs->mReserved;
-#endif
-
-    if (rhs->usingInlineStorage()) {
-        /* We can't move the buffer over in this case, so copy elements. */
-        mBegin = (T *)storage.addr();
-        Impl::moveConstruct(mBegin, rhs->beginNoCheck(), rhs->endNoCheck());
-        /*
-         * Leave rhs's mLength, mBegin, mCapacity, and mReserved as they are.
-         * The elements in its in-line storage still need to be destroyed.
-         */
-    } else {
-        /*
-         * Take src's buffer, and turn src into an empty vector using
-         * in-line storage.
-         */
-        mBegin = rhs->mBegin;
-        rhs->mBegin = (T *) rhs->storage.addr();
-        rhs->mCapacity = sInlineCapacity;
-        rhs->mLength = 0;
-#ifdef DEBUG
-        rhs->mReserved = sInlineCapacity;
-#endif
-    }
-}
-
-/* Move assignment. */
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE
-Vector<T, N, AP> &
-Vector<T, N, AP>::operator=(mozilla::MoveRef<Vector> rhs)
-{
-    this->~Vector();
-    new(this) Vector(rhs);
-    return *this;
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE
-Vector<T,N,AP>::~Vector()
-{
-    REENTRANCY_GUARD_ET_AL;
-    Impl::destroy(beginNoCheck(), endNoCheck());
-    if (!usingInlineStorage())
-        this->free_(beginNoCheck());
-}
-
-/*
- * This function will create a new heap buffer with capacity newCap,
- * move all elements in the inline buffer to this new buffer,
- * and fail on OOM.
- */
-template <class T, size_t N, class AP>
-inline bool
-Vector<T,N,AP>::convertToHeapStorage(size_t newCap)
-{
-    MOZ_ASSERT(usingInlineStorage());
-
-    /* Allocate buffer. */
-    MOZ_ASSERT(!CapacityHasExcessSpace<T>(newCap));
-    T *newBuf = reinterpret_cast<T *>(this->malloc_(newCap * sizeof(T)));
-    if (!newBuf)
-        return false;
-
-    /* Copy inline elements into heap buffer. */
-    Impl::moveConstruct(newBuf, beginNoCheck(), endNoCheck());
-    Impl::destroy(beginNoCheck(), endNoCheck());
-
-    /* Switch in heap buffer. */
-    mBegin = newBuf;
-    /* mLength is unchanged. */
-    mCapacity = newCap;
-    return true;
-}
-
-template <class T, size_t N, class AP>
-MOZ_NEVER_INLINE bool
-Vector<T,N,AP>::growStorageBy(size_t incr)
-{
-    MOZ_ASSERT(mLength + incr > mCapacity);
-    MOZ_ASSERT_IF(!usingInlineStorage(), !CapacityHasExcessSpace<T>(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
-     * result in a non-2^N request size.
-     */
-
-    size_t newCap;
-
-    if (incr == 1) {
-        if (usingInlineStorage()) {
-            /* This case occurs in ~70--80% of the calls to this function. */
-            size_t newSize = mozilla::tl::RoundUpPow2<(sInlineCapacity + 1) * sizeof(T)>::value;
-            newCap = newSize / sizeof(T);
-            goto convert;
-        }
-
-        if (mLength == 0) {
-            /* This case occurs in ~0--10% of the calls to this function. */
-            newCap = 1;
-            goto grow;
-        }
-
-        /* This case occurs in ~15--20% of the calls to this function. */
-
-        /*
-         * Will mLength*4*sizeof(T) overflow?  This condition limits a Vector
-         * to 1GB of memory on a 32-bit system, which is a reasonable limit.
-         * It also ensures that the ((char *)end() - (char *)begin()) does not
-         * overflow ptrdiff_t (see Bug 510319).
-         */
-        if (mLength & mozilla::tl::MulOverflowMask<4 * sizeof(T)>::value) {
-            this->reportAllocOverflow();
-            return false;
-        }
-
-        /*
-         * If we reach here, the existing capacity will have a size that is
-         * already as close to 2^N as sizeof(T) will allow.  Just double the
-         * capacity, and then there might be space for one more element.
-         */
-        newCap = mLength * 2;
-        if (CapacityHasExcessSpace<T>(newCap))
-            newCap += 1;
-
-    } else {
-        /* This case occurs in ~2% of the calls to this function. */
-        size_t newMinCap = mLength + incr;
-
-        /* Did mLength+incr overflow?  Will newCap*sizeof(T) overflow? */
-        if (newMinCap < mLength ||
-            newMinCap & mozilla::tl::MulOverflowMask<2 * sizeof(T)>::value)
-        {
-            this->reportAllocOverflow();
-            return false;
-        }
-
-        size_t newMinSize = newMinCap * sizeof(T);
-        size_t newSize = mozilla::RoundUpPow2(newMinSize);
-        newCap = newSize / sizeof(T);
-    }
-
-    if (usingInlineStorage()) {
-      convert:
-        return convertToHeapStorage(newCap);
-    }
-
-  grow:
-    return Impl::growTo(*this, newCap);
-}
-
-template <class T, size_t N, class AP>
-inline bool
-Vector<T,N,AP>::initCapacity(size_t request)
-{
-    MOZ_ASSERT(empty());
-    MOZ_ASSERT(usingInlineStorage());
-    if (request == 0)
-        return true;
-    T *newbuf = reinterpret_cast<T *>(this->malloc_(request * sizeof(T)));
-    if (!newbuf)
-        return false;
-    mBegin = newbuf;
-    mCapacity = request;
-#ifdef DEBUG
-    mReserved = request;
-#endif
-    return true;
-}
-
-template <class T, size_t N, class AP>
-inline bool
-Vector<T,N,AP>::reserve(size_t request)
-{
-    REENTRANCY_GUARD_ET_AL;
-    if (request > mCapacity && !growStorageBy(request - mLength))
-        return false;
-
-#ifdef DEBUG
-    if (request > mReserved)
-        mReserved = request;
-    MOZ_ASSERT(mLength <= mReserved);
-    MOZ_ASSERT(mReserved <= mCapacity);
-#endif
-    return true;
-}
-
-template <class T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::shrinkBy(size_t incr)
-{
-    REENTRANCY_GUARD_ET_AL;
-    MOZ_ASSERT(incr <= mLength);
-    Impl::destroy(endNoCheck() - incr, endNoCheck());
-    mLength -= incr;
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::growBy(size_t incr)
-{
-    REENTRANCY_GUARD_ET_AL;
-    if (incr > mCapacity - mLength && !growStorageBy(incr))
-        return false;
-
-    MOZ_ASSERT(mLength + incr <= mCapacity);
-    T *newend = endNoCheck() + incr;
-    Impl::initialize(endNoCheck(), newend);
-    mLength += incr;
-#ifdef DEBUG
-    if (mLength > mReserved)
-        mReserved = mLength;
-#endif
-    return true;
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::growByUninitialized(size_t incr)
-{
-    REENTRANCY_GUARD_ET_AL;
-    if (incr > mCapacity - mLength && !growStorageBy(incr))
-        return false;
-
-    MOZ_ASSERT(mLength + incr <= mCapacity);
-    mLength += incr;
-#ifdef DEBUG
-    if (mLength > mReserved)
-        mReserved = mLength;
-#endif
-    return true;
-}
-
-template <class T, size_t N, class AP>
-inline bool
-Vector<T,N,AP>::resize(size_t newLength)
-{
-    size_t curLength = mLength;
-    if (newLength > curLength)
-        return growBy(newLength - curLength);
-    shrinkBy(curLength - newLength);
-    return true;
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::resizeUninitialized(size_t newLength)
-{
-    size_t curLength = mLength;
-    if (newLength > curLength)
-        return growByUninitialized(newLength - curLength);
-    shrinkBy(curLength - newLength);
-    return true;
-}
-
-template <class T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::clear()
-{
-    REENTRANCY_GUARD_ET_AL;
-    Impl::destroy(beginNoCheck(), endNoCheck());
-    mLength = 0;
-}
-
-template <class T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::clearAndFree()
-{
-    clear();
-
-    if (usingInlineStorage())
-        return;
-
-    this->free_(beginNoCheck());
-    mBegin = (T *)storage.addr();
-    mCapacity = sInlineCapacity;
-#ifdef DEBUG
-    mReserved = sInlineCapacity;
-#endif
-}
-
-template <class T, size_t N, class AP>
-inline bool
-Vector<T,N,AP>::canAppendWithoutRealloc(size_t needed) const
-{
-    return mLength + needed <= mCapacity;
-}
-
-template <class T, size_t N, class AP>
-template <class U>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::append(U t)
-{
-    REENTRANCY_GUARD_ET_AL;
-    if (mLength == mCapacity && !growStorageBy(1))
-        return false;
-
-#ifdef DEBUG
-    if (mLength + 1 > mReserved)
-        mReserved = mLength + 1;
-#endif
-    internalAppend(t);
-    return true;
-}
-
-template <class T, size_t N, class AP>
-template <class U>
-MOZ_ALWAYS_INLINE void
-Vector<T,N,AP>::internalAppend(U u)
-{
-    MOZ_ASSERT(mLength + 1 <= mReserved);
-    MOZ_ASSERT(mReserved <= mCapacity);
-    new(endNoCheck()) T(u);
-    ++mLength;
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::appendN(const T &t, size_t needed)
-{
-    REENTRANCY_GUARD_ET_AL;
-    if (mLength + needed > mCapacity && !growStorageBy(needed))
-        return false;
-
-#ifdef DEBUG
-    if (mLength + needed > mReserved)
-        mReserved = mLength + needed;
-#endif
-    internalAppendN(t, needed);
-    return true;
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE void
-Vector<T,N,AP>::internalAppendN(const T &t, size_t needed)
-{
-    MOZ_ASSERT(mLength + needed <= mReserved);
-    MOZ_ASSERT(mReserved <= mCapacity);
-    Impl::copyConstructN(endNoCheck(), needed, t);
-    mLength += needed;
-}
-
-template <class T, size_t N, class AP>
-inline T *
-Vector<T,N,AP>::insert(T *p, const T &val)
-{
-    MOZ_ASSERT(begin() <= p);
-    MOZ_ASSERT(p <= end());
-    size_t pos = p - begin();
-    MOZ_ASSERT(pos <= mLength);
-    size_t oldLength = mLength;
-    if (pos == oldLength) {
-        if (!append(val))
-            return NULL;
-    } else {
-        T oldBack = back();
-        if (!append(oldBack)) /* Dup the last element. */
-            return NULL;
-        for (size_t i = oldLength; i > pos; --i)
-            (*this)[i] = (*this)[i - 1];
-        (*this)[pos] = val;
-    }
-    return begin() + pos;
-}
-
-template<typename T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::erase(T *it)
-{
-    MOZ_ASSERT(begin() <= it);
-    MOZ_ASSERT(it < end());
-    while (it + 1 != end()) {
-        *it = *(it + 1);
-        ++it;
-    }
-    popBack();
-}
-
-template <class T, size_t N, class AP>
-template <class U>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::append(const U *insBegin, const U *insEnd)
-{
-    REENTRANCY_GUARD_ET_AL;
-    size_t needed = mozilla::PointerRangeSize(insBegin, insEnd);
-    if (mLength + needed > mCapacity && !growStorageBy(needed))
-        return false;
-
-#ifdef DEBUG
-    if (mLength + needed > mReserved)
-        mReserved = mLength + needed;
-#endif
-    internalAppend(insBegin, needed);
-    return true;
-}
-
-template <class T, size_t N, class AP>
-template <class U>
-MOZ_ALWAYS_INLINE void
-Vector<T,N,AP>::internalAppend(const U *insBegin, size_t insLength)
-{
-    MOZ_ASSERT(mLength + insLength <= mReserved);
-    MOZ_ASSERT(mReserved <= mCapacity);
-    Impl::copyConstruct(endNoCheck(), insBegin, insBegin + insLength);
-    mLength += insLength;
-}
-
-template <class T, size_t N, class AP>
-template <class U, size_t O, class BP>
-inline bool
-Vector<T,N,AP>::append(const Vector<U,O,BP> &other)
-{
-    return append(other.begin(), other.end());
-}
-
-template <class T, size_t N, class AP>
-template <class U, size_t O, class BP>
-inline void
-Vector<T,N,AP>::internalAppend(const Vector<U,O,BP> &other)
-{
-    internalAppend(other.begin(), other.length());
-}
-
-template <class T, size_t N, class AP>
-template <class U>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::append(const U *insBegin, size_t insLength)
-{
-    return this->append(insBegin, insBegin + insLength);
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE void
-Vector<T,N,AP>::popBack()
-{
-    REENTRANCY_GUARD_ET_AL;
-    MOZ_ASSERT(!empty());
-    --mLength;
-    endNoCheck()->~T();
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE T
-Vector<T,N,AP>::popCopy()
-{
-    T ret = back();
-    popBack();
-    return ret;
-}
-
-template <class T, size_t N, class AP>
-inline T *
-Vector<T,N,AP>::extractRawBuffer()
-{
-    T *ret;
-    if (usingInlineStorage()) {
-        ret = reinterpret_cast<T *>(this->malloc_(mLength * sizeof(T)));
-        if (!ret)
-            return NULL;
-        Impl::copyConstruct(ret, beginNoCheck(), endNoCheck());
-        Impl::destroy(beginNoCheck(), endNoCheck());
-        /* mBegin, mCapacity are unchanged. */
-        mLength = 0;
-    } else {
-        ret = mBegin;
-        mBegin = (T *)storage.addr();
-        mLength = 0;
-        mCapacity = sInlineCapacity;
-#ifdef DEBUG
-        mReserved = sInlineCapacity;
-#endif
-    }
-    return ret;
-}
-
-template <class T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::replaceRawBuffer(T *p, size_t aLength)
-{
-    REENTRANCY_GUARD_ET_AL;
-
-    /* Destroy what we have. */
-    Impl::destroy(beginNoCheck(), endNoCheck());
-    if (!usingInlineStorage())
-        this->free_(beginNoCheck());
-
-    /* Take in the new buffer. */
-    if (aLength <= sInlineCapacity) {
-        /*
-         * We convert to inline storage if possible, even though p might
-         * otherwise be acceptable.  Maybe this behaviour should be
-         * specifiable with an argument to this function.
-         */
-        mBegin = (T *)storage.addr();
-        mLength = aLength;
-        mCapacity = sInlineCapacity;
-        Impl::moveConstruct(mBegin, p, p + aLength);
-        Impl::destroy(p, p + aLength);
-        this->free_(p);
-    } else {
-        mBegin = p;
-        mLength = aLength;
-        mCapacity = aLength;
-    }
-#ifdef DEBUG
-    mReserved = aLength;
-#endif
-}
-
-template <class T, size_t N, class AP>
-inline size_t
-Vector<T,N,AP>::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
-{
-    return usingInlineStorage() ? 0 : mallocSizeOf(beginNoCheck());
-}
-
-template <class T, size_t N, class AP>
-inline size_t
-Vector<T,N,AP>::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
-{
-    return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
-}
-
-template <class T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::swap(Vector &other)
-{
-    MOZ_STATIC_ASSERT(N == 0,
-                      "still need to implement this for N != 0");
-
-    // This only works when inline storage is always empty.
-    if (!usingInlineStorage() && other.usingInlineStorage()) {
-        other.mBegin = mBegin;
-        mBegin = inlineStorage();
-    } else if (usingInlineStorage() && !other.usingInlineStorage()) {
-        mBegin = other.mBegin;
-        other.mBegin = other.inlineStorage();
-    } else if (!usingInlineStorage() && !other.usingInlineStorage()) {
-        mozilla::Swap(mBegin, other.mBegin);
-    } else {
-        // This case is a no-op, since we'd set both to use their inline storage.
-    }
-
-    mozilla::Swap(mLength, other.mLength);
-    mozilla::Swap(mCapacity, other.mCapacity);
-#ifdef DEBUG
-    mozilla::Swap(mReserved, other.mReserved);
-#endif
-}
-
-}  /* namespace js */
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
+} // namespace js
 
 #endif /* js_Vector_h */
--- a/js/src/assembler/assembler/AbstractMacroAssembler.h
+++ b/js/src/assembler/assembler/AbstractMacroAssembler.h
@@ -433,17 +433,17 @@ public:
 
     public:
         typedef js::Vector<Jump, 16 ,js::SystemAllocPolicy > JumpVector;
 
         JumpList() {}
 
         JumpList(const JumpList &other)
         {
-            m_jumps.append(other.m_jumps);
+            m_jumps.appendAll(other.m_jumps);
         }
 
         JumpList &operator=(const JumpList &other)
         {
             m_jumps.clear();
             m_jumps.append(other.m_jumps);
             return *this;
         }
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -148,17 +148,19 @@ TokenStream::SourceCoords::add(uint32_t 
 
     if (lineIndex == sentinelIndex) {
         // We haven't seen this newline before.  Update lineStartOffsets_.
         // We ignore any failures due to OOM -- because we always have a
         // sentinel node, it'll just be like the newline wasn't present.  I.e.
         // the line numbers will be wrong, but the code won't crash or anything
         // like that.
         lineStartOffsets_[lineIndex] = lineStartOffset;
-        (void)lineStartOffsets_.append(MAX_PTR);
+
+        uint32_t maxPtr = MAX_PTR;
+        (void)lineStartOffsets_.append(maxPtr);
 
     } else {
         // We have seen this newline before (and ungot it).  Do nothing (other
         // than checking it hasn't mysteriously changed).
         JS_ASSERT(lineStartOffsets_[lineIndex] == lineStartOffset);
     }
 }
 
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -159,17 +159,17 @@ CompareRooters(const void *vpA, const vo
  * loop. Since statically, everything is either rooted or it isn't, these scans
  * are almost certain to be worthless. Detect these cases by checking whether
  * the addresses of the top several rooters in the stack are recurring. Note
  * that there may be more than one CheckRoots call within the loop, so we may
  * alternate between a couple of stacks rather than just repeating the same one
  * over and over, so we need more than a depth-1 memory.
  */
 static bool
-SuppressCheckRoots(Vector<Rooter, 0, SystemAllocPolicy> &rooters)
+SuppressCheckRoots(js::Vector<Rooter, 0, SystemAllocPolicy> &rooters)
 {
     static const unsigned int NumStackMemories = 6;
     static const size_t StackCheckDepth = 10;
 
     static uint32_t stacks[NumStackMemories];
     static unsigned int numMemories = 0;
     static unsigned int oldestMemory = 0;
 
@@ -203,17 +203,17 @@ SuppressCheckRoots(Vector<Rooter, 0, Sys
     oldestMemory = (oldestMemory + 1) % NumStackMemories;
     if (numMemories < NumStackMemories)
         numMemories++;
 
     return false;
 }
 
 static void
-GatherRooters(Vector<Rooter, 0, SystemAllocPolicy> &rooters,
+GatherRooters(js::Vector<Rooter, 0, SystemAllocPolicy> &rooters,
               Rooted<void*> **thingGCRooters,
               unsigned thingRootKind)
 {
     Rooted<void*> *rooter = thingGCRooters[thingRootKind];
     while (rooter) {
         Rooter r = { rooter, ThingRootKind(thingRootKind) };
         JS_ALWAYS_TRUE(rooters.append(r));
         rooter = rooter->previous();
@@ -250,17 +250,17 @@ JS::CheckStackRoots(JSContext *cx)
 
     JS_ASSERT(cgcd->hasStackToScan());
     uintptr_t *stackMin, *stackEnd;
     stackMin = cgcd->nativeStackTop + 1;
     stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase);
     JS_ASSERT(stackMin <= stackEnd);
 
     // Gather up all of the rooters
-    Vector<Rooter, 0, SystemAllocPolicy> rooters;
+    js::Vector<Rooter, 0, SystemAllocPolicy> rooters;
     for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
         for (ContextIter cx(rt); !cx.done(); cx.next()) {
             GatherRooters(rooters, cx->thingGCRooters, i);
         }
 
         GatherRooters(rooters, rt->mainThread.thingGCRooters, i);
     }
 
--- a/js/src/ion/AsmJS.cpp
+++ b/js/src/ion/AsmJS.cpp
@@ -620,20 +620,20 @@ class ABIArgIter
     ABIArg *operator->() { JS_ASSERT(!done()); return &gen_.current(); }
     ABIArg &operator*() { JS_ASSERT(!done()); return gen_.current(); }
 
     unsigned index() const { JS_ASSERT(!done()); return i_; }
     MIRType mirType() const { JS_ASSERT(!done()); return ToMIRType(types_[i_]); }
     uint32_t stackBytesConsumedSoFar() const { return gen_.stackBytesConsumedSoFar(); }
 };
 
-typedef Vector<MIRType, 8> MIRTypeVector;
+typedef js::Vector<MIRType, 8> MIRTypeVector;
 typedef ABIArgIter<MIRTypeVector> ABIArgMIRTypeIter;
 
-typedef Vector<VarType, 8> VarTypeVector;
+typedef js::Vector<VarType, 8> VarTypeVector;
 typedef ABIArgIter<VarTypeVector> ABIArgTypeIter;
 
 class Signature
 {
     VarTypeVector argTypes_;
     RetType retType_;
 
   public:
@@ -862,18 +862,18 @@ TypedArrayStoreType(ArrayBufferView::Vie
         return ArrayStore_Doublish;
       default:;
     }
     MOZ_ASSUME_UNREACHABLE("Unexpected array type");
 }
 
 /*****************************************************************************/
 
-typedef Vector<PropertyName*,1> LabelVector;
-typedef Vector<MBasicBlock*,8> BlockVector;
+typedef js::Vector<PropertyName*,1> LabelVector;
+typedef js::Vector<MBasicBlock*,8> BlockVector;
 
 // ModuleCompiler encapsulates the compilation of an entire asm.js module. Over
 // the course of an ModuleCompiler object's lifetime, many FunctionCompiler
 // objects will be created and destroyed in sequence, one for each function in
 // the module.
 //
 // *** asm.js FFI calls ***
 //
@@ -1018,17 +1018,17 @@ class MOZ_STACK_CLASS ModuleCompiler
             return u.mathBuiltin_;
         }
         double constant() const {
             JS_ASSERT(which_ == Constant);
             return u.constant_;
         }
     };
 
-    typedef Vector<const Func*> FuncPtrVector;
+    typedef js::Vector<const Func*> FuncPtrVector;
 
     class FuncPtrTable
     {
         Signature sig_;
         uint32_t mask_;
         uint32_t globalDataOffset_;
         FuncPtrVector elems_;
 
@@ -1046,17 +1046,17 @@ class MOZ_STACK_CLASS ModuleCompiler
         unsigned mask() const { return mask_; }
         unsigned globalDataOffset() const { return globalDataOffset_; }
 
         void initElems(MoveRef<FuncPtrVector> elems) { elems_ = elems; JS_ASSERT(!elems_.empty()); }
         unsigned numElems() const { JS_ASSERT(!elems_.empty()); return elems_.length(); }
         const Func &elem(unsigned i) const { return *elems_[i]; }
     };
 
-    typedef Vector<FuncPtrTable> FuncPtrTableVector;
+    typedef js::Vector<FuncPtrTable> FuncPtrTableVector;
 
     class ExitDescriptor
     {
         PropertyName *name_;
         Signature sig_;
 
       public:
         ExitDescriptor(PropertyName *name, MoveRef<Signature> sig)
@@ -1090,19 +1090,19 @@ class MOZ_STACK_CLASS ModuleCompiler
         PropertyName *name;
         unsigned ms;
         unsigned line;
         unsigned column;
     };
 
     typedef HashMap<PropertyName*, AsmJSMathBuiltin> MathNameMap;
     typedef HashMap<PropertyName*, Global*> GlobalMap;
-    typedef Vector<Func*> FuncVector;
-    typedef Vector<AsmJSGlobalAccess> GlobalAccessVector;
-    typedef Vector<SlowFunction> SlowFunctionVector;
+    typedef js::Vector<Func*> FuncVector;
+    typedef js::Vector<AsmJSGlobalAccess> GlobalAccessVector;
+    typedef js::Vector<SlowFunction> SlowFunctionVector;
 
     JSContext *                    cx_;
     AsmJSParser &                  parser_;
 
     MacroAssembler                 masm_;
 
     ScopedJSDeletePtr<AsmJSModule> module_;
     LifoAlloc                      moduleLifo_;
@@ -1433,17 +1433,17 @@ class MOZ_STACK_CLASS ModuleCompiler
     bool collectAccesses(MIRGenerator &gen) {
 #ifdef JS_CPU_ARM
         if (!module_->addBoundsChecks(gen.asmBoundsChecks()))
             return false;
 #else
         if (!module_->addHeapAccesses(gen.heapAccesses()))
             return false;
 #endif
-        if (!globalAccesses_.append(gen.globalAccesses()))
+        if (!globalAccesses_.appendAll(gen.globalAccesses()))
             return false;
         return true;
     }
 
 #ifdef MOZ_VTUNE
     bool trackProfiledFunction(const Func &func, unsigned endCodeOffset) {
         unsigned startCodeOffset = func.code()->offset();
         return module_->trackProfiledFunction(func.name(), startCodeOffset, endCodeOffset);
@@ -1624,20 +1624,20 @@ class FunctionCompiler
     {
         VarType type;
         unsigned slot;
         Local(VarType t, unsigned slot) : type(t), slot(slot) {}
     };
 
   private:
     typedef HashMap<PropertyName*, Local> LocalMap;
-    typedef Vector<Value> VarInitializerVector;
+    typedef js::Vector<Value> VarInitializerVector;
     typedef HashMap<PropertyName*, BlockVector> LabeledBlockMap;
     typedef HashMap<ParseNode*, BlockVector> UnlabeledBlockMap;
-    typedef Vector<ParseNode*, 4> NodeStack;
+    typedef js::Vector<ParseNode*, 4> NodeStack;
 
     ModuleCompiler &       m_;
     LifoAlloc &            lifo_;
     ParseNode *            fn_;
 
     LocalMap               locals_;
     VarInitializerVector   varInitializers_;
     Maybe<RetType>         alreadyReturned_;
@@ -1971,17 +1971,17 @@ class FunctionCompiler
     class Call
     {
         ABIArgGenerator abi_;
         uint32_t prevMaxStackBytes_;
         uint32_t maxChildStackBytes_;
         uint32_t spIncrement_;
         Signature sig_;
         MAsmJSCall::Args regArgs_;
-        Vector<MAsmJSPassStackArg*> stackArgs_;
+        js::Vector<MAsmJSPassStackArg*> stackArgs_;
         bool childClobbers_;
 
         friend class FunctionCompiler;
 
       public:
         Call(FunctionCompiler &f, RetType retType)
           : prevMaxStackBytes_(0),
             maxChildStackBytes_(0),
@@ -4870,21 +4870,21 @@ CheckFunctionsSequential(ModuleCompiler 
     return true;
 }
 
 #ifdef JS_PARALLEL_COMPILATION
 // State of compilation as tracked and updated by the main thread.
 struct ParallelGroupState
 {
     WorkerThreadState &state;
-    Vector<AsmJSParallelTask> &tasks;
+    js::Vector<AsmJSParallelTask> &tasks;
     int32_t outstandingJobs; // Good work, jobs!
     uint32_t compiledJobs;
 
-    ParallelGroupState(WorkerThreadState &state, Vector<AsmJSParallelTask> &tasks)
+    ParallelGroupState(WorkerThreadState &state, js::Vector<AsmJSParallelTask> &tasks)
       : state(state), tasks(tasks), outstandingJobs(0), compiledJobs(0)
     { }
 };
 
 // Block until a worker-assigned LifoAlloc becomes finished.
 static AsmJSParallelTask *
 GetFinishedCompilation(ModuleCompiler &m, ParallelGroupState &group)
 {
@@ -5034,17 +5034,17 @@ static bool
 CheckFunctionsParallel(ModuleCompiler &m)
 {
     // Saturate all worker threads plus the main thread.
     WorkerThreadState &state = *m.cx()->runtime()->workerThreadState;
     size_t numParallelJobs = state.numThreads + 1;
 
     // Allocate scoped AsmJSParallelTask objects. Each contains a unique
     // LifoAlloc that provides all necessary memory for compilation.
-    Vector<AsmJSParallelTask, 0> tasks(m.cx());
+    js::Vector<AsmJSParallelTask, 0> tasks(m.cx());
     if (!tasks.initCapacity(numParallelJobs))
         return false;
 
     for (size_t i = 0; i < numParallelJobs; i++)
         tasks.infallibleAppend(LIFO_ALLOC_PARALLEL_CHUNK_SIZE);
 
     // With compilation memory in-scope, dispatch worker threads.
     ParallelGroupState group(state, tasks);
--- a/js/src/ion/AsmJSModule.h
+++ b/js/src/ion/AsmJSModule.h
@@ -661,30 +661,30 @@ class AsmJSModule
         return functionBytes_;
     }
     bool containsPC(void *pc) const {
         uint8_t *code = functionCode();
         return pc >= code && pc < (code + functionBytes());
     }
 
     bool addHeapAccesses(const ion::AsmJSHeapAccessVector &accesses) {
-        return heapAccesses_.append(accesses);
+        return heapAccesses_.appendAll(accesses);
     }
     unsigned numHeapAccesses() const {
         return heapAccesses_.length();
     }
     ion::AsmJSHeapAccess &heapAccess(unsigned i) {
         return heapAccesses_[i];
     }
     const ion::AsmJSHeapAccess &heapAccess(unsigned i) const {
         return heapAccesses_[i];
     }
 #if defined(JS_CPU_ARM)
     bool addBoundsChecks(const ion::AsmJSBoundsCheckVector &checks) {
-        return boundsChecks_.append(checks);
+        return boundsChecks_.appendAll(checks);
     }
     void convertBoundsChecksToActualOffset(ion::MacroAssembler &masm) {
         for (unsigned i = 0; i < boundsChecks_.length(); i++)
             boundsChecks_[i].setOffset(masm.actualOffset(boundsChecks_[i].offset()));
     }
 
     void patchBoundsChecks(unsigned heapSize) {
         if (heapSize == 0)
--- a/js/src/ion/IonAnalysis.h
+++ b/js/src/ion/IonAnalysis.h
@@ -100,17 +100,17 @@ class LinearSum
     LinearSum()
       : constant_(0)
     {
     }
 
     LinearSum(const LinearSum &other)
       : constant_(other.constant_)
     {
-        terms_.append(other.terms_);
+        terms_.appendAll(other.terms_);
     }
 
     bool multiply(int32_t scale);
     bool add(const LinearSum &other);
     bool add(MDefinition *term, int32_t scale);
     bool add(int32_t constant);
 
     int32_t constant() const { return constant_; }
--- a/js/src/ion/RegisterAllocator.h
+++ b/js/src/ion/RegisterAllocator.h
@@ -60,28 +60,28 @@ struct AllocationIntegrityState
         Vector<LDefinition, 0, SystemAllocPolicy> temps;
         Vector<LDefinition, 1, SystemAllocPolicy> outputs;
 
         InstructionInfo()
         { }
 
         InstructionInfo(const InstructionInfo &o)
         {
-            inputs.append(o.inputs);
-            temps.append(o.temps);
-            outputs.append(o.outputs);
+            inputs.appendAll(o.inputs);
+            temps.appendAll(o.temps);
+            outputs.appendAll(o.outputs);
         }
     };
     Vector<InstructionInfo, 0, SystemAllocPolicy> instructions;
 
     struct BlockInfo {
         Vector<InstructionInfo, 5, SystemAllocPolicy> phis;
         BlockInfo() {}
         BlockInfo(const BlockInfo &o) {
-            phis.append(o.phis);
+            phis.appendAll(o.phis);
         }
     };
     Vector<BlockInfo, 0, SystemAllocPolicy> blocks;
 
     Vector<LDefinition*, 20, SystemAllocPolicy> virtualRegisters;
 
     // Describes a correspondence that should hold at the end of a block.
     // The value which was written to vreg in the original LIR should be
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -237,18 +237,18 @@ class AutoVectorRooter : protected AutoG
     }
 
     typedef T ElementType;
 
     size_t length() const { return vector.length(); }
     bool empty() const { return vector.empty(); }
 
     bool append(const T &v) { return vector.append(v); }
-    bool append(const AutoVectorRooter<T> &other) {
-        return vector.append(other.vector);
+    bool appendAll(const AutoVectorRooter<T> &other) {
+        return vector.appendAll(other.vector);
     }
 
     bool insert(T *p, const T &val) { return vector.insert(p, val); }
 
     /* For use when space has already been reserved. */
     void infallibleAppend(const T &v) { vector.infallibleAppend(v); }
 
     void popBack() { vector.popBack(); }
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -2412,17 +2412,17 @@ js::AppendUnique(JSContext *cx, AutoIdVe
             if (others[i] == base[j]) {
                 unique = false;
                 break;
             }
         }
         if (unique)
             uniqueOthers.append(others[i]);
     }
-    return base.append(uniqueOthers);
+    return base.appendAll(uniqueOthers);
 }
 
 bool
 Proxy::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
     JS_CHECK_RECURSION(cx, return false);
     BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
     AutoEnterPolicy policy(cx, handler, proxy, JS::JSID_VOIDHANDLE, BaseProxyHandler::GET, true);
--- a/js/src/yarr/wtfbridge.h
+++ b/js/src/yarr/wtfbridge.h
@@ -166,17 +166,17 @@ class Vector {
     template <typename U>
     void append(const U &u) {
         if (!impl.append(static_cast<T>(u)))
             MOZ_CRASH();
     }
 
     template <size_t M>
     void append(const Vector<T,M> &v) {
-        if (!impl.append(v.impl))
+        if (!impl.appendAll(v.impl))
             MOZ_CRASH();
     }
 
     void insert(size_t i, const T& t) {
         if (!impl.insert(&impl[i], t))
             MOZ_CRASH();
     }
 
copy from js/public/Vector.h
copy to mfbt/Vector.h
--- a/js/public/Vector.h
+++ b/mfbt/Vector.h
@@ -1,1115 +1,1188 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
  * 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 js_Vector_h
-#define js_Vector_h
+/* A type/length-parametrized vector class. */
 
+#ifndef mozilla_Vector_h
+#define mozilla_Vector_h
+
+#include "mozilla/AllocPolicy.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
+#include "mozilla/NullPtr.h"
 #include "mozilla/ReentrancyGuard.h"
 #include "mozilla/TemplateLib.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Util.h"
 
 /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4345)
 #endif
 
-namespace js {
-
-class TempAllocPolicy;
+namespace mozilla {
 
-template <class T,
-          size_t MinInlineCapacity = 0,
-          class AllocPolicy = TempAllocPolicy>
-class Vector;
+template<typename T, size_t N, class AllocPolicy, class ThisVector>
+class VectorBase;
+
+namespace detail {
 
 /*
  * Check that the given capacity wastes the minimal amount of space if
  * allocated on the heap.  This means that cap*sizeof(T) is as close to a
  * power-of-two as possible.  growStorageBy() is responsible for ensuring
  * this.
  */
-template <typename T>
+template<typename T>
 static bool CapacityHasExcessSpace(size_t cap)
 {
-    size_t size = cap * sizeof(T);
-    return mozilla::RoundUpPow2(size) - size >= sizeof(T);
+  size_t size = cap * 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 <class T, size_t N, class AP, bool IsPod>
+template<typename T, size_t N, class AP, class ThisVector, bool IsPod>
 struct VectorImpl
 {
     /* Destroys constructed objects in the range [begin, end). */
-    static inline void destroy(T *begin, T *end) {
-        for (T *p = begin; p != end; ++p)
-            p->~T();
+    static inline void destroy(T* begin, T* end) {
+      for (T* p = begin; p < end; ++p)
+        p->~T();
     }
 
     /* Constructs objects in the uninitialized range [begin, end). */
-    static inline void initialize(T *begin, T *end) {
-        for (T *p = begin; p != end; ++p)
-            new(p) T();
+    static inline void initialize(T* begin, T* end) {
+      for (T* p = begin; p < end; ++p)
+        new(p) T();
     }
 
     /*
      * Copy-constructs objects in the uninitialized range
      * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
      */
-    template <class U>
-    static inline void copyConstruct(T *dst, const U *srcbeg, const U *srcend) {
-        for (const U *p = srcbeg; p != srcend; ++p, ++dst)
-            new(dst) T(*p);
+    template<typename U>
+    static inline void copyConstruct(T* dst, const U* srcbeg, const U* srcend) {
+      for (const U* p = srcbeg; p < srcend; ++p, ++dst)
+        new(dst) T(*p);
     }
 
     /*
      * Move-constructs objects in the uninitialized range
      * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
      */
-    template <class U>
-    static inline void moveConstruct(T *dst, const U *srcbeg, const U *srcend) {
-        for (const U *p = srcbeg; p != srcend; ++p, ++dst)
-            new(dst) T(mozilla::Move(*p));
+    template<typename U>
+    static inline void moveConstruct(T* dst, const U* srcbeg, const U* srcend) {
+      for (const U* p = srcbeg; p < srcend; ++p, ++dst)
+        new(dst) T(Move(*p));
     }
 
     /*
      * Copy-constructs objects in the uninitialized range [dst, dst+n) from the
      * same object u.
      */
-    template <class U>
-    static inline void copyConstructN(T *dst, size_t n, const U &u) {
-        for (T *end = dst + n; dst != end; ++dst)
-            new(dst) T(u);
+    template<typename U>
+    static inline void copyConstructN(T* dst, size_t n, const U& u) {
+      for (T* end = dst + n; dst < end; ++dst)
+        new(dst) T(u);
     }
 
     /*
      * Grows the given buffer to have capacity newCap, preserving the objects
      * constructed in the range [begin, end) and updating v. Assumes that (1)
      * newCap has not overflowed, and (2) multiplying newCap by sizeof(T) will
      * not overflow.
      */
-    static inline bool growTo(Vector<T,N,AP> &v, size_t newCap) {
-        MOZ_ASSERT(!v.usingInlineStorage());
-        MOZ_ASSERT(!CapacityHasExcessSpace<T>(newCap));
-        T *newbuf = reinterpret_cast<T *>(v.malloc_(newCap * sizeof(T)));
-        if (!newbuf)
-            return false;
-        for (T *dst = newbuf, *src = v.beginNoCheck(); src != v.endNoCheck(); ++dst, ++src)
-            new(dst) T(mozilla::Move(*src));
-        VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck());
-        v.free_(v.mBegin);
-        v.mBegin = newbuf;
-        /* v.mLength is unchanged. */
-        v.mCapacity = newCap;
-        return true;
+    static inline bool
+    growTo(VectorBase<T, N, AP, ThisVector>& v, size_t newCap) {
+      MOZ_ASSERT(!v.usingInlineStorage());
+      MOZ_ASSERT(!CapacityHasExcessSpace<T>(newCap));
+      T* newbuf = reinterpret_cast<T*>(v.malloc_(newCap * sizeof(T)));
+      if (!newbuf)
+        return false;
+      T* dst = newbuf;
+      T* src = v.beginNoCheck();
+      for (; src < v.endNoCheck(); ++dst, ++src)
+        new(dst) T(Move(*src));
+      VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck());
+      v.free_(v.mBegin);
+      v.mBegin = newbuf;
+      /* v.mLength is unchanged. */
+      v.mCapacity = newCap;
+      return true;
     }
 };
 
 /*
  * 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 <class T, size_t N, class AP>
-struct VectorImpl<T, N, AP, true>
+template<typename T, size_t N, class AP, class ThisVector>
+struct VectorImpl<T, N, AP, ThisVector, true>
 {
-    static inline void destroy(T *, T *) {}
+    static inline void destroy(T*, T*) {}
 
-    static inline void initialize(T *begin, T *end) {
-        /*
-         * You would think that memset would be a big win (or even break even)
-         * when we know T is a POD. But currently it's not. This is probably
-         * because |append| tends to be given small ranges and memset requires
-         * a function call that doesn't get inlined.
-         *
-         * memset(begin, 0, sizeof(T) * (end-begin));
-         */
-        for (T *p = begin; p != end; ++p)
-            new(p) T();
+    static inline void initialize(T* begin, T* end) {
+      /*
+       * You would think that memset would be a big win (or even break even)
+       * when we know T is a POD. But currently it's not. This is probably
+       * because |append| tends to be given small ranges and memset requires
+       * a function call that doesn't get inlined.
+       *
+       * memset(begin, 0, sizeof(T) * (end-begin));
+       */
+      for (T* p = begin; p < end; ++p)
+        new(p) T();
     }
 
-    template <class U>
-    static inline void copyConstruct(T *dst, const U *srcbeg, const U *srcend) {
-        /*
-         * See above memset comment. Also, notice that copyConstruct is
-         * currently templated (T != U), so memcpy won't work without
-         * requiring T == U.
-         *
-         * memcpy(dst, srcbeg, sizeof(T) * (srcend - srcbeg));
-         */
-        for (const U *p = srcbeg; p != srcend; ++p, ++dst)
-            *dst = *p;
+    template<typename U>
+    static inline void copyConstruct(T* dst, const U* srcbeg, const U* srcend) {
+      /*
+       * See above memset comment. Also, notice that copyConstruct is
+       * currently templated (T != U), so memcpy won't work without
+       * requiring T == U.
+       *
+       * memcpy(dst, srcbeg, sizeof(T) * (srcend - srcbeg));
+       */
+      for (const U* p = srcbeg; p < srcend; ++p, ++dst)
+        *dst = *p;
     }
 
-    template <class U>
-    static inline void moveConstruct(T *dst, const U *srcbeg, const U *srcend) {
-        copyConstruct(dst, srcbeg, srcend);
+    template<typename U>
+    static inline void moveConstruct(T* dst, const U* srcbeg, const U* srcend) {
+      copyConstruct(dst, srcbeg, srcend);
     }
 
-    static inline void copyConstructN(T *dst, size_t n, const T &t) {
-        for (T *p = dst, *end = dst + n; p != end; ++p)
-            *p = t;
+    static inline void copyConstructN(T* dst, size_t n, const T& t) {
+      for (T* end = dst + n; dst < end; ++dst)
+        *dst = t;
     }
 
-    static inline bool growTo(Vector<T,N,AP> &v, size_t newCap) {
-        MOZ_ASSERT(!v.usingInlineStorage());
-        MOZ_ASSERT(!CapacityHasExcessSpace<T>(newCap));
-        size_t oldSize = sizeof(T) * v.mCapacity;
-        size_t newSize = sizeof(T) * newCap;
-        T *newbuf = reinterpret_cast<T *>(v.realloc_(v.mBegin, oldSize, newSize));
-        if (!newbuf)
-            return false;
-        v.mBegin = newbuf;
-        /* v.mLength is unchanged. */
-        v.mCapacity = newCap;
-        return true;
+    static inline bool
+    growTo(VectorBase<T, N, AP, ThisVector>& v, size_t newCap) {
+      MOZ_ASSERT(!v.usingInlineStorage());
+      MOZ_ASSERT(!CapacityHasExcessSpace<T>(newCap));
+      size_t oldSize = sizeof(T) * v.mCapacity;
+      size_t newSize = sizeof(T) * newCap;
+      T* newbuf = reinterpret_cast<T*>(v.realloc_(v.mBegin, oldSize, newSize));
+      if (!newbuf)
+        return false;
+      v.mBegin = newbuf;
+      /* v.mLength is unchanged. */
+      v.mCapacity = newCap;
+      return true;
     }
 };
 
+} // namespace detail
+
 /*
- * JS-friendly, 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.
+ * 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!
  *
- * 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 jsalloc.h (default js::TempAllocPolicy)
- *
- * N.B: Vector is not reentrant: T member functions called during Vector member
- *      functions must not call back into the same object.
+ * See mozilla::Vector for interface requirements.
  */
-template <class T, size_t N, class AllocPolicy>
-class Vector : private AllocPolicy
+template<typename T, size_t N, class AllocPolicy, class ThisVector>
+class VectorBase : private AllocPolicy
 {
-    // typedef typename tl::StaticAssert<!tl::IsPostBarrieredType<T>::result>::result _;
-
     /* utilities */
 
-    static const bool sElemIsPod = mozilla::IsPod<T>::value;
-    typedef VectorImpl<T, N, AllocPolicy, sElemIsPod> Impl;
-    friend struct VectorImpl<T, N, AllocPolicy, sElemIsPod>;
+    static const bool sElemIsPod = IsPod<T>::value;
+    typedef detail::VectorImpl<T, N, AllocPolicy, ThisVector, sElemIsPod> Impl;
+    friend struct detail::VectorImpl<T, N, AllocPolicy, ThisVector, sElemIsPod>;
 
     bool growStorageBy(size_t incr);
     bool convertToHeapStorage(size_t newCap);
 
     /* magic constants */
 
     static const int sMaxInlineBytes = 1024;
 
     /* compute constants */
 
     /*
-     * Consider element size to be 1 for buffer sizing if there are
-     * 0 inline elements. This allows us to compile when the definition
-     * of the element type is not visible here.
+     * Consider element size to be 1 for buffer sizing if there are 0 inline
+     * elements.  This allows us to compile when the definition of the element
+     * type is not visible here.
      *
-     * Explicit specialization is only allowed at namespace scope, so
-     * in order to keep everything here, we use a dummy template
-     * parameter with partial specialization.
+     * Explicit specialization is only allowed at namespace scope, so in order
+     * to keep everything here, we use a dummy template parameter with partial
+     * specialization.
      */
-    template <int M, int Dummy>
-    struct ElemSize {
+    template<int M, int Dummy>
+    struct ElemSize
+    {
         static const size_t value = sizeof(T);
     };
-    template <int Dummy>
-    struct ElemSize<0, Dummy> {
+    template<int Dummy>
+    struct ElemSize<0, Dummy>
+    {
         static const size_t value = 1;
     };
 
     static const size_t sInlineCapacity =
-        mozilla::tl::Min<N, sMaxInlineBytes / ElemSize<N, 0>::value>::value;
+      tl::Min<N, sMaxInlineBytes / ElemSize<N, 0>::value>::value;
 
     /* Calculate inline buffer size; avoid 0-sized array. */
     static const size_t sInlineBytes =
-        mozilla::tl::Max<1, sInlineCapacity * ElemSize<N, 0>::value>::value;
+      tl::Max<1, sInlineCapacity * ElemSize<N, 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
      * previously allocated by a call to reserve().
      */
-    T *mBegin;
-    size_t mLength;     /* Number of elements in the Vector. */
-    size_t mCapacity;   /* Max number of elements storable in the Vector without resizing. */
+    T* mBegin;
+
+    /* Number of elements in the vector. */
+    size_t mLength;
+
+    /* Max number of elements storable in the vector without resizing. */
+    size_t mCapacity;
+
 #ifdef DEBUG
-    size_t mReserved;   /* Max elements of reserved or used space in this vector. */
+    /* Max elements of reserved or used space in this vector. */
+    size_t mReserved;
 #endif
 
-    mozilla::AlignedStorage<sInlineBytes> storage;
+    /* Memory used for inline storage. */
+    AlignedStorage<sInlineBytes> storage;
 
 #ifdef DEBUG
-    friend class mozilla::ReentrancyGuard;
+    friend class ReentrancyGuard;
     bool entered;
 #endif
 
-    Vector(const Vector &) MOZ_DELETE;
-    Vector &operator=(const Vector &) MOZ_DELETE;
-
     /* private accessors */
 
     bool usingInlineStorage() const {
-        return mBegin == inlineStorage();
+      return mBegin == const_cast<VectorBase*>(this)->inlineStorage();
     }
 
-    T *inlineStorage() const {
-        return (T *)storage.addr();
+    T* inlineStorage() {
+      return static_cast<T*>(storage.addr());
     }
 
-    T *beginNoCheck() const {
-        return mBegin;
+    T* beginNoCheck() const {
+      return mBegin;
     }
 
-    T *endNoCheck() {
-        return mBegin + mLength;
+    T* endNoCheck() {
+      return mBegin + mLength;
     }
 
-    const T *endNoCheck() const {
-        return mBegin + mLength;
+    const T* endNoCheck() const {
+      return mBegin + mLength;
     }
 
 #ifdef DEBUG
     size_t reserved() const {
-        MOZ_ASSERT(mReserved <= mCapacity);
-        MOZ_ASSERT(mLength <= mReserved);
-        return mReserved;
+      MOZ_ASSERT(mReserved <= mCapacity);
+      MOZ_ASSERT(mLength <= mReserved);
+      return mReserved;
     }
 #endif
 
     /* Append operations guaranteed to succeed due to pre-reserved space. */
-    template <class U> void internalAppend(U u);
-    void internalAppendN(const T &t, size_t n);
-    template <class U> void internalAppend(const U *begin, size_t length);
-    template <class U, size_t O, class BP> void internalAppend(const Vector<U,O,BP> &other);
+    template<typename U> void internalAppend(const U& u);
+    template<typename U, size_t O, class BP, class UV>
+    void internalAppendAll(const VectorBase<U, O, BP, UV>& u);
+    void internalAppendN(const T& t, size_t n);
+    template<typename U> void internalAppend(const U* begin, size_t length);
 
   public:
     static const size_t sMaxInlineStorage = N;
 
     typedef T ElementType;
 
-    Vector(AllocPolicy = AllocPolicy());
-    Vector(mozilla::MoveRef<Vector>); /* Move constructor. */
-    Vector &operator=(mozilla::MoveRef<Vector>); /* Move assignment. */
-    ~Vector();
+    VectorBase(AllocPolicy = AllocPolicy());
+    VectorBase(MoveRef<ThisVector>); /* Move constructor. */
+    ThisVector& operator=(MoveRef<ThisVector>); /* Move assignment. */
+    ~VectorBase();
 
     /* accessors */
 
-    const AllocPolicy &allocPolicy() const {
-        return *this;
+    const AllocPolicy& allocPolicy() const {
+      return *this;
     }
 
-    AllocPolicy &allocPolicy() {
-        return *this;
+    AllocPolicy& allocPolicy() {
+      return *this;
     }
 
     enum { InlineLength = N };
 
     size_t length() const {
-        return mLength;
+      return mLength;
     }
 
     bool empty() const {
-        return mLength == 0;
+      return mLength == 0;
     }
 
     size_t capacity() const {
-        return mCapacity;
+      return mCapacity;
     }
 
-    T *begin() {
-        MOZ_ASSERT(!entered);
-        return mBegin;
+    T* begin() {
+      MOZ_ASSERT(!entered);
+      return mBegin;
     }
 
-    const T *begin() const {
-        MOZ_ASSERT(!entered);
-        return mBegin;
+    const T* begin() const {
+      MOZ_ASSERT(!entered);
+      return mBegin;
     }
 
-    T *end() {
-        MOZ_ASSERT(!entered);
-        return mBegin + mLength;
+    T* end() {
+      MOZ_ASSERT(!entered);
+      return mBegin + mLength;
     }
 
-    const T *end() const {
-        MOZ_ASSERT(!entered);
-        return mBegin + mLength;
+    const T* end() const {
+      MOZ_ASSERT(!entered);
+      return mBegin + mLength;
     }
 
-    T &operator[](size_t i) {
-        MOZ_ASSERT(!entered);
-        MOZ_ASSERT(i < mLength);
-        return begin()[i];
+    T& operator[](size_t i) {
+      MOZ_ASSERT(!entered);
+      MOZ_ASSERT(i < mLength);
+      return begin()[i];
     }
 
-    const T &operator[](size_t i) const {
-        MOZ_ASSERT(!entered);
-        MOZ_ASSERT(i < mLength);
-        return begin()[i];
+    const T& operator[](size_t i) const {
+      MOZ_ASSERT(!entered);
+      MOZ_ASSERT(i < mLength);
+      return begin()[i];
     }
 
-    T &back() {
-        MOZ_ASSERT(!entered);
-        MOZ_ASSERT(!empty());
-        return *(end() - 1);
+    T& back() {
+      MOZ_ASSERT(!entered);
+      MOZ_ASSERT(!empty());
+      return *(end() - 1);
     }
 
-    const T &back() const {
-        MOZ_ASSERT(!entered);
-        MOZ_ASSERT(!empty());
-        return *(end() - 1);
+    const T& back() const {
+      MOZ_ASSERT(!entered);
+      MOZ_ASSERT(!empty());
+      return *(end() - 1);
     }
 
-    class Range {
-        friend class Vector;
-        T *cur_, *end_;
-        Range(T *cur, T *end) : cur_(cur), end_(end) {}
+    class Range
+    {
+        friend class VectorBase;
+        T* cur_;
+        T* end_;
+        Range(T* cur, T* end) : cur_(cur), end_(end) {}
+
       public:
         Range() {}
         bool empty() const { return cur_ == end_; }
         size_t remain() const { return end_ - cur_; }
-        T &front() const { return *cur_; }
+        T& front() const { return *cur_; }
         void popFront() { MOZ_ASSERT(!empty()); ++cur_; }
         T popCopyFront() { MOZ_ASSERT(!empty()); return *cur_++; }
     };
 
     Range all() {
-        return Range(begin(), end());
+      return Range(begin(), end());
     }
 
     /* mutators */
 
-    /* Given that the Vector is empty and has no inline storage, grow to |capacity|. */
+    /**
+     * Given that the vector is empty and has no inline storage, grow to
+     * |capacity|.
+     */
     bool initCapacity(size_t request);
 
-    /* If reserve(length() + N) succeeds, the N next appends are guaranteed to succeed. */
+    /**
+     * If reserve(length() + N) succeeds, the N next appends are guaranteed to
+     * succeed.
+     */
     bool reserve(size_t request);
 
-    /*
+    /**
      * Destroy elements in the range [end() - incr, end()). Does not deallocate
      * or unreserve storage for those elements.
      */
     void shrinkBy(size_t incr);
 
-    /* Grow the vector by incr elements. */
+    /** Grow the vector by incr elements. */
     bool growBy(size_t incr);
 
-    /* Call shrinkBy or growBy based on whether newSize > length(). */
+    /** Call shrinkBy or growBy based on whether newSize > length(). */
     bool resize(size_t newLength);
 
-    /* Leave new elements as uninitialized memory. */
+    /**
+     * Increase the length of the vector, but don't initialize the new elements
+     * -- leave them as uninitialized memory.
+     */
     bool growByUninitialized(size_t incr);
     bool resizeUninitialized(size_t newLength);
 
-    /* Shorthand for shrinkBy(length()). */
+    /** Shorthand for shrinkBy(length()). */
     void clear();
 
-    /* Clears and releases any heap-allocated storage. */
+    /** Clears and releases any heap-allocated storage. */
     void clearAndFree();
 
-    /* If true, appending |needed| elements will not call realloc(). */
+    /**
+     * If true, appending |needed| elements won't reallocate elements storage.
+     * This *doesn't* mean that infallibleAppend may be used!  You still must
+     * reserve the extra space, even if this method indicates that appends won't
+     * need to reallocate elements storage.
+     */
     bool canAppendWithoutRealloc(size_t needed) const;
 
-    /*
+    /**
      * Potentially fallible append operations.
      *
-     * The function templates that take an unspecified type U require a
-     * const T & or a MoveRef<T>. The MoveRef<T> variants move their
-     * operands into the vector, instead of copying them. If they fail, the
-     * operand is left unmoved.
+     * The function templates that take an unspecified type U require a const T&
+     * or a MoveRef<T>.  The MoveRef<T> variants move their operands into the
+     * vector, instead of copying them.  If they fail, the operand is left
+     * unmoved.
      */
-    template <class U> bool append(U t);
-    bool appendN(const T &t, size_t n);
-    template <class U> bool append(const U *begin, const U *end);
-    template <class U> bool append(const U *begin, size_t length);
-    template <class U, size_t O, class BP> bool append(const Vector<U,O,BP> &other);
+    template<typename U> bool append(const U& u);
+    template<typename U, size_t O, class BP, class UV>
+    bool appendAll(const VectorBase<U, O, BP, UV>& u);
+    bool appendN(const T& t, size_t n);
+    template<typename U> bool append(const U* begin, const U* end);
+    template<typename U> bool append(const U* begin, size_t length);
 
     /*
      * Guaranteed-infallible append operations for use upon vectors whose
-     * memory has been pre-reserved.
+     * memory has been pre-reserved.  Don't use this if you haven't reserved the
+     * memory!
      */
-    template <class U> void infallibleAppend(const U &u) {
-        internalAppend(u);
-    }
-    void infallibleAppendN(const T &t, size_t n) {
-        internalAppendN(t, n);
+    template<typename U> void infallibleAppend(const U& u) {
+      internalAppend(u);
     }
-    template <class U> void infallibleAppend(const U *aBegin, const U *aEnd) {
-        internalAppend(aBegin, mozilla::PointerRangeSize(aBegin, aEnd));
+    void infallibleAppendN(const T& t, size_t n) {
+      internalAppendN(t, n);
     }
-    template <class U> void infallibleAppend(const U *aBegin, size_t aLength) {
-        internalAppend(aBegin, aLength);
+    template<typename U> void infallibleAppend(const U* aBegin, const U* aEnd) {
+      internalAppend(aBegin, PointerRangeSize(aBegin, aEnd));
     }
-    template <class U, size_t O, class BP> void infallibleAppend(const Vector<U,O,BP> &other) {
-        internalAppend(other);
+    template<typename U> void infallibleAppend(const U* aBegin, size_t aLength) {
+      internalAppend(aBegin, aLength);
     }
 
     void popBack();
 
     T popCopy();
 
-    /*
-     * Transfers ownership of the internal buffer used by Vector to the caller.
-     * After this call, the Vector is empty. Since the returned buffer may need
-     * to be allocated (if the elements are currently stored in-place), the
-     * call can fail, returning NULL.
+    /**
+     * Transfers ownership of the internal buffer used by this vector to the
+     * caller.  (It's the caller's responsibility to properly deallocate this
+     * buffer, in accordance with this vector's AllocPolicy.)  After this call,
+     * the vector is empty.  Since the returned buffer may need to be allocated
+     * (if the elements are currently stored in-place), the call can fail,
+     * returning nullptr.
      *
      * N.B. Although a T*, only the range [0, length()) is constructed.
      */
-    T *extractRawBuffer();
+    T* extractRawBuffer();
 
-    /*
-     * Transfer ownership of an array of objects into the Vector.
+    /**
+     * Transfer ownership of an array of objects into the vector.  The caller
+     * must have allocated the array in accordance with this vector's
+     * AllocPolicy.
+     *
      * N.B. This call assumes that there are no uninitialized elements in the
      *      passed array.
      */
-    void replaceRawBuffer(T *p, size_t length);
+    void replaceRawBuffer(T* p, size_t length);
 
-    /*
-     * Places |val| at position |p|, shifting existing elements from |p|
-     * onward one position higher.  On success, |p| should not be reused
-     * because it will be a dangling pointer if reallocation of the vector
-     * storage occurred;  the return value should be used instead.  On failure,
-     * NULL is returned.
+    /**
+     * Places |val| at position |p|, shifting existing elements from |p| onward
+     * one position higher.  On success, |p| should not be reused because it'll
+     * be a dangling pointer if reallocation of the vector storage occurred; the
+     * return value should be used instead.  On failure, nullptr is returned.
      *
      * Example usage:
      *
      *   if (!(p = vec.insert(p, val)))
-     *       <handle failure>
+     *     <handle failure>
      *   <keep working with p>
+     *
+     * This is inherently a linear-time operation.  Be careful!
      */
-    T *insert(T *p, const T &val);
+    T* insert(T* p, const T& val);
 
-    /*
+    /**
      * Removes the element |t|, which must fall in the bounds [begin, end),
      * shifting existing elements from |t + 1| onward one position lower.
      */
-    void erase(T *t);
+    void erase(T* t);
 
-    /*
-     * Measure the size of the Vector's heap-allocated storage.
+    /**
+     * Measure the size of the vector's heap-allocated storage.
      */
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+    size_t sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const;
 
-    /*
-     * Like sizeOfExcludingThis, but also measures the size of the Vector
+    /**
+     * Like sizeOfExcludingThis, but also measures the size of the vector
      * object (which must be heap-allocated) itself.
      */
-    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+    size_t sizeOfIncludingThis(MallocSizeOf mallocSizeOf) const;
+
+    void swap(ThisVector& other);
 
-    void swap(Vector &other);
+  private:
+    VectorBase(const ThisVector&) MOZ_DELETE;
+    void operator=(const ThisVector&) MOZ_DELETE;
 };
 
 /* This does the re-entrancy check plus several other sanity checks. */
-#define REENTRANCY_GUARD_ET_AL \
-    mozilla::ReentrancyGuard g(*this); \
-    MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == sInlineCapacity); \
-    MOZ_ASSERT(reserved() <= mCapacity); \
-    MOZ_ASSERT(mLength <= reserved()); \
-    MOZ_ASSERT(mLength <= mCapacity)
+#define MOZ_REENTRANCY_GUARD_ET_AL \
+  ReentrancyGuard g(*this); \
+  MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == sInlineCapacity); \
+  MOZ_ASSERT(reserved() <= mCapacity); \
+  MOZ_ASSERT(mLength <= reserved()); \
+  MOZ_ASSERT(mLength <= mCapacity)
 
 /* Vector Implementation */
 
-template <class T, size_t N, class AllocPolicy>
+template<typename T, size_t N, class AP, class TV>
 MOZ_ALWAYS_INLINE
-Vector<T,N,AllocPolicy>::Vector(AllocPolicy ap)
-  : AllocPolicy(ap), mBegin((T *)storage.addr()), mLength(0),
+VectorBase<T, N, AP, TV>::VectorBase(AP ap)
+  : AP(ap),
+    mBegin(static_cast<T*>(storage.addr())),
+    mLength(0),
     mCapacity(sInlineCapacity)
 #ifdef DEBUG
-  , mReserved(sInlineCapacity), entered(false)
+  , mReserved(sInlineCapacity),
+    entered(false)
 #endif
 {}
 
 /* Move constructor. */
-template <class T, size_t N, class AllocPolicy>
+template<typename T, size_t N, class AllocPolicy, class TV>
 MOZ_ALWAYS_INLINE
-Vector<T, N, AllocPolicy>::Vector(mozilla::MoveRef<Vector> rhs)
-    : AllocPolicy(rhs)
+VectorBase<T, N, AllocPolicy, TV>::VectorBase(MoveRef<TV> rhs)
+  : AllocPolicy(rhs)
 #ifdef DEBUG
     , entered(false)
 #endif
 {
-    mLength = rhs->mLength;
-    mCapacity = rhs->mCapacity;
+  mLength = rhs->mLength;
+  mCapacity = rhs->mCapacity;
 #ifdef DEBUG
-    mReserved = rhs->mReserved;
+  mReserved = rhs->mReserved;
 #endif
 
-    if (rhs->usingInlineStorage()) {
-        /* We can't move the buffer over in this case, so copy elements. */
-        mBegin = (T *)storage.addr();
-        Impl::moveConstruct(mBegin, rhs->beginNoCheck(), rhs->endNoCheck());
-        /*
-         * Leave rhs's mLength, mBegin, mCapacity, and mReserved as they are.
-         * The elements in its in-line storage still need to be destroyed.
-         */
-    } else {
-        /*
-         * Take src's buffer, and turn src into an empty vector using
-         * in-line storage.
-         */
-        mBegin = rhs->mBegin;
-        rhs->mBegin = (T *) rhs->storage.addr();
-        rhs->mCapacity = sInlineCapacity;
-        rhs->mLength = 0;
+  if (rhs->usingInlineStorage()) {
+    /* We can't move the buffer over in this case, so copy elements. */
+    mBegin = static_cast<T*>(storage.addr());
+    Impl::moveConstruct(mBegin, rhs->beginNoCheck(), rhs->endNoCheck());
+    /*
+     * Leave rhs's mLength, mBegin, mCapacity, and mReserved as they are.
+     * The elements in its in-line storage still need to be destroyed.
+     */
+  } else {
+    /*
+     * Take src's buffer, and turn src into an empty vector using
+     * in-line storage.
+     */
+    mBegin = rhs->mBegin;
+    rhs->mBegin = static_cast<T*>(rhs->storage.addr());
+    rhs->mCapacity = sInlineCapacity;
+    rhs->mLength = 0;
 #ifdef DEBUG
-        rhs->mReserved = sInlineCapacity;
+    rhs->mReserved = sInlineCapacity;
 #endif
-    }
+  }
 }
 
 /* Move assignment. */
-template <class T, size_t N, class AP>
+template<typename T, size_t N, class AP, class TV>
 MOZ_ALWAYS_INLINE
-Vector<T, N, AP> &
-Vector<T, N, AP>::operator=(mozilla::MoveRef<Vector> rhs)
+TV&
+VectorBase<T, N, AP, TV>::operator=(MoveRef<TV> rhs)
 {
-    this->~Vector();
-    new(this) Vector(rhs);
-    return *this;
+  TV* tv = static_cast<TV*>(this);
+  tv->~TV();
+  new(tv) TV(rhs);
+  return *tv;
 }
 
-template <class T, size_t N, class AP>
+template<typename T, size_t N, class AP, class TV>
 MOZ_ALWAYS_INLINE
-Vector<T,N,AP>::~Vector()
+VectorBase<T, N, AP, TV>::~VectorBase()
 {
-    REENTRANCY_GUARD_ET_AL;
-    Impl::destroy(beginNoCheck(), endNoCheck());
-    if (!usingInlineStorage())
-        this->free_(beginNoCheck());
+  MOZ_REENTRANCY_GUARD_ET_AL;
+  Impl::destroy(beginNoCheck(), endNoCheck());
+  if (!usingInlineStorage())
+    this->free_(beginNoCheck());
 }
 
 /*
  * This function will create a new heap buffer with capacity newCap,
  * move all elements in the inline buffer to this new buffer,
  * and fail on OOM.
  */
-template <class T, size_t N, class AP>
+template<typename T, size_t N, class AP, class TV>
 inline bool
-Vector<T,N,AP>::convertToHeapStorage(size_t newCap)
+VectorBase<T, N, AP, TV>::convertToHeapStorage(size_t newCap)
 {
-    MOZ_ASSERT(usingInlineStorage());
+  MOZ_ASSERT(usingInlineStorage());
 
-    /* Allocate buffer. */
-    MOZ_ASSERT(!CapacityHasExcessSpace<T>(newCap));
-    T *newBuf = reinterpret_cast<T *>(this->malloc_(newCap * sizeof(T)));
-    if (!newBuf)
-        return false;
+  /* Allocate buffer. */
+  MOZ_ASSERT(!detail::CapacityHasExcessSpace<T>(newCap));
+  T* newBuf = reinterpret_cast<T*>(this->malloc_(newCap * sizeof(T)));
+  if (!newBuf)
+    return false;
 
-    /* Copy inline elements into heap buffer. */
-    Impl::moveConstruct(newBuf, beginNoCheck(), endNoCheck());
-    Impl::destroy(beginNoCheck(), endNoCheck());
+  /* Copy inline elements into heap buffer. */
+  Impl::moveConstruct(newBuf, beginNoCheck(), endNoCheck());
+  Impl::destroy(beginNoCheck(), endNoCheck());
 
-    /* Switch in heap buffer. */
-    mBegin = newBuf;
-    /* mLength is unchanged. */
-    mCapacity = newCap;
-    return true;
+  /* Switch in heap buffer. */
+  mBegin = newBuf;
+  /* mLength is unchanged. */
+  mCapacity = newCap;
+  return true;
 }
 
-template <class T, size_t N, class AP>
+template<typename T, size_t N, class AP, class TV>
 MOZ_NEVER_INLINE bool
-Vector<T,N,AP>::growStorageBy(size_t incr)
+VectorBase<T, N, AP, TV>::growStorageBy(size_t incr)
 {
-    MOZ_ASSERT(mLength + incr > mCapacity);
-    MOZ_ASSERT_IF(!usingInlineStorage(), !CapacityHasExcessSpace<T>(mCapacity));
+  MOZ_ASSERT(mLength + incr > mCapacity);
+  MOZ_ASSERT_IF(!usingInlineStorage(),
+                !detail::CapacityHasExcessSpace<T>(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
+   * result in a non-2**N request size.
+   */
+
+  size_t newCap;
+
+  if (incr == 1) {
+    if (usingInlineStorage()) {
+      /* This case occurs in ~70--80% of the calls to this function. */
+      size_t newSize =
+        tl::RoundUpPow2<(sInlineCapacity + 1) * sizeof(T)>::value;
+      newCap = newSize / sizeof(T);
+      goto convert;
+    }
+
+    if (mLength == 0) {
+      /* This case occurs in ~0--10% of the calls to this function. */
+      newCap = 1;
+      goto grow;
+    }
+
+    /* This case occurs in ~15--20% of the calls to this function. */
+
+    /*
+     * Will mLength * 4 *sizeof(T) overflow?  This condition limits a vector
+     * to 1GB of memory on a 32-bit system, which is a reasonable limit.  It
+     * also ensures that
+     *
+     *   static_cast<char*>(end()) - static_cast<char*>(begin())
+     *
+     * doesn't overflow ptrdiff_t (see bug 510319).
+     */
+    if (mLength & tl::MulOverflowMask<4 * sizeof(T)>::value) {
+      this->reportAllocOverflow();
+      return false;
+    }
 
     /*
-     * 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
-     * result in a non-2^N request size.
+     * If we reach here, the existing capacity will have a size that is already
+     * as close to 2^N as sizeof(T) will allow.  Just double the capacity, and
+     * then there might be space for one more element.
      */
-
-    size_t newCap;
-
-    if (incr == 1) {
-        if (usingInlineStorage()) {
-            /* This case occurs in ~70--80% of the calls to this function. */
-            size_t newSize = mozilla::tl::RoundUpPow2<(sInlineCapacity + 1) * sizeof(T)>::value;
-            newCap = newSize / sizeof(T);
-            goto convert;
-        }
-
-        if (mLength == 0) {
-            /* This case occurs in ~0--10% of the calls to this function. */
-            newCap = 1;
-            goto grow;
-        }
-
-        /* This case occurs in ~15--20% of the calls to this function. */
+    newCap = mLength * 2;
+    if (detail::CapacityHasExcessSpace<T>(newCap))
+      newCap += 1;
+  } else {
+    /* This case occurs in ~2% of the calls to this function. */
+    size_t newMinCap = mLength + incr;
 
-        /*
-         * Will mLength*4*sizeof(T) overflow?  This condition limits a Vector
-         * to 1GB of memory on a 32-bit system, which is a reasonable limit.
-         * It also ensures that the ((char *)end() - (char *)begin()) does not
-         * overflow ptrdiff_t (see Bug 510319).
-         */
-        if (mLength & mozilla::tl::MulOverflowMask<4 * sizeof(T)>::value) {
-            this->reportAllocOverflow();
-            return false;
-        }
-
-        /*
-         * If we reach here, the existing capacity will have a size that is
-         * already as close to 2^N as sizeof(T) will allow.  Just double the
-         * capacity, and then there might be space for one more element.
-         */
-        newCap = mLength * 2;
-        if (CapacityHasExcessSpace<T>(newCap))
-            newCap += 1;
-
-    } else {
-        /* This case occurs in ~2% of the calls to this function. */
-        size_t newMinCap = mLength + incr;
-
-        /* Did mLength+incr overflow?  Will newCap*sizeof(T) overflow? */
-        if (newMinCap < mLength ||
-            newMinCap & mozilla::tl::MulOverflowMask<2 * sizeof(T)>::value)
-        {
-            this->reportAllocOverflow();
-            return false;
-        }
-
-        size_t newMinSize = newMinCap * sizeof(T);
-        size_t newSize = mozilla::RoundUpPow2(newMinSize);
-        newCap = newSize / sizeof(T);
+    /* Did mLength + incr overflow?  Will newCap * sizeof(T) overflow? */
+    if (newMinCap < mLength ||
+        newMinCap & tl::MulOverflowMask<2 * sizeof(T)>::value)
+    {
+      this->reportAllocOverflow();
+      return false;
     }
 
-    if (usingInlineStorage()) {
-      convert:
-        return convertToHeapStorage(newCap);
-    }
+    size_t newMinSize = newMinCap * sizeof(T);
+    size_t newSize = RoundUpPow2(newMinSize);
+    newCap = newSize / sizeof(T);
+  }
+
+  if (usingInlineStorage()) {
+  convert:
+    return convertToHeapStorage(newCap);
+  }
+
+grow:
+  return Impl::growTo(*this, newCap);
+}
+
+template<typename T, size_t N, class AP, class TV>
+inline bool
+VectorBase<T, N, AP, TV>::initCapacity(size_t request)
+{
+  MOZ_ASSERT(empty());
+  MOZ_ASSERT(usingInlineStorage());
+  if (request == 0)
+    return true;
+  T* newbuf = reinterpret_cast<T*>(this->malloc_(request * sizeof(T)));
+  if (!newbuf)
+    return false;
+  mBegin = newbuf;
+  mCapacity = request;
+#ifdef DEBUG
+  mReserved = request;
+#endif
+  return true;
+}
+
+template<typename T, size_t N, class AP, class TV>
+inline bool
+VectorBase<T, N, AP, TV>::reserve(size_t request)
+{
+  MOZ_REENTRANCY_GUARD_ET_AL;
+  if (request > mCapacity && !growStorageBy(request - mLength))
+    return false;
+
+#ifdef DEBUG
+  if (request > mReserved)
+    mReserved = request;
+  MOZ_ASSERT(mLength <= mReserved);
+  MOZ_ASSERT(mReserved <= mCapacity);
+#endif
+  return true;
+}
 
-  grow:
-    return Impl::growTo(*this, newCap);
+template<typename T, size_t N, class AP, class TV>
+inline void
+VectorBase<T, N, AP, TV>::shrinkBy(size_t incr)
+{
+  MOZ_REENTRANCY_GUARD_ET_AL;
+  MOZ_ASSERT(incr <= mLength);
+  Impl::destroy(endNoCheck() - incr, endNoCheck());
+  mLength -= incr;
+}
+
+template<typename T, size_t N, class AP, class TV>
+MOZ_ALWAYS_INLINE bool
+VectorBase<T, N, AP, TV>::growBy(size_t incr)
+{
+  MOZ_REENTRANCY_GUARD_ET_AL;
+  if (incr > mCapacity - mLength && !growStorageBy(incr))
+    return false;
+
+  MOZ_ASSERT(mLength + incr <= mCapacity);
+  T* newend = endNoCheck() + incr;
+  Impl::initialize(endNoCheck(), newend);
+  mLength += incr;
+#ifdef DEBUG
+  if (mLength > mReserved)
+    mReserved = mLength;
+#endif
+  return true;
+}
+
+template<typename T, size_t N, class AP, class TV>
+MOZ_ALWAYS_INLINE bool
+VectorBase<T, N, AP, TV>::growByUninitialized(size_t incr)
+{
+  MOZ_REENTRANCY_GUARD_ET_AL;
+  if (incr > mCapacity - mLength && !growStorageBy(incr))
+    return false;
+
+  MOZ_ASSERT(mLength + incr <= mCapacity);
+  mLength += incr;
+#ifdef DEBUG
+  if (mLength > mReserved)
+    mReserved = mLength;
+#endif
+  return true;
+}
+
+template<typename T, size_t N, class AP, class TV>
+inline bool
+VectorBase<T, N, AP, TV>::resize(size_t newLength)
+{
+  size_t curLength = mLength;
+  if (newLength > curLength)
+    return growBy(newLength - curLength);
+  shrinkBy(curLength - newLength);
+  return true;
+}
+
+template<typename T, size_t N, class AP, class TV>
+MOZ_ALWAYS_INLINE bool
+VectorBase<T, N, AP, TV>::resizeUninitialized(size_t newLength)
+{
+  size_t curLength = mLength;
+  if (newLength > curLength)
+    return growByUninitialized(newLength - curLength);
+  shrinkBy(curLength - newLength);
+  return true;
 }
 
-template <class T, size_t N, class AP>
-inline bool
-Vector<T,N,AP>::initCapacity(size_t request)
+template<typename T, size_t N, class AP, class TV>
+inline void
+VectorBase<T, N, AP, TV>::clear()
+{
+  MOZ_REENTRANCY_GUARD_ET_AL;
+  Impl::destroy(beginNoCheck(), endNoCheck());
+  mLength = 0;
+}
+
+template<typename T, size_t N, class AP, class TV>
+inline void
+VectorBase<T, N, AP, TV>::clearAndFree()
 {
-    MOZ_ASSERT(empty());
-    MOZ_ASSERT(usingInlineStorage());
-    if (request == 0)
-        return true;
-    T *newbuf = reinterpret_cast<T *>(this->malloc_(request * sizeof(T)));
-    if (!newbuf)
-        return false;
-    mBegin = newbuf;
-    mCapacity = request;
+  clear();
+
+  if (usingInlineStorage())
+    return;
+
+  this->free_(beginNoCheck());
+  mBegin = static_cast<T*>(storage.addr());
+  mCapacity = sInlineCapacity;
 #ifdef DEBUG
-    mReserved = request;
+  mReserved = sInlineCapacity;
 #endif
-    return true;
+}
+
+template<typename T, size_t N, class AP, class TV>
+inline bool
+VectorBase<T, N, AP, TV>::canAppendWithoutRealloc(size_t needed) const
+{
+  return mLength + needed <= mCapacity;
+}
+
+template<typename T, size_t N, class AP, class TV>
+template<typename U, size_t O, class BP, class UV>
+MOZ_ALWAYS_INLINE void
+VectorBase<T, N, AP, TV>::internalAppendAll(const VectorBase<U, O, BP, UV>& other)
+{
+  internalAppend(other.begin(), other.length());
 }
 
-template <class T, size_t N, class AP>
-inline bool
-Vector<T,N,AP>::reserve(size_t request)
+template<typename T, size_t N, class AP, class TV>
+template<typename U>
+MOZ_ALWAYS_INLINE void
+VectorBase<T, N, AP, TV>::internalAppend(const U& u)
 {
-    REENTRANCY_GUARD_ET_AL;
-    if (request > mCapacity && !growStorageBy(request - mLength))
-        return false;
+  MOZ_ASSERT(mLength + 1 <= mReserved);
+  MOZ_ASSERT(mReserved <= mCapacity);
+  new(endNoCheck()) T(u);
+  ++mLength;
+}
+
+template<typename T, size_t N, class AP, class TV>
+MOZ_ALWAYS_INLINE bool
+VectorBase<T, N, AP, TV>::appendN(const T& t, size_t needed)
+{
+  MOZ_REENTRANCY_GUARD_ET_AL;
+  if (mLength + needed > mCapacity && !growStorageBy(needed))
+    return false;
 
 #ifdef DEBUG
-    if (request > mReserved)
-        mReserved = request;
-    MOZ_ASSERT(mLength <= mReserved);
-    MOZ_ASSERT(mReserved <= mCapacity);
+  if (mLength + needed > mReserved)
+    mReserved = mLength + needed;
 #endif
-    return true;
+  internalAppendN(t, needed);
+  return true;
+}
+
+template<typename T, size_t N, class AP, class TV>
+MOZ_ALWAYS_INLINE void
+VectorBase<T, N, AP, TV>::internalAppendN(const T& t, size_t needed)
+{
+  MOZ_ASSERT(mLength + needed <= mReserved);
+  MOZ_ASSERT(mReserved <= mCapacity);
+  Impl::copyConstructN(endNoCheck(), needed, t);
+  mLength += needed;
 }
 
-template <class T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::shrinkBy(size_t incr)
+template<typename T, size_t N, class AP, class TV>
+inline T*
+VectorBase<T, N, AP, TV>::insert(T* p, const T& val)
 {
-    REENTRANCY_GUARD_ET_AL;
-    MOZ_ASSERT(incr <= mLength);
-    Impl::destroy(endNoCheck() - incr, endNoCheck());
-    mLength -= incr;
+  MOZ_ASSERT(begin() <= p);
+  MOZ_ASSERT(p <= end());
+  size_t pos = p - begin();
+  MOZ_ASSERT(pos <= mLength);
+  size_t oldLength = mLength;
+  if (pos == oldLength) {
+    if (!append(val))
+      return nullptr;
+  } else {
+    T oldBack = back();
+    if (!append(oldBack)) /* Dup the last element. */
+      return nullptr;
+    for (size_t i = oldLength; i > pos; --i)
+      (*this)[i] = (*this)[i - 1];
+    (*this)[pos] = val;
+  }
+  return begin() + pos;
 }
 
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::growBy(size_t incr)
+template<typename T, size_t N, class AP, class TV>
+inline void
+VectorBase<T, N, AP, TV>::erase(T* it)
 {
-    REENTRANCY_GUARD_ET_AL;
-    if (incr > mCapacity - mLength && !growStorageBy(incr))
-        return false;
-
-    MOZ_ASSERT(mLength + incr <= mCapacity);
-    T *newend = endNoCheck() + incr;
-    Impl::initialize(endNoCheck(), newend);
-    mLength += incr;
-#ifdef DEBUG
-    if (mLength > mReserved)
-        mReserved = mLength;
-#endif
-    return true;
+  MOZ_ASSERT(begin() <= it);
+  MOZ_ASSERT(it < end());
+  while (it + 1 < end()) {
+    *it = *(it + 1);
+    ++it;
+  }
+  popBack();
 }
 
-template <class T, size_t N, class AP>
+template<typename T, size_t N, class AP, class TV>
+template<typename U>
 MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::growByUninitialized(size_t incr)
+VectorBase<T, N, AP, TV>::append(const U* insBegin, const U* insEnd)
 {
-    REENTRANCY_GUARD_ET_AL;
-    if (incr > mCapacity - mLength && !growStorageBy(incr))
-        return false;
+  MOZ_REENTRANCY_GUARD_ET_AL;
+  size_t needed = PointerRangeSize(insBegin, insEnd);
+  if (mLength + needed > mCapacity && !growStorageBy(needed))
+    return false;
 
-    MOZ_ASSERT(mLength + incr <= mCapacity);
-    mLength += incr;
 #ifdef DEBUG
-    if (mLength > mReserved)
-        mReserved = mLength;
+  if (mLength + needed > mReserved)
+    mReserved = mLength + needed;
 #endif
-    return true;
+  internalAppend(insBegin, needed);
+  return true;
+}
+
+template<typename T, size_t N, class AP, class TV>
+template<typename U>
+MOZ_ALWAYS_INLINE void
+VectorBase<T, N, AP, TV>::internalAppend(const U* insBegin, size_t insLength)
+{
+  MOZ_ASSERT(mLength + insLength <= mReserved);
+  MOZ_ASSERT(mReserved <= mCapacity);
+  Impl::copyConstruct(endNoCheck(), insBegin, insBegin + insLength);
+  mLength += insLength;
 }
 
-template <class T, size_t N, class AP>
-inline bool
-Vector<T,N,AP>::resize(size_t newLength)
+template<typename T, size_t N, class AP, class TV>
+template<typename U>
+MOZ_ALWAYS_INLINE bool
+VectorBase<T, N, AP, TV>::append(const U& u)
 {
-    size_t curLength = mLength;
-    if (newLength > curLength)
-        return growBy(newLength - curLength);
-    shrinkBy(curLength - newLength);
-    return true;
+  MOZ_REENTRANCY_GUARD_ET_AL;
+  if (mLength == mCapacity && !growStorageBy(1))
+    return false;
+
+#ifdef DEBUG
+  if (mLength + 1 > mReserved)
+    mReserved = mLength + 1;
+#endif
+  internalAppend(u);
+  return true;
+}
+
+template<typename T, size_t N, class AP, class TV>
+template<typename U, size_t O, class BP, class UV>
+MOZ_ALWAYS_INLINE bool
+VectorBase<T, N, AP, TV>::appendAll(const VectorBase<U, O, BP, UV>& other)
+{
+  return append(other.begin(), other.length());
+}
+
+template<typename T, size_t N, class AP, class TV>
+template<class U>
+MOZ_ALWAYS_INLINE bool
+VectorBase<T, N, AP, TV>::append(const U *insBegin, size_t insLength)
+{
+  return append(insBegin, insBegin + insLength);
 }
 
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::resizeUninitialized(size_t newLength)
+template<typename T, size_t N, class AP, class TV>
+MOZ_ALWAYS_INLINE void
+VectorBase<T, N, AP, TV>::popBack()
 {
-    size_t curLength = mLength;
-    if (newLength > curLength)
-        return growByUninitialized(newLength - curLength);
-    shrinkBy(curLength - newLength);
-    return true;
+  MOZ_REENTRANCY_GUARD_ET_AL;
+  MOZ_ASSERT(!empty());
+  --mLength;
+  endNoCheck()->~T();
 }
 
-template <class T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::clear()
+template<typename T, size_t N, class AP, class TV>
+MOZ_ALWAYS_INLINE T
+VectorBase<T, N, AP, TV>::popCopy()
 {
-    REENTRANCY_GUARD_ET_AL;
-    Impl::destroy(beginNoCheck(), endNoCheck());
-    mLength = 0;
+  T ret = back();
+  popBack();
+  return ret;
 }
 
-template <class T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::clearAndFree()
+template<typename T, size_t N, class AP, class TV>
+inline T*
+VectorBase<T, N, AP, TV>::extractRawBuffer()
 {
-    clear();
-
-    if (usingInlineStorage())
-        return;
-
-    this->free_(beginNoCheck());
-    mBegin = (T *)storage.addr();
+  T* ret;
+  if (usingInlineStorage()) {
+    ret = reinterpret_cast<T*>(this->malloc_(mLength * sizeof(T)));
+    if (!ret)
+        return NULL;
+    Impl::copyConstruct(ret, beginNoCheck(), endNoCheck());
+    Impl::destroy(beginNoCheck(), endNoCheck());
+    /* mBegin, mCapacity are unchanged. */
+    mLength = 0;
+  } else {
+    ret = mBegin;
+    mBegin = static_cast<T*>(storage.addr());
+    mLength = 0;
     mCapacity = sInlineCapacity;
 #ifdef DEBUG
     mReserved = sInlineCapacity;
 #endif
-}
-
-template <class T, size_t N, class AP>
-inline bool
-Vector<T,N,AP>::canAppendWithoutRealloc(size_t needed) const
-{
-    return mLength + needed <= mCapacity;
-}
-
-template <class T, size_t N, class AP>
-template <class U>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::append(U t)
-{
-    REENTRANCY_GUARD_ET_AL;
-    if (mLength == mCapacity && !growStorageBy(1))
-        return false;
-
-#ifdef DEBUG
-    if (mLength + 1 > mReserved)
-        mReserved = mLength + 1;
-#endif
-    internalAppend(t);
-    return true;
-}
-
-template <class T, size_t N, class AP>
-template <class U>
-MOZ_ALWAYS_INLINE void
-Vector<T,N,AP>::internalAppend(U u)
-{
-    MOZ_ASSERT(mLength + 1 <= mReserved);
-    MOZ_ASSERT(mReserved <= mCapacity);
-    new(endNoCheck()) T(u);
-    ++mLength;
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::appendN(const T &t, size_t needed)
-{
-    REENTRANCY_GUARD_ET_AL;
-    if (mLength + needed > mCapacity && !growStorageBy(needed))
-        return false;
-
-#ifdef DEBUG
-    if (mLength + needed > mReserved)
-        mReserved = mLength + needed;
-#endif
-    internalAppendN(t, needed);
-    return true;
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE void
-Vector<T,N,AP>::internalAppendN(const T &t, size_t needed)
-{
-    MOZ_ASSERT(mLength + needed <= mReserved);
-    MOZ_ASSERT(mReserved <= mCapacity);
-    Impl::copyConstructN(endNoCheck(), needed, t);
-    mLength += needed;
-}
-
-template <class T, size_t N, class AP>
-inline T *
-Vector<T,N,AP>::insert(T *p, const T &val)
-{
-    MOZ_ASSERT(begin() <= p);
-    MOZ_ASSERT(p <= end());
-    size_t pos = p - begin();
-    MOZ_ASSERT(pos <= mLength);
-    size_t oldLength = mLength;
-    if (pos == oldLength) {
-        if (!append(val))
-            return NULL;
-    } else {
-        T oldBack = back();
-        if (!append(oldBack)) /* Dup the last element. */
-            return NULL;
-        for (size_t i = oldLength; i > pos; --i)
-            (*this)[i] = (*this)[i - 1];
-        (*this)[pos] = val;
-    }
-    return begin() + pos;
-}
-
-template<typename T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::erase(T *it)
-{
-    MOZ_ASSERT(begin() <= it);
-    MOZ_ASSERT(it < end());
-    while (it + 1 != end()) {
-        *it = *(it + 1);
-        ++it;
-    }
-    popBack();
+  }
+  return ret;
 }
 
-template <class T, size_t N, class AP>
-template <class U>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::append(const U *insBegin, const U *insEnd)
+template<typename T, size_t N, class AP, class TV>
+inline void
+VectorBase<T, N, AP, TV>::replaceRawBuffer(T* p, size_t aLength)
 {
-    REENTRANCY_GUARD_ET_AL;
-    size_t needed = mozilla::PointerRangeSize(insBegin, insEnd);
-    if (mLength + needed > mCapacity && !growStorageBy(needed))
-        return false;
-
-#ifdef DEBUG
-    if (mLength + needed > mReserved)
-        mReserved = mLength + needed;
-#endif
-    internalAppend(insBegin, needed);
-    return true;
-}
-
-template <class T, size_t N, class AP>
-template <class U>
-MOZ_ALWAYS_INLINE void
-Vector<T,N,AP>::internalAppend(const U *insBegin, size_t insLength)
-{
-    MOZ_ASSERT(mLength + insLength <= mReserved);
-    MOZ_ASSERT(mReserved <= mCapacity);
-    Impl::copyConstruct(endNoCheck(), insBegin, insBegin + insLength);
-    mLength += insLength;
-}
+  MOZ_REENTRANCY_GUARD_ET_AL;
 
-template <class T, size_t N, class AP>
-template <class U, size_t O, class BP>
-inline bool
-Vector<T,N,AP>::append(const Vector<U,O,BP> &other)
-{
-    return append(other.begin(), other.end());
-}
-
-template <class T, size_t N, class AP>
-template <class U, size_t O, class BP>
-inline void
-Vector<T,N,AP>::internalAppend(const Vector<U,O,BP> &other)
-{
-    internalAppend(other.begin(), other.length());
-}
-
-template <class T, size_t N, class AP>
-template <class U>
-MOZ_ALWAYS_INLINE bool
-Vector<T,N,AP>::append(const U *insBegin, size_t insLength)
-{
-    return this->append(insBegin, insBegin + insLength);
-}
-
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE void
-Vector<T,N,AP>::popBack()
-{
-    REENTRANCY_GUARD_ET_AL;
-    MOZ_ASSERT(!empty());
-    --mLength;
-    endNoCheck()->~T();
-}
+  /* Destroy what we have. */
+  Impl::destroy(beginNoCheck(), endNoCheck());
+  if (!usingInlineStorage())
+    this->free_(beginNoCheck());
 
-template <class T, size_t N, class AP>
-MOZ_ALWAYS_INLINE T
-Vector<T,N,AP>::popCopy()
-{
-    T ret = back();
-    popBack();
-    return ret;
-}
-
-template <class T, size_t N, class AP>
-inline T *
-Vector<T,N,AP>::extractRawBuffer()
-{
-    T *ret;
-    if (usingInlineStorage()) {
-        ret = reinterpret_cast<T *>(this->malloc_(mLength * sizeof(T)));
-        if (!ret)
-            return NULL;
-        Impl::copyConstruct(ret, beginNoCheck(), endNoCheck());
-        Impl::destroy(beginNoCheck(), endNoCheck());
-        /* mBegin, mCapacity are unchanged. */
-        mLength = 0;
-    } else {
-        ret = mBegin;
-        mBegin = (T *)storage.addr();
-        mLength = 0;
-        mCapacity = sInlineCapacity;
+  /* Take in the new buffer. */
+  if (aLength <= sInlineCapacity) {
+    /*
+     * We convert to inline storage if possible, even though p might
+     * otherwise be acceptable.  Maybe this behaviour should be
+     * specifiable with an argument to this function.
+     */
+    mBegin = static_cast<T*>(storage.addr());
+    mLength = aLength;
+    mCapacity = sInlineCapacity;
+    Impl::moveConstruct(mBegin, p, p + aLength);
+    Impl::destroy(p, p + aLength);
+    this->free_(p);
+  } else {
+    mBegin = p;
+    mLength = aLength;
+    mCapacity = aLength;
+  }
 #ifdef DEBUG
-        mReserved = sInlineCapacity;
-#endif
-    }
-    return ret;
-}
-
-template <class T, size_t N, class AP>
-inline void
-Vector<T,N,AP>::replaceRawBuffer(T *p, size_t aLength)
-{
-    REENTRANCY_GUARD_ET_AL;
-
-    /* Destroy what we have. */
-    Impl::destroy(beginNoCheck(), endNoCheck());
-    if (!usingInlineStorage())
-        this->free_(beginNoCheck());
-
-    /* Take in the new buffer. */
-    if (aLength <= sInlineCapacity) {
-        /*
-         * We convert to inline storage if possible, even though p might
-         * otherwise be acceptable.  Maybe this behaviour should be
-         * specifiable with an argument to this function.
-         */
-        mBegin = (T *)storage.addr();
-        mLength = aLength;
-        mCapacity = sInlineCapacity;
-        Impl::moveConstruct(mBegin, p, p + aLength);
-        Impl::destroy(p, p + aLength);
-        this->free_(p);
-    } else {
-        mBegin = p;
-        mLength = aLength;
-        mCapacity = aLength;
-    }
-#ifdef DEBUG
-    mReserved = aLength;
+  mReserved = aLength;
 #endif
 }
 
-template <class T, size_t N, class AP>
+template<typename T, size_t N, class AP, class TV>
 inline size_t
-Vector<T,N,AP>::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+VectorBase<T, N, AP, TV>::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return usingInlineStorage() ? 0 : mallocSizeOf(beginNoCheck());
 }
 
-template <class T, size_t N, class AP>
+template<typename T, size_t N, class AP, class TV>
 inline size_t
-Vector<T,N,AP>::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+VectorBase<T, N, AP, TV>::sizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
 {
     return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
 }
 
-template <class T, size_t N, class AP>
+template<typename T, size_t N, class AP, class TV>
 inline void
-Vector<T,N,AP>::swap(Vector &other)
+VectorBase<T, N, AP, TV>::swap(TV& other)
 {
-    MOZ_STATIC_ASSERT(N == 0,
-                      "still need to implement this for N != 0");
+  MOZ_STATIC_ASSERT(N == 0,
+                    "still need to implement this for N != 0");
 
-    // This only works when inline storage is always empty.
-    if (!usingInlineStorage() && other.usingInlineStorage()) {
-        other.mBegin = mBegin;
-        mBegin = inlineStorage();
-    } else if (usingInlineStorage() && !other.usingInlineStorage()) {
-        mBegin = other.mBegin;
-        other.mBegin = other.inlineStorage();
-    } else if (!usingInlineStorage() && !other.usingInlineStorage()) {
-        mozilla::Swap(mBegin, other.mBegin);
-    } else {
-        // This case is a no-op, since we'd set both to use their inline storage.
-    }
+  // This only works when inline storage is always empty.
+  if (!usingInlineStorage() && other.usingInlineStorage()) {
+    other.mBegin = mBegin;
+    mBegin = inlineStorage();
+  } else if (usingInlineStorage() && !other.usingInlineStorage()) {
+    mBegin = other.mBegin;
+    other.mBegin = other.inlineStorage();
+  } else if (!usingInlineStorage() && !other.usingInlineStorage()) {
+    Swap(mBegin, other.mBegin);
+  } else {
+    // This case is a no-op, since we'd set both to use their inline storage.
+  }
 
-    mozilla::Swap(mLength, other.mLength);
-    mozilla::Swap(mCapacity, other.mCapacity);
+  Swap(mLength, other.mLength);
+  Swap(mCapacity, other.mCapacity);
 #ifdef DEBUG
-    mozilla::Swap(mReserved, other.mReserved);
+  Swap(mReserved, other.mReserved);
 #endif
 }
 
-}  /* namespace js */
+/*
+ * 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:
+    Vector(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
+    Vector(mozilla::MoveRef<Vector> vec) : Base(vec) {}
+    Vector& operator=(mozilla::MoveRef<Vector> vec) {
+      return Base::operator=(vec);
+    }
+};
+
+} // namespace mozilla
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
-#endif /* js_Vector_h */
+#endif /* mozilla_Vector_h */
--- a/mfbt/exported_headers.mk
+++ b/mfbt/exported_headers.mk
@@ -46,10 +46,11 @@ EXPORTS_mozilla += \
   SplayTree.h \
   StandardInteger.h \
   TemplateLib.h \
   ThreadLocal.h \
   TypedEnum.h \
   Types.h \
   TypeTraits.h \
   Util.h \
+  Vector.h \
   WeakPtr.h \
   $(NULL)
--- a/widget/gonk/nsAppShell.cpp
+++ b/widget/gonk/nsAppShell.cpp
@@ -372,17 +372,17 @@ public:
     virtual void notifyMotion(const NotifyMotionArgs* args);
     virtual void notifySwitch(const NotifySwitchArgs* args);
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
 
     virtual int32_t injectInputEvent(const InputEvent* event,
             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
             uint32_t policyFlags);
 
-    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
+    virtual void setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles);
     virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
 
     virtual void setInputDispatchMode(bool enabled, bool frozen);
     virtual void setInputFilterEnabled(bool enabled) {}
     virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
             const sp<InputChannel>& toChannel) { return true; }
 
     virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
@@ -568,17 +568,17 @@ int32_t GeckoInputDispatcher::injectInpu
     const InputEvent* event,
     int32_t injectorPid, int32_t injectorUid, int32_t syncMode,
     int32_t timeoutMillis, uint32_t policyFlags)
 {
     return INPUT_EVENT_INJECTION_SUCCEEDED;
 }
 
 void
-GeckoInputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles)
+GeckoInputDispatcher::setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles)
 {
 }
 
 void
 GeckoInputDispatcher::setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle)
 {
 }