Bug 1280407 - Use SystemAllocPolicy rather that the default with mozilla::Vector in the JS engine r=sfink r=fitzgen r=jandem
☠☠ backed out by 0d735d33bd84 ☠ ☠
authorJon Coppeard <jcoppeard@mozilla.com>
Sat, 18 Jun 2016 10:46:13 +0100
changeset 302054 afc3c6a5f93a4e5b5309659a13a84e7ec5c8fb2e
parent 302053 c6f2a2408e4d4904ba5f0da56f2eb2f58e511672
child 302055 0d735d33bd844616bf224f3fabd56dd694cd03e9
push id19710
push usercbook@mozilla.com
push dateMon, 20 Jun 2016 11:52:48 +0000
treeherderfx-team@3c5025f98e56 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink, fitzgen, jandem
bugs1280407
milestone50.0a1
Bug 1280407 - Use SystemAllocPolicy rather that the default with mozilla::Vector in the JS engine r=sfink r=fitzgen r=jandem
js/public/UbiNode.h
js/public/UbiNodeDominatorTree.h
js/public/UbiNodeShortestPaths.h
js/src/builtin/TestingFunctions.cpp
js/src/gc/Statistics.cpp
js/src/jit-test/tests/gc/oomInByteSize.js
js/src/jit-test/tests/gc/oomInFindPath.js
js/src/jsapi-tests/testThreadingThread.cpp
js/src/jsapi.h
js/src/jsgc.cpp
js/src/vm/Stopwatch.cpp
js/src/vm/Stopwatch.h
js/src/vm/UbiNodeCensus.cpp
toolkit/components/perfmonitoring/nsPerformanceStats.cpp
toolkit/components/perfmonitoring/nsPerformanceStats.h
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -178,16 +178,19 @@ namespace JS {
 namespace ubi {
 
 using mozilla::Forward;
 using mozilla::Maybe;
 using mozilla::Move;
 using mozilla::RangedPtr;
 using mozilla::Variant;
 
+template <typename T>
+using Vector = mozilla::Vector<T, 0, js::SystemAllocPolicy>;
+
 /*** ubi::StackFrame ******************************************************************************/
 
 // Concrete JS::ubi::StackFrame instances backed by a live SavedFrame object
 // store their strings as JSAtom*, while deserialized stack frames from offline
 // heap snapshots store their strings as const char16_t*. In order to provide
 // zero-cost accessors to these strings in a single interface that works with
 // both cases, we use this variant type.
 class AtomOrTwoByteChars : public Variant<JSAtom*, const char16_t*> {
--- a/js/public/UbiNodeDominatorTree.h
+++ b/js/public/UbiNodeDominatorTree.h
@@ -89,20 +89,20 @@ class JS_PUBLIC_API(DominatorTree)
      * `DominatedSetRange`.
      *
      * @see JS::ubi::DominatorTree::getDominatedSet
      */
     class DominatedNodePtr
     {
         friend class DominatedSetRange;
 
-        const mozilla::Vector<Node>& postOrder;
+        const JS::ubi::Vector<Node>& postOrder;
         const uint32_t* ptr;
 
-        DominatedNodePtr(const mozilla::Vector<Node>& postOrder, const uint32_t* ptr)
+        DominatedNodePtr(const JS::ubi::Vector<Node>& postOrder, const uint32_t* ptr)
           : postOrder(postOrder)
           , ptr(ptr)
         { }
 
       public:
         bool operator!=(const DominatedNodePtr& rhs) const { return ptr != rhs.ptr; }
         void operator++() { ptr++; }
         const Node& operator*() const { return postOrder[*ptr]; }
@@ -113,21 +113,21 @@ class JS_PUBLIC_API(DominatorTree)
      * range-based for loops.
      *
      * @see JS::ubi::DominatorTree::getDominatedSet
      */
     class DominatedSetRange
     {
         friend class DominatedSets;
 
-        const mozilla::Vector<Node>& postOrder;
+        const JS::ubi::Vector<Node>& postOrder;
         const uint32_t* beginPtr;
         const uint32_t* endPtr;
 
-        DominatedSetRange(mozilla::Vector<Node>& postOrder, const uint32_t* begin, const uint32_t* end)
+        DominatedSetRange(JS::ubi::Vector<Node>& postOrder, const uint32_t* begin, const uint32_t* end)
           : postOrder(postOrder)
           , beginPtr(begin)
           , endPtr(end)
         {
             MOZ_ASSERT(begin <= end);
         }
 
       public:
@@ -174,20 +174,20 @@ class JS_PUBLIC_API(DominatorTree)
      * The set of all dominated sets in a dominator tree.
      *
      * Internally stores the sets in a contiguous array, with a side table of
      * indices into that contiguous array to denote the start index of each
      * individual set.
      */
     class DominatedSets
     {
-        mozilla::Vector<uint32_t> dominated;
-        mozilla::Vector<uint32_t> indices;
+        JS::ubi::Vector<uint32_t> dominated;
+        JS::ubi::Vector<uint32_t> indices;
 
-        DominatedSets(mozilla::Vector<uint32_t>&& dominated, mozilla::Vector<uint32_t>&& indices)
+        DominatedSets(JS::ubi::Vector<uint32_t>&& dominated, JS::ubi::Vector<uint32_t>&& indices)
           : dominated(mozilla::Move(dominated))
           , indices(mozilla::Move(indices))
         { }
 
       public:
         // DominatedSets is not copy-able.
         DominatedSets(const DominatedSets& rhs) = delete;
         DominatedSets& operator=(const DominatedSets& rhs) = delete;
@@ -205,17 +205,17 @@ class JS_PUBLIC_API(DominatorTree)
             return *this;
         }
 
         /**
          * Create the DominatedSets given the mapping of a node index to its
          * immediate dominator. Returns `Some` on success, `Nothing` on OOM
          * failure.
          */
-        static mozilla::Maybe<DominatedSets> Create(const mozilla::Vector<uint32_t>& doms) {
+        static mozilla::Maybe<DominatedSets> Create(const JS::ubi::Vector<uint32_t>& doms) {
             auto length = doms.length();
             MOZ_ASSERT(length < UINT32_MAX);
 
             // Create a vector `dominated` holding a flattened set of buckets of
             // immediately dominated children nodes, with a lookup table
             // `indices` mapping from each node to the beginning of its bucket.
             //
             // This has three phases:
@@ -230,18 +230,18 @@ class JS_PUBLIC_API(DominatorTree)
             //    bucket.
             //
             // 3. Iterate over the full set of nodes again, filling in bucket
             //    entries from the end of the bucket's range to its
             //    beginning. This decrements each index as a bucket entry is
             //    filled in. After having filled in all of a bucket's entries,
             //    the index points to the start of the bucket.
 
-            mozilla::Vector<uint32_t> dominated;
-            mozilla::Vector<uint32_t> indices;
+            JS::ubi::Vector<uint32_t> dominated;
+            JS::ubi::Vector<uint32_t> indices;
             if (!dominated.growBy(length) || !indices.growBy(length))
                 return mozilla::Nothing();
 
             // 1
             memset(indices.begin(), 0, length * sizeof(uint32_t));
             for (uint32_t i = 0; i < length; i++)
                 indices[doms[i]]++;
 
@@ -273,63 +273,63 @@ class JS_PUBLIC_API(DominatorTree)
 
             return mozilla::Some(DominatedSets(mozilla::Move(dominated), mozilla::Move(indices)));
         }
 
         /**
          * Get the set of nodes immediately dominated by the node at
          * `postOrder[nodeIndex]`.
          */
-        DominatedSetRange dominatedSet(mozilla::Vector<Node>& postOrder, uint32_t nodeIndex) const {
+        DominatedSetRange dominatedSet(JS::ubi::Vector<Node>& postOrder, uint32_t nodeIndex) const {
             MOZ_ASSERT(postOrder.length() == indices.length());
             MOZ_ASSERT(nodeIndex < indices.length());
             auto end = nodeIndex == indices.length() - 1
                 ? dominated.end()
                 : &dominated[indices[nodeIndex + 1]];
             return DominatedSetRange(postOrder, &dominated[indices[nodeIndex]], end);
         }
     };
 
   private:
     // Data members.
-    mozilla::Vector<Node> postOrder;
+    JS::ubi::Vector<Node> postOrder;
     NodeToIndexMap nodeToPostOrderIndex;
-    mozilla::Vector<uint32_t> doms;
+    JS::ubi::Vector<uint32_t> doms;
     DominatedSets dominatedSets;
-    mozilla::Maybe<mozilla::Vector<JS::ubi::Node::Size>> retainedSizes;
+    mozilla::Maybe<JS::ubi::Vector<JS::ubi::Node::Size>> retainedSizes;
 
   private:
     // We use `UNDEFINED` as a sentinel value in the `doms` vector to signal
     // that we haven't found any dominators for the node at the corresponding
     // index in `postOrder` yet.
     static const uint32_t UNDEFINED = UINT32_MAX;
 
-    DominatorTree(mozilla::Vector<Node>&& postOrder, NodeToIndexMap&& nodeToPostOrderIndex,
-                  mozilla::Vector<uint32_t>&& doms, DominatedSets&& dominatedSets)
+    DominatorTree(JS::ubi::Vector<Node>&& postOrder, NodeToIndexMap&& nodeToPostOrderIndex,
+                  JS::ubi::Vector<uint32_t>&& doms, DominatedSets&& dominatedSets)
         : postOrder(mozilla::Move(postOrder))
         , nodeToPostOrderIndex(mozilla::Move(nodeToPostOrderIndex))
         , doms(mozilla::Move(doms))
         , dominatedSets(mozilla::Move(dominatedSets))
         , retainedSizes(mozilla::Nothing())
     { }
 
-    static uint32_t intersect(mozilla::Vector<uint32_t>& doms, uint32_t finger1, uint32_t finger2) {
+    static uint32_t intersect(JS::ubi::Vector<uint32_t>& doms, uint32_t finger1, uint32_t finger2) {
         while (finger1 != finger2) {
             if (finger1 < finger2)
                 finger1 = doms[finger1];
             else if (finger2 < finger1)
                 finger2 = doms[finger2];
         }
         return finger1;
     }
 
     // Do the post order traversal of the heap graph and populate our
     // predecessor sets.
     static MOZ_MUST_USE bool doTraversal(JSRuntime* rt, AutoCheckCannotGC& noGC, const Node& root,
-                                         mozilla::Vector<Node>& postOrder,
+                                         JS::ubi::Vector<Node>& postOrder,
                                          PredecessorSets& predecessorSets) {
         uint32_t nodeCount = 0;
         auto onNode = [&](const Node& node) {
             nodeCount++;
             if (MOZ_UNLIKELY(nodeCount == UINT32_MAX))
                 return false;
             return postOrder.append(node);
         };
@@ -352,36 +352,36 @@ class JS_PUBLIC_API(DominatorTree)
         PostOrder traversal(rt, noGC);
         return traversal.init() &&
                traversal.addStart(root) &&
                traversal.traverse(onNode, onEdge);
     }
 
     // Populates the given `map` with an entry for each node to its index in
     // `postOrder`.
-    static MOZ_MUST_USE bool mapNodesToTheirIndices(mozilla::Vector<Node>& postOrder,
+    static MOZ_MUST_USE bool mapNodesToTheirIndices(JS::ubi::Vector<Node>& postOrder,
                                                     NodeToIndexMap& map) {
         MOZ_ASSERT(!map.initialized());
         MOZ_ASSERT(postOrder.length() < UINT32_MAX);
         uint32_t length = postOrder.length();
         if (!map.init(length))
             return false;
         for (uint32_t i = 0; i < length; i++)
             map.putNewInfallible(postOrder[i], i);
         return true;
     }
 
     // Convert the Node -> NodeSet predecessorSets to a index -> Vector<index>
     // form.
     static MOZ_MUST_USE bool convertPredecessorSetsToVectors(
         const Node& root,
-        mozilla::Vector<Node>& postOrder,
+        JS::ubi::Vector<Node>& postOrder,
         PredecessorSets& predecessorSets,
         NodeToIndexMap& nodeToPostOrderIndex,
-        mozilla::Vector<mozilla::Vector<uint32_t>>& predecessorVectors)
+        JS::ubi::Vector<JS::ubi::Vector<uint32_t>>& predecessorVectors)
     {
         MOZ_ASSERT(postOrder.length() < UINT32_MAX);
         uint32_t length = postOrder.length();
 
         MOZ_ASSERT(predecessorVectors.length() == 0);
         if (!predecessorVectors.growBy(length))
             return false;
 
@@ -405,17 +405,17 @@ class JS_PUBLIC_API(DominatorTree)
             }
         }
         predecessorSets.finish();
         return true;
     }
 
     // Initialize `doms` such that the immediate dominator of the `root` is the
     // `root` itself and all others are `UNDEFINED`.
-    static MOZ_MUST_USE bool initializeDominators(mozilla::Vector<uint32_t>& doms,
+    static MOZ_MUST_USE bool initializeDominators(JS::ubi::Vector<uint32_t>& doms,
                                                   uint32_t length) {
         MOZ_ASSERT(doms.length() == 0);
         if (!doms.growByUninitialized(length))
             return false;
         doms[length - 1] = length - 1;
         for (uint32_t i = 0; i < length - 1; i++)
             doms[i] = UNDEFINED;
         return true;
@@ -509,17 +509,17 @@ class JS_PUBLIC_API(DominatorTree)
      * that embedders with knowledge of the graph's implementation will do the
      * Right Thing.
      *
      * Returns `mozilla::Nothing()` on OOM failure. It is the caller's
      * responsibility to handle and report the OOM.
      */
     static mozilla::Maybe<DominatorTree>
     Create(JSRuntime* rt, AutoCheckCannotGC& noGC, const Node& root) {
-        mozilla::Vector<Node> postOrder;
+        JS::ubi::Vector<Node> postOrder;
         PredecessorSets predecessorSets;
         if (!predecessorSets.init() || !doTraversal(rt, noGC, root, postOrder, predecessorSets))
             return mozilla::Nothing();
 
         MOZ_ASSERT(postOrder.length() < UINT32_MAX);
         uint32_t length = postOrder.length();
         MOZ_ASSERT(postOrder[length - 1] == root);
 
@@ -528,22 +528,22 @@ class JS_PUBLIC_API(DominatorTree)
         // possible. This greatly improves the performance of this
         // implementation, but we have to pay a little bit of upfront cost to
         // convert our data structures to play along first.
 
         NodeToIndexMap nodeToPostOrderIndex;
         if (!mapNodesToTheirIndices(postOrder, nodeToPostOrderIndex))
             return mozilla::Nothing();
 
-        mozilla::Vector<mozilla::Vector<uint32_t>> predecessorVectors;
+        JS::ubi::Vector<JS::ubi::Vector<uint32_t>> predecessorVectors;
         if (!convertPredecessorSetsToVectors(root, postOrder, predecessorSets, nodeToPostOrderIndex,
                                              predecessorVectors))
             return mozilla::Nothing();
 
-        mozilla::Vector<uint32_t> doms;
+        JS::ubi::Vector<uint32_t> doms;
         if (!initializeDominators(doms, length))
             return mozilla::Nothing();
 
         bool changed = true;
         while (changed) {
             changed = false;
 
             // Iterate over the non-root nodes in reverse post order.
--- a/js/public/UbiNodeShortestPaths.h
+++ b/js/public/UbiNodeShortestPaths.h
@@ -64,29 +64,29 @@ struct JS_PUBLIC_API(BackEdge)
     EdgeName& name() { return name_; }
 
     const JS::ubi::Node& predecessor() const { return predecessor_; }
 };
 
 /**
  * A path is a series of back edges from which we discovered a target node.
  */
-using Path = mozilla::Vector<BackEdge*>;
+using Path = JS::ubi::Vector<BackEdge*>;
 
 /**
  * The `JS::ubi::ShortestPaths` type represents a collection of up to N shortest
  * retaining paths for each of a target set of nodes, starting from the same
  * root node.
  */
 struct JS_PUBLIC_API(ShortestPaths)
 {
   private:
     // Types, type aliases, and data members.
 
-    using BackEdgeVector = mozilla::Vector<BackEdge::Ptr>;
+    using BackEdgeVector = JS::ubi::Vector<BackEdge::Ptr>;
     using NodeToBackEdgeVectorMap = js::HashMap<Node, BackEdgeVector, js::DefaultHasher<Node>,
                                                 js::SystemAllocPolicy>;
 
     struct Handler;
     using Traversal = BreadthFirst<Handler>;
 
     /**
      * A `JS::ubi::BreadthFirst` traversal handler that records back edges for
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2657,21 +2657,26 @@ FindPath(JSContext* cx, unsigned argc, V
         // We can't tolerate the GC moving things around while we're searching
         // the heap. Check that nothing we do causes a GC.
         JS::AutoCheckCannotGC autoCannotGC;
 
         JS::ubi::Node start(args[0]), target(args[1]);
 
         heaptools::FindPathHandler handler(cx, start, target, &nodes, edges);
         heaptools::FindPathHandler::Traversal traversal(cx->runtime(), handler, autoCannotGC);
-        if (!traversal.init() || !traversal.addStart(start))
+        if (!traversal.init() || !traversal.addStart(start)) {
+            ReportOutOfMemory(cx);
             return false;
-
-        if (!traversal.traverse())
+        }
+
+        if (!traversal.traverse()) {
+            if (!cx->isExceptionPending())
+                ReportOutOfMemory(cx);
             return false;
+        }
 
         if (!handler.foundPath) {
             // We didn't find any paths from the start to the target.
             args.rval().setUndefined();
             return true;
         }
     }
 
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -189,23 +189,23 @@ static const PhaseInfo phases[] = {
     // numbers.
 };
 
 static ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } };
 
 // Mapping from all nodes with a multi-parented child to a Vector of all
 // multi-parented children and their descendants. (Single-parented children will
 // not show up in this list.)
-static mozilla::Vector<Phase> dagDescendants[Statistics::NumTimingArrays];
+static mozilla::Vector<Phase, 0, SystemAllocPolicy> dagDescendants[Statistics::NumTimingArrays];
 
 struct AllPhaseIterator {
     int current;
     int baseLevel;
     size_t activeSlot;
-    mozilla::Vector<Phase>::Range descendants;
+    mozilla::Vector<Phase, 0, SystemAllocPolicy>::Range descendants;
 
     explicit AllPhaseIterator(const Statistics::PhaseTimeTable table)
       : current(0)
       , baseLevel(0)
       , activeSlot(PHASE_DAG_NONE)
       , descendants(dagDescendants[PHASE_DAG_NONE].all()) /* empty range */
     {
     }
@@ -824,17 +824,17 @@ Statistics::initialize()
                 return false;
             j++;
         } while (j != PHASE_LIMIT && phases[j].parent != PHASE_MULTI_PARENTS);
     }
     MOZ_ASSERT(dagSlot <= MaxMultiparentPhases - 1);
 
     // Fill in the depth of each node in the tree. Multi-parented nodes
     // have depth 0.
-    mozilla::Vector<Phase> stack;
+    mozilla::Vector<Phase, 0, SystemAllocPolicy> stack;
     if (!stack.append(PHASE_LIMIT)) // Dummy entry to avoid special-casing the first node
         return false;
     for (int i = 0; i < PHASE_LIMIT; i++) {
         if (phases[i].parent == PHASE_NO_PARENT ||
             phases[i].parent == PHASE_MULTI_PARENTS)
         {
             stack.clear();
         } else {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/oomInByteSize.js
@@ -0,0 +1,19 @@
+if (!('oomTest' in this))
+    quit();
+
+oomTest(() => byteSize({}));
+oomTest(() => byteSize({ w: 1, x: 2, y: 3 }));
+oomTest(() => byteSize({ w:1, x:2, y:3, z:4, a:6, 0:0, 1:1, 2:2 }));
+oomTest(() => byteSize([1, 2, 3]));
+oomTest(() => byteSize(function () {}));
+
+function f1() {
+  return 42;
+}
+oomTest(() => byteSizeOfScript(f1));
+
+oomTest(() => byteSize("1234567"));
+oomTest(() => byteSize("千早ぶる神代"));
+
+let s = Symbol();
+oomTest(() => byteSize(s));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/oomInFindPath.js
@@ -0,0 +1,19 @@
+if (!('oomTest' in this))
+    quit();
+
+var o = { w: { x: { y: { z: {} } } } };
+oomTest(() => findPath(o, o.w.x.y.z));
+
+var a = [ , o ];
+oomTest(() => findPath(a, o));
+
+function C() {}
+C.prototype.obj = {};
+var c = new C;
+
+oomTest(() => findPath(c, c.obj));
+
+function f(x) { return function g(y) { return x+y; }; }
+var o = {}
+var gc = f(o);
+oomTest(() => findPath(gc, o));
--- a/js/src/jsapi-tests/testThreadingThread.cpp
+++ b/js/src/jsapi-tests/testThreadingThread.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * 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/. */
 
+#include "jsalloc.h"
+
 #include "mozilla/Atomics.h"
 #include "mozilla/IntegerRange.h"
 #include "mozilla/Move.h"
 #include "mozilla/Vector.h"
 #include "jsapi-tests/tests.h"
 #include "threading/Thread.h"
 
 BEGIN_TEST(testThreadingThreadJoin)
@@ -57,17 +59,17 @@ BEGIN_TEST(testThreadingThreadId)
     return true;
 }
 END_TEST(testThreadingThreadId)
 
 BEGIN_TEST(testThreadingThreadVectorMoveConstruct)
 {
     const static size_t N = 10;
     mozilla::Atomic<int> count(0);
-    mozilla::Vector<js::Thread> v;
+    mozilla::Vector<js::Thread, 0, js::SystemAllocPolicy> v;
     for (auto i : mozilla::MakeRange(N)) {
         CHECK(v.emplaceBack([](mozilla::Atomic<int>* countp){(*countp)++;}, &count));
         CHECK(v.length() == i + 1);
     }
     for (auto& th : v)
         th.join();
     CHECK(count == 10);
     return true;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -6145,16 +6145,18 @@ struct PerformanceGroup {
 
   public:
     // Compatibility with RefPtr<>
     void AddRef();
     void Release();
     uint64_t refCount_;
 };
 
+using PerformanceGroupVector = mozilla::Vector<RefPtr<js::PerformanceGroup>, 0, SystemAllocPolicy>;
+
 /**
  * Commit any Performance Monitoring data.
  *
  * Until `FlushMonitoring` has been called, all PerformanceMonitoring data is invisible
  * to the outside world and can cancelled with a call to `ResetMonitoring`.
  */
 extern JS_PUBLIC_API(bool)
 FlushPerformanceMonitoring(JSRuntime*);
@@ -6203,21 +6205,21 @@ extern JS_PUBLIC_API(void)
 AddCPOWPerformanceDelta(JSRuntime*, uint64_t delta);
 
 typedef bool
 (*StopwatchStartCallback)(uint64_t, void*);
 extern JS_PUBLIC_API(bool)
 SetStopwatchStartCallback(JSRuntime*, StopwatchStartCallback, void*);
 
 typedef bool
-(*StopwatchCommitCallback)(uint64_t, mozilla::Vector<RefPtr<PerformanceGroup>>&, void*);
+(*StopwatchCommitCallback)(uint64_t, PerformanceGroupVector&, void*);
 extern JS_PUBLIC_API(bool)
 SetStopwatchCommitCallback(JSRuntime*, StopwatchCommitCallback, void*);
 
 typedef bool
-(*GetGroupsCallback)(JSContext*, mozilla::Vector<RefPtr<PerformanceGroup>>&, void*);
+(*GetGroupsCallback)(JSContext*, PerformanceGroupVector&, void*);
 extern JS_PUBLIC_API(bool)
 SetGetPerformanceGroupsCallback(JSRuntime*, GetGroupsCallback, void*);
 
 } /* namespace js */
 
 
 #endif /* jsapi_h */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -967,17 +967,17 @@ GCRuntime::setNextScheduled(uint32_t cou
     nextScheduled = count;
 }
 
 bool
 GCRuntime::parseAndSetZeal(const char* str)
 {
     int frequency = -1;
     bool foundFrequency = false;
-    mozilla::Vector<int> zeals;
+    mozilla::Vector<int, 0, SystemAllocPolicy> zeals;
 
     static const struct {
         const char* const zealMode;
         size_t length;
         uint32_t zeal;
     } zealModes[] = {
 #define ZEAL_MODE(name, value) {#name, sizeof(#name) - 1, value},
         JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
@@ -2638,18 +2638,19 @@ GCRuntime::releaseRelocatedArenasWithout
 // Sometimes protect them instead and hold onto them until the next GC sweep
 // phase to catch any pointers to them that didn't get forwarded.
 
 void
 GCRuntime::releaseHeldRelocatedArenas()
 {
 #ifdef DEBUG
     unprotectHeldRelocatedArenas();
-    releaseRelocatedArenas(relocatedArenasToRelease);
+    Arena* arenas = relocatedArenasToRelease;
     relocatedArenasToRelease = nullptr;
+    releaseRelocatedArenas(arenas);
 #endif
 }
 
 void
 GCRuntime::releaseHeldRelocatedArenasWithoutUnlocking(const AutoLockGC& lock)
 {
 #ifdef DEBUG
     unprotectHeldRelocatedArenas();
@@ -3129,17 +3130,17 @@ GCRuntime::decommitArenas(AutoLockGC& lo
 {
     // Verify that all entries in the empty chunks pool are decommitted.
     for (ChunkPool::Iter chunk(emptyChunks(lock)); !chunk.done(); chunk.next())
         MOZ_ASSERT(!chunk->info.numArenasFreeCommitted);
 
     // Build a Vector of all current available Chunks. Since we release the
     // gc lock while doing the decommit syscall, it is dangerous to iterate
     // the available list directly, as concurrent operations can modify it.
-    mozilla::Vector<Chunk*> toDecommit;
+    mozilla::Vector<Chunk*, 0, SystemAllocPolicy> toDecommit;
     MOZ_ASSERT(availableChunks(lock).verify());
     for (ChunkPool::Iter iter(availableChunks(lock)); !iter.done(); iter.next()) {
         if (!toDecommit.append(iter.get())) {
             // The OOM handler does a full, immediate decommit, so there is
             // nothing more to do here in any case.
             return onOutOfMallocMemory(lock);
         }
     }
--- a/js/src/vm/Stopwatch.cpp
+++ b/js/src/vm/Stopwatch.cpp
@@ -147,17 +147,17 @@ PerformanceMonitoring::commit()
         return true;
     }
 
     if (startedAtIteration_ != iteration_) {
         // No JS code has been monitored during this iteration.
         return true;
     }
 
-    GroupVector recentGroups;
+    PerformanceGroupVector recentGroups;
     recentGroups_.swap(recentGroups);
 
     bool success = true;
     if (stopwatchCommitCallback)
         success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure);
 
     // Reset immediately, to make sure that we're not hit by the end
     // of a nested event loop (which would cause `commit` to be called
@@ -195,17 +195,17 @@ PerformanceGroupHolder::~PerformanceGrou
 
 void
 PerformanceGroupHolder::unlink()
 {
     initialized_ = false;
     groups_.clear();
 }
 
-const GroupVector*
+const PerformanceGroupVector*
 PerformanceGroupHolder::getGroups(JSContext* cx)
 {
     if (initialized_)
         return &groups_;
 
     if (!runtime_->performanceMonitoring.getGroupsCallback)
         return nullptr;
 
@@ -228,17 +228,17 @@ AutoStopwatch::AutoStopwatch(JSContext* 
 
     JSCompartment* compartment = cx_->compartment();
     if (compartment->scheduledForDestruction)
         return;
 
     JSRuntime* runtime = cx_->runtime();
     iteration_ = runtime->performanceMonitoring.iteration();
 
-    const GroupVector* groups = compartment->performanceMonitoring.getGroups(cx);
+    const PerformanceGroupVector* groups = compartment->performanceMonitoring.getGroups(cx);
     if (!groups) {
       // Either the embedding has not provided any performance
       // monitoring logistics or there was an error that prevents
       // performance monitoring.
       return;
     }
     for (auto group = groups->begin(); group < groups->end(); group++) {
       auto acquired = acquireGroup(*group);
--- a/js/src/vm/Stopwatch.h
+++ b/js/src/vm/Stopwatch.h
@@ -14,18 +14,16 @@
 
 /*
   An API for following in real-time the amount of CPU spent executing
   webpages, add-ons, etc.
 */
 
 namespace js {
 
-typedef mozilla::Vector<RefPtr<js::PerformanceGroup>> GroupVector;
-
 /**
  * A container for performance groups.
  *
  * Performance monitoring deals with the execution duration of code
  * that belongs to components, for a notion of components defined by
  * the embedding.  Typically, in a web browser, a component may be a
  * webpage and/or a frame and/or a module and/or an add-on and/or a
  * sandbox and/or a process etc.
@@ -38,33 +36,33 @@ struct PerformanceGroupHolder {
     /**
      * Get the groups to which this compartment belongs.
      *
      * Pre-condition: Execution must have entered the compartment.
      *
      * May return `nullptr` if the embedding has not initialized
      * support for performance groups.
      */
-    const GroupVector* getGroups(JSContext*);
+    const PerformanceGroupVector* getGroups(JSContext*);
 
     explicit PerformanceGroupHolder(JSRuntime* runtime)
       : runtime_(runtime)
       , initialized_(false)
     {  }
     ~PerformanceGroupHolder();
     void unlink();
   private:
     JSRuntime* runtime_;
 
     // `true` once a call to `getGroups` has succeeded.
     bool initialized_;
 
     // The groups to which this compartment belongs. Filled if and only
     // if `initialized_` is `true`.
-    GroupVector groups_;
+    PerformanceGroupVector groups_;
 };
 
 /**
  * Container class for everything related to performance monitoring.
  */
 struct PerformanceMonitoring {
     /**
      * The number of the current iteration of the event loop.
@@ -287,17 +285,17 @@ struct PerformanceMonitoring {
      * during the same event loop and to avoid committing stale
      * stopwatch results.
      */
     uint64_t startedAtIteration_;
 
     /**
      * Groups used in the current iteration.
      */
-    GroupVector recentGroups_;
+    PerformanceGroupVector recentGroups_;
 
     /**
      * The highest value of the timestamp counter encountered
      * during this iteration.
      */
     uint64_t highestTimestampCounter_;
 };
 
@@ -339,17 +337,17 @@ class AutoStopwatch final {
     // Timestamps captured while starting the stopwatch.
     uint64_t cyclesStart_;
     uint64_t CPOWTimeStart_;
 
     // The CPU on which we started the measure. Defined only
     // if `isMonitoringJank_` is `true`.
     cpuid_t cpuStart_;
 
-    mozilla::Vector<RefPtr<js::PerformanceGroup>> groups_;
+    PerformanceGroupVector groups_;
 
   public:
     // If the stopwatch is active, constructing an instance of
     // AutoStopwatch causes it to become the current owner of the
     // stopwatch.
     //
     // Previous owner is restored upon destruction.
     explicit AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
--- a/js/src/vm/UbiNodeCensus.cpp
+++ b/js/src/vm/UbiNodeCensus.cpp
@@ -122,17 +122,17 @@ SimpleCount::report(JSContext* cx, Count
     return true;
 }
 
 
 // A count type that collects all matching nodes in a bucket.
 class BucketCount : public CountType {
 
     struct Count : CountBase {
-        mozilla::Vector<JS::ubi::Node::Id> ids_;
+        JS::ubi::Vector<JS::ubi::Node::Id> ids_;
 
         explicit Count(BucketCount& count)
           : CountBase(count),
             ids_()
         { }
     };
 
   public:
@@ -344,17 +344,17 @@ using CStringCountMap = HashMap<const ch
 // `const char*`.
 template <class Map, class GetName>
 static PlainObject*
 countMapToObject(JSContext* cx, Map& map, GetName getName) {
     // Build a vector of pointers to entries; sort by total; and then use
     // that to build the result object. This makes the ordering of entries
     // more interesting, and a little less non-deterministic.
 
-    mozilla::Vector<typename Map::Entry*> entries;
+    JS::ubi::Vector<typename Map::Entry*> entries;
     if (!entries.reserve(map.count())) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     for (auto r = map.all(); !r.empty(); r.popFront())
         entries.infallibleAppend(&r.front());
 
@@ -565,17 +565,17 @@ ByUbinodeType::count(CountBase& countBas
 bool
 ByUbinodeType::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
 {
     Count& count = static_cast<Count&>(countBase);
 
     // Build a vector of pointers to entries; sort by total; and then use
     // that to build the result object. This makes the ordering of entries
     // more interesting, and a little less non-deterministic.
-    mozilla::Vector<Entry*> entries;
+    JS::ubi::Vector<Entry*> entries;
     if (!entries.reserve(count.table.count()))
         return false;
     for (Table::Range r = count.table.all(); !r.empty(); r.popFront())
         entries.infallibleAppend(&r.front());
     qsort(entries.begin(), entries.length(), sizeof(*entries.begin()), compareEntries<Entry>);
 
     // Now build the result by iterating over the sorted vector.
     RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
@@ -731,17 +731,17 @@ ByAllocationStack::report(JSContext* cx,
 #ifdef DEBUG
     // Check that nothing rehashes our table while we hold pointers into it.
     Generation generation = count.table.generation();
 #endif
 
     // Build a vector of pointers to entries; sort by total; and then use
     // that to build the result object. This makes the ordering of entries
     // more interesting, and a little less non-deterministic.
-    mozilla::Vector<Entry*> entries;
+    JS::ubi::Vector<Entry*> entries;
     if (!entries.reserve(count.table.count()))
         return false;
     for (Table::Range r = count.table.all(); !r.empty(); r.popFront())
         entries.infallibleAppend(&r.front());
     qsort(entries.begin(), entries.length(), sizeof(*entries.begin()), compareEntries<Entry>);
 
     // Now build the result by iterating over the sorted vector.
     Rooted<MapObject*> map(cx, MapObject::create(cx));
--- a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
+++ b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
@@ -1022,23 +1022,28 @@ nsPerformanceStatsService::GetSnapshot(J
 }
 
 uint64_t
 nsPerformanceStatsService::GetNextId() {
   return ++mUIdCounter;
 }
 
 /* static*/ bool
-nsPerformanceStatsService::GetPerformanceGroupsCallback(JSContext* cx, JSGroupVector& out, void* closure) {
+nsPerformanceStatsService::GetPerformanceGroupsCallback(JSContext* cx,
+                                                        js::PerformanceGroupVector& out,
+                                                        void* closure)
+{
   RefPtr<nsPerformanceStatsService> self = reinterpret_cast<nsPerformanceStatsService*>(closure);
   return self->GetPerformanceGroups(cx, out);
 }
 
 bool
-nsPerformanceStatsService::GetPerformanceGroups(JSContext* cx, JSGroupVector& out) {
+nsPerformanceStatsService::GetPerformanceGroups(JSContext* cx,
+                                                js::PerformanceGroupVector& out)
+{
   JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
   if (!global) {
     // While it is possible for a compartment to have no global
     // (e.g. atoms), this compartment is not very interesting for us.
     return true;
   }
 
   // All compartments belong to the top group.
@@ -1131,23 +1136,27 @@ nsPerformanceStatsService::StopwatchStar
   if (NS_FAILED(rv)) {
     return false;
   }
 
   return true;
 }
 
 /*static*/ bool
-nsPerformanceStatsService::StopwatchCommitCallback(uint64_t iteration, JSGroupVector& recentGroups, void* closure) {
+nsPerformanceStatsService::StopwatchCommitCallback(uint64_t iteration,
+                                                   js::PerformanceGroupVector& recentGroups,
+                                                   void* closure)
+{
   RefPtr<nsPerformanceStatsService> self = reinterpret_cast<nsPerformanceStatsService*>(closure);
   return self->StopwatchCommit(iteration, recentGroups);
 }
 
 bool
-nsPerformanceStatsService::StopwatchCommit(uint64_t iteration, JSGroupVector& recentGroups)
+nsPerformanceStatsService::StopwatchCommit(uint64_t iteration,
+                                           js::PerformanceGroupVector& recentGroups)
 {
   MOZ_ASSERT(iteration == mIteration);
   MOZ_ASSERT(!recentGroups.empty());
 
   uint64_t userTimeStop, systemTimeStop;
   nsresult rv = GetResources(&userTimeStop, &systemTimeStop);
   if (NS_FAILED(rv)) {
     return false;
--- a/toolkit/components/perfmonitoring/nsPerformanceStats.h
+++ b/toolkit/components/perfmonitoring/nsPerformanceStats.h
@@ -14,17 +14,16 @@
 #include "nsIObserver.h"
 #include "nsPIDOMWindow.h"
 
 #include "nsIPerformanceStats.h"
 
 class nsPerformanceGroup;
 class nsPerformanceGroupDetails;
 
-typedef mozilla::Vector<RefPtr<js::PerformanceGroup>> JSGroupVector;
 typedef mozilla::Vector<RefPtr<nsPerformanceGroup>> GroupVector;
 
 /**
  * A data structure for registering observers interested in
  * performance alerts.
  *
  * Each performance group owns a single instance of this class.
  * Additionally, the service owns instances designed to observe the
@@ -187,18 +186,18 @@ protected:
    * - the compartment's own group.
    *
    * Pre-condition: the VM must have entered the JS compartment.
    *
    * The caller is expected to cache the results of this method, as
    * calling it more than once may not return the same instances of
    * performance groups.
    */
-  bool GetPerformanceGroups(JSContext* cx, JSGroupVector&);
-  static bool GetPerformanceGroupsCallback(JSContext* cx, JSGroupVector&, void* closure);
+  bool GetPerformanceGroups(JSContext* cx, js::PerformanceGroupVector&);
+  static bool GetPerformanceGroupsCallback(JSContext* cx, js::PerformanceGroupVector&, void* closure);
 
 
 
   /**********************************************************
    *
    * Sets of all performance groups, indexed by several keys.
    *
    * These sets do not keep the performance groups alive. Rather, a
@@ -324,18 +323,20 @@ protected:
    * measurement on outer loops is silently cancelled without any call
    * to this method.
    *
    * @param iteration The number of times we have started executing
    * JavaScript code.
    * @param recentGroups The groups that have seen activity during this
    * event.
    */
-  static bool StopwatchCommitCallback(uint64_t iteration, JSGroupVector& recentGroups, void* closure);
-  bool StopwatchCommit(uint64_t iteration, JSGroupVector& recentGroups);
+  static bool StopwatchCommitCallback(uint64_t iteration,
+                                      js::PerformanceGroupVector& recentGroups,
+                                      void* closure);
+  bool StopwatchCommit(uint64_t iteration, js::PerformanceGroupVector& recentGroups);
 
   /**
    * The number of times we have started executing JavaScript code.
    */
   uint64_t mIteration;
 
   /**
    * Commit performance measures of a single group.