Bug 1520104 - Using Vector instead of nsTArray - r=mstange
authorGerald Squelart <gsquelart@mozilla.com>
Mon, 29 Apr 2019 11:41:52 +0000
changeset 530542 97e259a4216f1565226bc354b6e9ba149c1fbc7c
parent 530541 37ac8c86f3c7b4adc96ec62346e5677b14ce4f9d
child 530543 85c36e78141e9c57b7e4edf9a0f45a2dedeaf584
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1520104
milestone68.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 1520104 - Using Vector instead of nsTArray - r=mstange Moving to non-XPCOM data structures, to help with upcoming transfer to mozglue. Differential Revision: https://phabricator.services.mozilla.com/D24697
tools/profiler/core/ProfileBufferEntry.cpp
tools/profiler/core/ProfileBufferEntry.h
tools/profiler/core/platform.cpp
tools/profiler/core/platform.h
tools/profiler/gecko/nsProfiler.cpp
tools/profiler/gecko/nsProfiler.h
tools/profiler/gecko/nsProfilerStartParams.cpp
tools/profiler/gecko/nsProfilerStartParams.h
--- a/tools/profiler/core/ProfileBufferEntry.cpp
+++ b/tools/profiler/core/ProfileBufferEntry.cpp
@@ -322,40 +322,50 @@ uint32_t JITFrameInfoForBufferRange::JIT
 
 bool JITFrameInfoForBufferRange::JITFrameKey::operator==(
     const JITFrameKey& aOther) const {
   return mCanonicalAddress == aOther.mCanonicalAddress &&
          mDepth == aOther.mDepth;
 }
 
 template <class KeyClass, class T>
+void CopyVectorHashtable(nsClassHashtable<KeyClass, Vector<T>>& aDest,
+                         const nsClassHashtable<KeyClass, Vector<T>>& aSrc) {
+  for (auto iter = aSrc.ConstIter(); !iter.Done(); iter.Next()) {
+    const Vector<T>& objRef = *iter.Data();
+    Vector<T>& destRef = *aDest.LookupOrAdd(iter.Key());
+    MOZ_RELEASE_ASSERT(destRef.appendAll(objRef));
+  }
+}
+
+template <class KeyClass, class T>
 void CopyClassHashtable(nsClassHashtable<KeyClass, T>& aDest,
                         const nsClassHashtable<KeyClass, T>& aSrc) {
   for (auto iter = aSrc.ConstIter(); !iter.Done(); iter.Next()) {
     const T& objRef = *iter.Data();
     aDest.LookupOrAdd(iter.Key(), objRef);
   }
 }
 
 JITFrameInfoForBufferRange JITFrameInfoForBufferRange::Clone() const {
-  nsClassHashtable<nsPtrHashKey<void>, nsTArray<JITFrameKey>>
+  nsClassHashtable<nsPtrHashKey<void>, Vector<JITFrameKey>>
       jitAddressToJITFramesMap;
   nsClassHashtable<nsGenericHashKey<JITFrameKey>, nsCString>
       jitFrameToFrameJSONMap;
-  CopyClassHashtable(jitAddressToJITFramesMap, mJITAddressToJITFramesMap);
+  CopyVectorHashtable(jitAddressToJITFramesMap, mJITAddressToJITFramesMap);
   CopyClassHashtable(jitFrameToFrameJSONMap, mJITFrameToFrameJSONMap);
   return JITFrameInfoForBufferRange{mRangeStart, mRangeEnd,
                                     std::move(jitAddressToJITFramesMap),
                                     std::move(jitFrameToFrameJSONMap)};
 }
 
 JITFrameInfo::JITFrameInfo(const JITFrameInfo& aOther)
     : mUniqueStrings(MakeUnique<UniqueJSONStrings>(*aOther.mUniqueStrings)) {
   for (const JITFrameInfoForBufferRange& range : aOther.mRanges) {
-    mRanges.AppendElement(range.Clone());
+    MOZ_RELEASE_ASSERT(mRanges.append(range.Clone()));
   }
 }
 
 bool UniqueStacks::FrameKey::NormalFrameData::operator==(
     const NormalFrameData& aOther) const {
   return mLocation == aOther.mLocation &&
          mRelevantForJS == aOther.mRelevantForJS && mLine == aOther.mLine &&
          mColumn == aOther.mColumn && mCategoryPair == aOther.mCategoryPair;
@@ -423,55 +433,58 @@ struct PositionInRangeComparator final {
     return aRange.mRangeStart <= aPos && aPos < aRange.mRangeEnd;
   }
 
   bool LessThan(const RangeT& aRange, PosT aPos) const {
     return aRange.mRangeEnd <= aPos;
   }
 };
 
-Maybe<nsTArray<UniqueStacks::FrameKey>>
+Maybe<Vector<UniqueStacks::FrameKey>>
 UniqueStacks::LookupFramesForJITAddressFromBufferPos(void* aJITAddress,
                                                      uint64_t aBufferPos) {
-  size_t rangeIndex = mJITInfoRanges.BinaryIndexOf(
-      aBufferPos,
-      PositionInRangeComparator<JITFrameInfoForBufferRange, uint64_t>());
+  JITFrameInfoForBufferRange* rangeIter =
+      std::lower_bound(mJITInfoRanges.begin(), mJITInfoRanges.end(), aBufferPos,
+                       [](const JITFrameInfoForBufferRange& aRange,
+                          uint64_t aPos) { return aRange.mRangeEnd < aPos; });
   MOZ_RELEASE_ASSERT(
-      rangeIndex != mJITInfoRanges.NoIndex,
+      rangeIter != mJITInfoRanges.end() &&
+          rangeIter->mRangeStart <= aBufferPos &&
+          aBufferPos < rangeIter->mRangeEnd,
       "Buffer position of jit address needs to be in one of the ranges");
 
   using JITFrameKey = JITFrameInfoForBufferRange::JITFrameKey;
 
-  const JITFrameInfoForBufferRange& jitFrameInfoRange =
-      mJITInfoRanges[rangeIndex];
-  const nsTArray<JITFrameKey>* jitFrameKeys =
+  const JITFrameInfoForBufferRange& jitFrameInfoRange = *rangeIter;
+  const Vector<JITFrameKey>* jitFrameKeys =
       jitFrameInfoRange.mJITAddressToJITFramesMap.Get(aJITAddress);
   if (!jitFrameKeys) {
     return Nothing();
   }
 
   // Map the array of JITFrameKeys to an array of FrameKeys, and ensure that
   // each of the FrameKeys exists in mFrameToIndexMap.
-  nsTArray<FrameKey> frameKeys;
+  Vector<FrameKey> frameKeys;
+  MOZ_RELEASE_ASSERT(frameKeys.initCapacity(jitFrameKeys->length()));
   for (const JITFrameKey& jitFrameKey : *jitFrameKeys) {
     FrameKey frameKey(jitFrameKey.mCanonicalAddress, jitFrameKey.mDepth,
-                      rangeIndex);
+                      rangeIter - mJITInfoRanges.begin());
     uint32_t index = mFrameToIndexMap.Count();
     auto entry = mFrameToIndexMap.LookupForAdd(frameKey);
     if (!entry) {
       // We need to add this frame to our frame table. The JSON for this frame
       // already exists in jitFrameInfoRange, we just need to splice it into
       // the frame table and give it an index.
       const nsCString* frameJSON =
           jitFrameInfoRange.mJITFrameToFrameJSONMap.Get(jitFrameKey);
       MOZ_RELEASE_ASSERT(frameJSON, "Should have cached JSON for this frame");
       mFrameTableWriter.Splice(frameJSON->get());
       entry.OrInsert([&] { return index; });
     }
-    frameKeys.AppendElement(std::move(frameKey));
+    MOZ_RELEASE_ASSERT(frameKeys.append(std::move(frameKey)));
   }
   return Some(std::move(frameKeys));
 }
 
 uint32_t UniqueStacks::GetOrAddFrameIndex(const FrameKey& aFrame) {
   uint32_t count = mFrameToIndexMap.Count();
   auto entry = mFrameToIndexMap.LookupForAdd(aFrame);
   if (entry) {
@@ -679,50 +692,50 @@ void JITFrameInfo::AddInfoForRange(
     const std::function<void(const std::function<void(void*)>&)>&
         aJITAddressProvider) {
   if (aRangeStart == aRangeEnd) {
     return;
   }
 
   MOZ_RELEASE_ASSERT(aRangeStart < aRangeEnd);
 
-  if (!mRanges.IsEmpty()) {
-    const JITFrameInfoForBufferRange& prevRange = mRanges.LastElement();
+  if (!mRanges.empty()) {
+    const JITFrameInfoForBufferRange& prevRange = mRanges.back();
     MOZ_RELEASE_ASSERT(prevRange.mRangeEnd <= aRangeStart,
                        "Ranges must be non-overlapping and added in-order.");
   }
 
   using JITFrameKey = JITFrameInfoForBufferRange::JITFrameKey;
 
-  nsClassHashtable<nsPtrHashKey<void>, nsTArray<JITFrameKey>>
+  nsClassHashtable<nsPtrHashKey<void>, Vector<JITFrameKey>>
       jitAddressToJITFrameMap;
   nsClassHashtable<nsGenericHashKey<JITFrameKey>, nsCString>
       jitFrameToFrameJSONMap;
 
   aJITAddressProvider([&](void* aJITAddress) {
     // Make sure that we have cached data for aJITAddress.
     if (!jitAddressToJITFrameMap.Contains(aJITAddress)) {
-      nsTArray<JITFrameKey>& jitFrameKeys =
+      Vector<JITFrameKey>& jitFrameKeys =
           *jitAddressToJITFrameMap.LookupOrAdd(aJITAddress);
       for (JS::ProfiledFrameHandle handle :
            JS::GetProfiledFrames(aCx, aJITAddress)) {
-        uint32_t depth = jitFrameKeys.Length();
+        uint32_t depth = jitFrameKeys.length();
         JITFrameKey jitFrameKey{handle.canonicalAddress(), depth};
         if (!jitFrameToFrameJSONMap.Contains(jitFrameKey)) {
           nsCString& json = *jitFrameToFrameJSONMap.LookupOrAdd(jitFrameKey);
           json = JSONForJITFrame(aCx, handle, *mUniqueStrings);
         }
-        jitFrameKeys.AppendElement(jitFrameKey);
+        MOZ_RELEASE_ASSERT(jitFrameKeys.append(jitFrameKey));
       }
     }
   });
 
-  mRanges.AppendElement(JITFrameInfoForBufferRange{
+  MOZ_RELEASE_ASSERT(mRanges.append(JITFrameInfoForBufferRange{
       aRangeStart, aRangeEnd, std::move(jitAddressToJITFrameMap),
-      std::move(jitFrameToFrameJSONMap)});
+      std::move(jitFrameToFrameJSONMap)}));
 }
 
 struct ProfileSample {
   uint32_t mStack;
   double mTime;
   Maybe<double> mResponsiveness;
   Maybe<double> mRSS;
   Maybe<double> mUSS;
@@ -1103,17 +1116,17 @@ void ProfileBuffer::StreamSamplesToJSON(
             stack, UniqueStacks::FrameKey(std::move(frameLabel), relevantForJS,
                                           line, column, categoryPair));
 
       } else if (e.Get().IsJitReturnAddr()) {
         numFrames++;
 
         // A JIT frame may expand to multiple frames due to inlining.
         void* pc = e.Get().GetPtr();
-        const Maybe<nsTArray<UniqueStacks::FrameKey>>& frameKeys =
+        const Maybe<Vector<UniqueStacks::FrameKey>>& frameKeys =
             aUniqueStacks.LookupFramesForJITAddressFromBufferPos(pc,
                                                                  e.CurPos());
         MOZ_RELEASE_ASSERT(frameKeys,
                            "Attempting to stream samples for a buffer range "
                            "for which we don't have JITFrameInfo?");
         for (const UniqueStacks::FrameKey& frameKey : *frameKeys) {
           stack = aUniqueStacks.AppendFrame(stack, frameKey);
         }
@@ -1362,17 +1375,17 @@ void ProfileBuffer::StreamProfilerOverhe
 }
 
 struct CounterKeyedSample {
   double mTime;
   uint64_t mNumber;
   int64_t mCount;
 };
 
-typedef nsTArray<CounterKeyedSample> CounterKeyedSamples;
+typedef Vector<CounterKeyedSample> CounterKeyedSamples;
 
 static LazyLogModule sFuzzyfoxLog("Fuzzyfox");
 
 typedef nsDataHashtable<nsUint64HashKey, CounterKeyedSamples> CounterMap;
 
 void ProfileBuffer::StreamCountersToJSON(SpliceableJSONWriter& aWriter,
                                          const TimeStamp& aProcessStartTime,
                                          double aSinceTime) const {
@@ -1442,17 +1455,17 @@ void ProfileBuffer::StreamCountersToJSON
           e.Next();
           uint64_t number;
           if (!e.Has() || !e.Get().IsNumber()) {
             number = 0;
           } else {
             number = e.Get().GetInt64();
           }
           CounterKeyedSample sample = {time, number, count};
-          data.AppendElement(sample);
+          MOZ_RELEASE_ASSERT(data.append(sample));
         }
       } else {
         // skip counter sample - only need to skip the initial counter
         // id, then let the loop at the top skip the rest
       }
     }
     e.Next();
   }
@@ -1473,17 +1486,17 @@ void ProfileBuffer::StreamCountersToJSON
     aWriter.StringProperty("description", base_counter->mDescription);
 
     aWriter.StartObjectProperty("sample_groups");
     for (auto counter_iter = counter.Iter(); !counter_iter.Done();
          counter_iter.Next()) {
       CounterKeyedSamples& samples = counter_iter.Data();
       uint64_t key = counter_iter.Key();
 
-      size_t size = samples.Length();
+      size_t size = samples.length();
       if (size == 0) {
         continue;
       }
       aWriter.IntProperty("id", static_cast<int64_t>(key));
       aWriter.StartObjectProperty("samples");
       {
         // XXX Can we assume a missing count means 0?
         JSONSchemaWriter schema(aWriter);
--- a/tools/profiler/core/ProfileBufferEntry.h
+++ b/tools/profiler/core/ProfileBufferEntry.h
@@ -16,17 +16,16 @@
 #include "mozilla/HashFunctions.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Variant.h"
 #include "mozilla/Vector.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
-#include "nsTArray.h"
 
 class ProfilerMarker;
 
 // NOTE!  If you add entries, you need to verify if they need to be added to the
 // switch statement in DuplicateLastSample!
 #define FOR_EACH_PROFILE_BUFFER_ENTRY_KIND(MACRO)                   \
   MACRO(CategoryPair, int)                                          \
   MACRO(CollectionStart, double)                                    \
@@ -162,17 +161,17 @@ struct JITFrameInfoForBufferRange final 
     bool operator==(const JITFrameKey& aOther) const;
     bool operator!=(const JITFrameKey& aOther) const {
       return !(*this == aOther);
     }
 
     void* mCanonicalAddress;
     uint32_t mDepth;
   };
-  nsClassHashtable<nsPtrHashKey<void>, nsTArray<JITFrameKey>>
+  nsClassHashtable<nsPtrHashKey<void>, mozilla::Vector<JITFrameKey>>
       mJITAddressToJITFramesMap;
   nsClassHashtable<nsGenericHashKey<JITFrameKey>, nsCString>
       mJITFrameToFrameJSONMap;
 };
 
 // Contains JITFrameInfoForBufferRange objects for multiple profiler buffer
 // ranges.
 struct JITFrameInfo final {
@@ -191,29 +190,29 @@ struct JITFrameInfo final {
   void AddInfoForRange(
       uint64_t aRangeStart, uint64_t aRangeEnd, JSContext* aCx,
       const std::function<void(const std::function<void(void*)>&)>&
           aJITAddressProvider);
 
   // Returns whether the information stored in this object is still relevant
   // for any entries in the buffer.
   bool HasExpired(uint64_t aCurrentBufferRangeStart) const {
-    if (mRanges.IsEmpty()) {
+    if (mRanges.empty()) {
       // No information means no relevant information. Allow this object to be
       // discarded.
       return true;
     }
-    return mRanges.LastElement().mRangeEnd <= aCurrentBufferRangeStart;
+    return mRanges.back().mRangeEnd <= aCurrentBufferRangeStart;
   }
 
   // The array of ranges of JIT frame information, sorted by buffer position.
   // Ranges are non-overlapping.
   // The JSON of the cached frames can contain string indexes, which refer
   // to strings in mUniqueStrings.
-  nsTArray<JITFrameInfoForBufferRange> mRanges;
+  mozilla::Vector<JITFrameInfoForBufferRange> mRanges;
 
   // The string table which contains strings used in the frame JSON that's
   // cached in mRanges.
   mozilla::UniquePtr<UniqueJSONStrings> mUniqueStrings;
 };
 
 class UniqueStacks {
  public:
@@ -291,17 +290,17 @@ class UniqueStacks {
   MOZ_MUST_USE StackKey AppendFrame(const StackKey& aStack,
                                     const FrameKey& aFrame);
 
   // Look up frame keys for the given JIT address, and ensure that our frame
   // table has entries for the returned frame keys. The JSON for these frames
   // is taken from mJITInfoRanges.
   // aBufferPosition is needed in order to look up the correct JIT frame info
   // object in mJITInfoRanges.
-  MOZ_MUST_USE mozilla::Maybe<nsTArray<UniqueStacks::FrameKey>>
+  MOZ_MUST_USE mozilla::Maybe<mozilla::Vector<UniqueStacks::FrameKey>>
   LookupFramesForJITAddressFromBufferPos(void* aJITAddress,
                                          uint64_t aBufferPosition);
 
   MOZ_MUST_USE uint32_t GetOrAddFrameIndex(const FrameKey& aFrame);
   MOZ_MUST_USE uint32_t GetOrAddStackIndex(const StackKey& aStack);
 
   void SpliceFrameTableElements(SpliceableJSONWriter& aWriter);
   void SpliceStackTableElements(SpliceableJSONWriter& aWriter);
@@ -315,17 +314,17 @@ class UniqueStacks {
 
  private:
   SpliceableChunkedJSONWriter mFrameTableWriter;
   nsDataHashtable<nsGenericHashKey<FrameKey>, uint32_t> mFrameToIndexMap;
 
   SpliceableChunkedJSONWriter mStackTableWriter;
   nsDataHashtable<nsGenericHashKey<StackKey>, uint32_t> mStackToIndexMap;
 
-  nsTArray<JITFrameInfoForBufferRange> mJITInfoRanges;
+  mozilla::Vector<JITFrameInfoForBufferRange> mJITInfoRanges;
 };
 
 //
 // Thread profile JSON Format
 // --------------------------
 //
 // The profile contains much duplicate information. The output JSON of the
 // profile attempts to deduplicate strings, frames, and stack prefixes, to cut
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -287,71 +287,75 @@ class CorePS {
       aLulSize += sInstance->mLul->SizeOfIncludingThis(aMallocSizeOf);
     }
 #endif
   }
 
   // No PSLockRef is needed for this field because it's immutable.
   PS_GET_LOCKLESS(TimeStamp, ProcessStartTime)
 
-  PS_GET(const nsTArray<UniquePtr<RegisteredThread>>&, RegisteredThreads)
+  PS_GET(const Vector<UniquePtr<RegisteredThread>>&, RegisteredThreads)
 
   static void AppendRegisteredThread(
       PSLockRef, UniquePtr<RegisteredThread>&& aRegisteredThread) {
-    sInstance->mRegisteredThreads.AppendElement(std::move(aRegisteredThread));
+    MOZ_RELEASE_ASSERT(
+        sInstance->mRegisteredThreads.append(std::move(aRegisteredThread)));
   }
 
   static void RemoveRegisteredThread(PSLockRef,
                                      RegisteredThread* aRegisteredThread) {
     // Remove aRegisteredThread from mRegisteredThreads.
-    // Can't use RemoveElement() because we can't equality-compare a UniquePtr
-    // to a raw pointer.
-    sInstance->mRegisteredThreads.RemoveElementsBy(
-        [&](UniquePtr<RegisteredThread>& rt) {
-          return rt.get() == aRegisteredThread;
-        });
+    for (UniquePtr<RegisteredThread>& rt : sInstance->mRegisteredThreads) {
+      if (rt.get() == aRegisteredThread) {
+        sInstance->mRegisteredThreads.erase(&rt);
+        return;
+      }
+    }
   }
 
-  PS_GET(nsTArray<RefPtr<PageInformation>>&, RegisteredPages)
+  PS_GET(Vector<RefPtr<PageInformation>>&, RegisteredPages)
 
   static void AppendRegisteredPage(PSLockRef,
                                    RefPtr<PageInformation>&& aRegisteredPage) {
 #ifdef DEBUG
     struct RegisteredPageComparator {
-      bool Equals(PageInformation* aA, PageInformation* aB) const {
-        return aA->Equals(aB);
-      }
+      PageInformation* aA;
+      bool operator()(PageInformation* aB) const { return aA->Equals(aB); }
     };
-    MOZ_ASSERT(!sInstance->mRegisteredPages.Contains(
-        aRegisteredPage, RegisteredPageComparator()));
+    MOZ_RELEASE_ASSERT(std::none_of(
+        sInstance->mRegisteredPages.begin(), sInstance->mRegisteredPages.end(),
+        RegisteredPageComparator{aRegisteredPage.get()}));
 #endif
-    sInstance->mRegisteredPages.AppendElement(std::move(aRegisteredPage));
+    MOZ_RELEASE_ASSERT(
+        sInstance->mRegisteredPages.append(std::move(aRegisteredPage)));
   }
 
   static void RemoveRegisteredPages(PSLockRef,
                                     const nsID& aRegisteredDocShellId) {
     // Remove RegisteredPage from mRegisteredPages by given DocShell Id.
-    sInstance->mRegisteredPages.RemoveElementsBy(
-        [&](RefPtr<PageInformation>& rd) {
-          return rd->DocShellId().Equals(aRegisteredDocShellId);
-        });
+    sInstance->mRegisteredPages.eraseIf([&](const RefPtr<PageInformation>& rd) {
+      return rd->DocShellId().Equals(aRegisteredDocShellId);
+    });
   }
 
-  PS_GET(const nsTArray<BaseProfilerCount*>&, Counters)
+  PS_GET(const Vector<BaseProfilerCount*>&, Counters)
 
   static void AppendCounter(PSLockRef, BaseProfilerCount* aCounter) {
     // we don't own the counter; they may be stored in static objects
-    sInstance->mCounters.AppendElement(aCounter);
+    MOZ_RELEASE_ASSERT(sInstance->mCounters.append(aCounter));
   }
 
   static void RemoveCounter(PSLockRef, BaseProfilerCount* aCounter) {
     // we may be called to remove a counter after the profiler is stopped or
     // late in shutdown.
     if (sInstance) {
-      sInstance->mCounters.RemoveElement(aCounter);
+      auto* counter = std::find(sInstance->mCounters.begin(),
+                                sInstance->mCounters.end(), aCounter);
+      MOZ_RELEASE_ASSERT(counter != sInstance->mCounters.end());
+      sInstance->mCounters.erase(counter);
     }
   }
 
 #ifdef USE_LUL_STACKWALK
   static lul::LUL* Lul(PSLockRef) { return sInstance->mLul.get(); }
   static void SetLul(PSLockRef, UniquePtr<lul::LUL> aLul) {
     sInstance->mLul = std::move(aLul);
   }
@@ -363,24 +367,24 @@ class CorePS {
   // The singleton instance
   static CorePS* sInstance;
 
   // The time that the process started.
   const TimeStamp mProcessStartTime;
 
   // Info on all the registered threads.
   // ThreadIds in mRegisteredThreads are unique.
-  nsTArray<UniquePtr<RegisteredThread>> mRegisteredThreads;
+  Vector<UniquePtr<RegisteredThread>> mRegisteredThreads;
 
   // Info on all the registered pages.
   // DocShellId and DocShellHistoryId pairs in mRegisteredPages are unique.
-  nsTArray<RefPtr<PageInformation>> mRegisteredPages;
+  Vector<RefPtr<PageInformation>> mRegisteredPages;
 
   // Non-owning pointers to all active counters
-  nsTArray<BaseProfilerCount*> mCounters;
+  Vector<BaseProfilerCount*> mCounters;
 
 #ifdef USE_LUL_STACKWALK
   // LUL's state. Null prior to the first activation, non-null thereafter.
   UniquePtr<lul::LUL> mLul;
 #endif
 
   // Process name, provided by child process initialization code.
   nsAutoCString mProcessName;
@@ -622,156 +626,152 @@ class ActivePS {
         FeatureJSTracer(aLock) ? uint32_t(JSSamplingFlags::TraceLogging) : 0;
     return Flags;
   }
 
   PS_GET(const Vector<std::string>&, Filters)
 
   static ProfileBuffer& Buffer(PSLockRef) { return *sInstance->mBuffer.get(); }
 
-  static const nsTArray<LiveProfiledThreadData>& LiveProfiledThreads(
-      PSLockRef) {
+  static const Vector<LiveProfiledThreadData>& LiveProfiledThreads(PSLockRef) {
     return sInstance->mLiveProfiledThreads;
   }
 
   // Returns an array containing (RegisteredThread*, ProfiledThreadData*) pairs
   // for all threads that should be included in a profile, both for threads
   // that are still registered, and for threads that have been unregistered but
   // still have data in the buffer.
   // For threads that have already been unregistered, the RegisteredThread
   // pointer will be null.
   // The returned array is sorted by thread register time.
   // Do not hold on to the return value across thread registration or profiler
   // restarts.
-  static nsTArray<Pair<RegisteredThread*, ProfiledThreadData*>> ProfiledThreads(
+  static Vector<Pair<RegisteredThread*, ProfiledThreadData*>> ProfiledThreads(
       PSLockRef) {
-    nsTArray<Pair<RegisteredThread*, ProfiledThreadData*>> array;
+    Vector<Pair<RegisteredThread*, ProfiledThreadData*>> array;
+    MOZ_RELEASE_ASSERT(
+        array.initCapacity(sInstance->mLiveProfiledThreads.length() +
+                           sInstance->mDeadProfiledThreads.length()));
     for (auto& t : sInstance->mLiveProfiledThreads) {
-      array.AppendElement(
-          MakePair(t.mRegisteredThread, t.mProfiledThreadData.get()));
+      MOZ_RELEASE_ASSERT(array.append(
+          MakePair(t.mRegisteredThread, t.mProfiledThreadData.get())));
     }
     for (auto& t : sInstance->mDeadProfiledThreads) {
-      array.AppendElement(MakePair((RegisteredThread*)nullptr, t.get()));
+      MOZ_RELEASE_ASSERT(
+          array.append(MakePair((RegisteredThread*)nullptr, t.get())));
     }
 
-    class ThreadRegisterTimeComparator {
-     public:
-      bool Equals(const Pair<RegisteredThread*, ProfiledThreadData*>& a,
-                  const Pair<RegisteredThread*, ProfiledThreadData*>& b) const {
-        return a.second()->Info()->RegisterTime() ==
-               b.second()->Info()->RegisterTime();
-      }
-
-      bool LessThan(
-          const Pair<RegisteredThread*, ProfiledThreadData*>& a,
-          const Pair<RegisteredThread*, ProfiledThreadData*>& b) const {
-        return a.second()->Info()->RegisterTime() <
-               b.second()->Info()->RegisterTime();
-      }
-    };
-    array.Sort(ThreadRegisterTimeComparator());
+    std::sort(array.begin(), array.end(),
+              [](const Pair<RegisteredThread*, ProfiledThreadData*>& a,
+                 const Pair<RegisteredThread*, ProfiledThreadData*>& b) {
+                return a.second()->Info()->RegisterTime() <
+                       b.second()->Info()->RegisterTime();
+              });
     return array;
   }
 
-  static nsTArray<RefPtr<PageInformation>> ProfiledPages(PSLockRef aLock) {
-    nsTArray<RefPtr<PageInformation>> array;
+  static Vector<RefPtr<PageInformation>> ProfiledPages(PSLockRef aLock) {
+    Vector<RefPtr<PageInformation>> array;
     for (auto& d : CorePS::RegisteredPages(aLock)) {
-      array.AppendElement(d);
+      MOZ_RELEASE_ASSERT(array.append(d));
     }
     for (auto& d : sInstance->mDeadProfiledPages) {
-      array.AppendElement(d);
+      MOZ_RELEASE_ASSERT(array.append(d));
     }
     // We don't need to sort the DocShells like threads since we won't show them
     // as a list.
     return array;
   }
 
   // Do a linear search through mLiveProfiledThreads to find the
   // ProfiledThreadData object for a RegisteredThread.
   static ProfiledThreadData* GetProfiledThreadData(
       PSLockRef, RegisteredThread* aRegisteredThread) {
-    for (size_t i = 0; i < sInstance->mLiveProfiledThreads.Length(); i++) {
-      LiveProfiledThreadData& thread = sInstance->mLiveProfiledThreads[i];
+    for (const LiveProfiledThreadData& thread :
+         sInstance->mLiveProfiledThreads) {
       if (thread.mRegisteredThread == aRegisteredThread) {
         return thread.mProfiledThreadData.get();
       }
     }
     return nullptr;
   }
 
   static ProfiledThreadData* AddLiveProfiledThread(
       PSLockRef, RegisteredThread* aRegisteredThread,
       UniquePtr<ProfiledThreadData>&& aProfiledThreadData) {
-    sInstance->mLiveProfiledThreads.AppendElement(LiveProfiledThreadData{
-        aRegisteredThread, std::move(aProfiledThreadData)});
+    MOZ_RELEASE_ASSERT(
+        sInstance->mLiveProfiledThreads.append(LiveProfiledThreadData{
+            aRegisteredThread, std::move(aProfiledThreadData)}));
 
     // Return a weak pointer to the ProfiledThreadData object.
-    return sInstance->mLiveProfiledThreads.LastElement()
-        .mProfiledThreadData.get();
+    return sInstance->mLiveProfiledThreads.back().mProfiledThreadData.get();
   }
 
   static void UnregisterThread(PSLockRef aLockRef,
                                RegisteredThread* aRegisteredThread) {
     DiscardExpiredDeadProfiledThreads(aLockRef);
 
     // Find the right entry in the mLiveProfiledThreads array and remove the
     // element, moving the ProfiledThreadData object for the thread into the
     // mDeadProfiledThreads array.
     // The thread's RegisteredThread object gets destroyed here.
-    for (size_t i = 0; i < sInstance->mLiveProfiledThreads.Length(); i++) {
+    for (size_t i = 0; i < sInstance->mLiveProfiledThreads.length(); i++) {
       LiveProfiledThreadData& thread = sInstance->mLiveProfiledThreads[i];
       if (thread.mRegisteredThread == aRegisteredThread) {
         thread.mProfiledThreadData->NotifyUnregistered(
             sInstance->mBuffer->mRangeEnd);
-        sInstance->mDeadProfiledThreads.AppendElement(
-            std::move(thread.mProfiledThreadData));
-        sInstance->mLiveProfiledThreads.RemoveElementAt(i);
+        MOZ_RELEASE_ASSERT(sInstance->mDeadProfiledThreads.append(
+            std::move(thread.mProfiledThreadData)));
+        sInstance->mLiveProfiledThreads.erase(
+            &sInstance->mLiveProfiledThreads[i]);
         return;
       }
     }
   }
 
   PS_GET_AND_SET(bool, IsPaused)
 
 #if defined(GP_OS_linux)
   PS_GET_AND_SET(bool, WasPaused)
 #endif
 
   static void DiscardExpiredDeadProfiledThreads(PSLockRef) {
     uint64_t bufferRangeStart = sInstance->mBuffer->mRangeStart;
     // Discard any dead threads that were unregistered before bufferRangeStart.
-    sInstance->mDeadProfiledThreads.RemoveElementsBy(
-        [bufferRangeStart](UniquePtr<ProfiledThreadData>& aProfiledThreadData) {
+    sInstance->mDeadProfiledThreads.eraseIf(
+        [bufferRangeStart](
+            const UniquePtr<ProfiledThreadData>& aProfiledThreadData) {
           Maybe<uint64_t> bufferPosition =
               aProfiledThreadData->BufferPositionWhenUnregistered();
           MOZ_RELEASE_ASSERT(bufferPosition,
                              "should have unregistered this thread");
           return *bufferPosition < bufferRangeStart;
         });
   }
 
   static void UnregisterPages(PSLockRef aLock,
                               const nsID& aRegisteredDocShellId) {
     auto& registeredPages = CorePS::RegisteredPages(aLock);
-    for (size_t i = 0; i < registeredPages.Length(); i++) {
+    for (size_t i = 0; i < registeredPages.length(); i++) {
       RefPtr<PageInformation>& page = registeredPages[i];
       if (page->DocShellId().Equals(aRegisteredDocShellId)) {
         page->NotifyUnregistered(sInstance->mBuffer->mRangeEnd);
-        sInstance->mDeadProfiledPages.AppendElement(std::move(page));
-        registeredPages.RemoveElementAt(i--);
+        MOZ_RELEASE_ASSERT(
+            sInstance->mDeadProfiledPages.append(std::move(page)));
+        registeredPages.erase(&registeredPages[i--]);
       }
     }
   }
 
   static void DiscardExpiredPages(PSLockRef) {
     uint64_t bufferRangeStart = sInstance->mBuffer->mRangeStart;
     // Discard any dead pages that were unregistered before
     // bufferRangeStart.
-    sInstance->mDeadProfiledPages.RemoveElementsBy(
-        [bufferRangeStart](RefPtr<PageInformation>& aProfiledPage) {
+    sInstance->mDeadProfiledPages.eraseIf(
+        [bufferRangeStart](const RefPtr<PageInformation>& aProfiledPage) {
           Maybe<uint64_t> bufferPosition =
               aProfiledPage->BufferPositionWhenUnregistered();
           MOZ_RELEASE_ASSERT(bufferPosition,
                              "should have unregistered this page");
           return *bufferPosition < bufferRangeStart;
         });
   }
 
@@ -804,37 +804,39 @@ class ActivePS {
     IOInterposer::Register(IOInterposeObserver::OpAll,
                            sInstance->mInterposeObserver);
   }
 #endif
 
   static void ClearExpiredExitProfiles(PSLockRef) {
     uint64_t bufferRangeStart = sInstance->mBuffer->mRangeStart;
     // Discard exit profiles that were gathered before our buffer RangeStart.
-    sInstance->mExitProfiles.RemoveElementsBy(
+    sInstance->mExitProfiles.eraseIf(
         [bufferRangeStart](const ExitProfile& aExitProfile) {
           return aExitProfile.mBufferPositionAtGatherTime < bufferRangeStart;
         });
   }
 
   static void AddExitProfile(PSLockRef aLock, const nsCString& aExitProfile) {
     ClearExpiredExitProfiles(aLock);
 
-    sInstance->mExitProfiles.AppendElement(
-        ExitProfile{aExitProfile, sInstance->mBuffer->mRangeEnd});
+    MOZ_RELEASE_ASSERT(sInstance->mExitProfiles.append(
+        ExitProfile{aExitProfile, sInstance->mBuffer->mRangeEnd}));
   }
 
-  static nsTArray<nsCString> MoveExitProfiles(PSLockRef aLock) {
+  static Vector<nsCString> MoveExitProfiles(PSLockRef aLock) {
     ClearExpiredExitProfiles(aLock);
 
-    nsTArray<nsCString> profiles(sInstance->mExitProfiles.Length());
+    Vector<nsCString> profiles;
+    MOZ_RELEASE_ASSERT(
+        profiles.initCapacity(sInstance->mExitProfiles.length()));
     for (auto& profile : sInstance->mExitProfiles) {
-      profiles.AppendElement(std::move(profile.mJSON));
+      MOZ_RELEASE_ASSERT(profiles.append(std::move(profile.mJSON)));
     }
-    sInstance->mExitProfiles.Clear();
+    sInstance->mExitProfiles.clear();
     return profiles;
   }
 
  private:
   // The singleton instance.
   static ActivePS* sInstance;
 
   // We need to track activity generations. If we didn't we could have the
@@ -876,24 +878,24 @@ class ActivePS {
   // used in conjunction with CorePS::m{Live,Dead}Threads.
   const UniquePtr<ProfileBuffer> mBuffer;
 
   // ProfiledThreadData objects for any threads that were profiled at any point
   // during this run of the profiler:
   //  - mLiveProfiledThreads contains all threads that are still registered, and
   //  - mDeadProfiledThreads contains all threads that have already been
   //    unregistered but for which there is still data in the profile buffer.
-  nsTArray<LiveProfiledThreadData> mLiveProfiledThreads;
-  nsTArray<UniquePtr<ProfiledThreadData>> mDeadProfiledThreads;
+  Vector<LiveProfiledThreadData> mLiveProfiledThreads;
+  Vector<UniquePtr<ProfiledThreadData>> mDeadProfiledThreads;
 
   // Info on all the dead pages.
   // Registered pages are being moved to this array after unregistration.
   // We are keeping them in case we need them in the profile data.
   // We are removing them when we ensure that we won't need them anymore.
-  nsTArray<RefPtr<PageInformation>> mDeadProfiledPages;
+  Vector<RefPtr<PageInformation>> mDeadProfiledPages;
 
   // The current sampler thread. This class is not responsible for destroying
   // the SamplerThread object; the Destroy() method returns it so the caller
   // can destroy it.
   SamplerThread* const mSamplerThread;
 
   // The interposer that records main thread I/O.
   RefPtr<ProfilerIOInterposeObserver> mInterposeObserver;
@@ -906,17 +908,17 @@ class ActivePS {
   // at all times except just before/after forking.
   bool mWasPaused;
 #endif
 
   struct ExitProfile {
     nsCString mJSON;
     uint64_t mBufferPositionAtGatherTime;
   };
-  nsTArray<ExitProfile> mExitProfiles;
+  Vector<ExitProfile> mExitProfiles;
 };
 
 ActivePS* ActivePS::sInstance = nullptr;
 uint32_t ActivePS::sNextGeneration = 0;
 
 #undef PS_GET
 #undef PS_GET_LOCKLESS
 #undef PS_GET_AND_SET
@@ -1731,28 +1733,28 @@ static void StreamNameAndThreadId(JSONWr
 #endif
 
 static void StreamTaskTracer(PSLockRef aLock, SpliceableJSONWriter& aWriter) {
 #ifdef MOZ_TASK_TRACER
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
   aWriter.StartArrayProperty("data");
   {
-    UniquePtr<nsTArray<nsCString>> data =
+    UniquePtr<Vector<nsCString>> data =
         tasktracer::GetLoggedData(CorePS::ProcessStartTime());
-    for (uint32_t i = 0; i < data->Length(); ++i) {
-      aWriter.StringElement((data->ElementAt(i)).get());
+    for (const nsCString& dataString : *data) {
+      aWriter.StringElement(dataString.get());
     }
   }
   aWriter.EndArray();
 
   aWriter.StartArrayProperty("threads");
   {
     ActivePS::DiscardExpiredDeadProfiledThreads(aLock);
-    nsTArray<Pair<RegisteredThread*, ProfiledThreadData*>> threads =
+    Vector<Pair<RegisteredThread*, ProfiledThreadData*>> threads =
         ActivePS::ProfiledThreads(aLock);
     for (auto& thread : threads) {
       RefPtr<ThreadInfo> info = thread.second()->Info();
       StreamNameAndThreadId(aWriter, info->Name(), info->ThreadId());
     }
   }
   aWriter.EndArray();
 
@@ -2032,17 +2034,17 @@ static void locked_profiler_stream_json_
     StreamTaskTracer(aLock, aWriter);
     aWriter.EndObject();
   }
 
   // Lists the samples for each thread profile
   aWriter.StartArrayProperty("threads");
   {
     ActivePS::DiscardExpiredDeadProfiledThreads(aLock);
-    nsTArray<Pair<RegisteredThread*, ProfiledThreadData*>> threads =
+    Vector<Pair<RegisteredThread*, ProfiledThreadData*>> threads =
         ActivePS::ProfiledThreads(aLock);
     for (auto& thread : threads) {
       RegisteredThread* registeredThread = thread.first();
       JSContext* cx =
           registeredThread ? registeredThread->GetJSContext() : nullptr;
       ProfiledThreadData* profiledThreadData = thread.second();
       profiledThreadData->StreamJSON(buffer, cx, aWriter,
                                      CorePS::ProcessName(aLock),
@@ -2347,17 +2349,17 @@ void SamplerThread::Run() {
       }
 
       ActivePS::ClearExpiredExitProfiles(lock);
 
       ActivePS::Buffer(lock).DeleteExpiredStoredMarkers();
       TimeStamp expiredMarkersCleaned = TimeStamp::Now();
 
       if (!ActivePS::IsPaused(lock)) {
-        const nsTArray<LiveProfiledThreadData>& liveThreads =
+        const Vector<LiveProfiledThreadData>& liveThreads =
             ActivePS::LiveProfiledThreads(lock);
 
         TimeDuration delta = sampleStart - CorePS::ProcessStartTime();
         ProfileBuffer& buffer = ActivePS::Buffer(lock);
 
         // Report memory use
         int64_t rssMemory = 0;
         int64_t ussMemory = 0;
@@ -2371,17 +2373,17 @@ void SamplerThread::Run() {
             if (ussMemory != 0) {
               buffer.AddEntry(ProfileBufferEntry::UnsharedMemory(ussMemory));
             }
           }
           buffer.AddEntry(ProfileBufferEntry::Time(delta.ToMilliseconds()));
         }
 
         // handle per-process generic counters
-        const nsTArray<BaseProfilerCount*>& counters = CorePS::Counters(lock);
+        const Vector<BaseProfilerCount*>& counters = CorePS::Counters(lock);
         TimeStamp now = TimeStamp::Now();
         for (auto& counter : counters) {
           // create Buffer entries for each counter
           buffer.AddEntry(ProfileBufferEntry::CounterId(counter));
           buffer.AddEntry(ProfileBufferEntry::Time(delta.ToMilliseconds()));
           // XXX support keyed maps of counts
           // In the future, we'll support keyed counters - for example, counters
           // with a key which is a thread ID. For "simple" counters we'll just
@@ -2572,17 +2574,17 @@ uint32_t ParseFeaturesFromStringArray(co
 
   return features;
 }
 
 // Find the RegisteredThread for the current thread. This should only be called
 // in places where TLSRegisteredThread can't be used.
 static RegisteredThread* FindCurrentThreadRegisteredThread(PSLockRef aLock) {
   int id = Thread::GetCurrentId();
-  const nsTArray<UniquePtr<RegisteredThread>>& registeredThreads =
+  const Vector<UniquePtr<RegisteredThread>>& registeredThreads =
       CorePS::RegisteredThreads(aLock);
   for (auto& registeredThread : registeredThreads) {
     if (registeredThread->Info()->ThreadId() == id) {
       return registeredThread.get();
     }
   }
 
   return nullptr;
@@ -2663,17 +2665,17 @@ static void NotifyProfilerStarted(const 
                                   const char** aFilters,
                                   uint32_t aFilterCount) {
   nsTArray<nsCString> filtersArray;
   for (size_t i = 0; i < aFilterCount; ++i) {
     filtersArray.AppendElement(aFilters[i]);
   }
 
   nsCOMPtr<nsIProfilerStartParams> params = new nsProfilerStartParams(
-      aCapacity, aDuration, aInterval, aFeatures, filtersArray);
+      aCapacity, aDuration, aInterval, aFeatures, std::move(filtersArray));
 
   ProfilerParent::ProfilerStarted(params);
   NotifyObservers("profiler-started", params);
 }
 
 static void locked_profiler_start(PSLockRef aLock, uint32_t aCapacity,
                                   double aInterval, uint32_t aFeatures,
                                   const char** aFilters, uint32_t aFilterCount,
@@ -2692,32 +2694,32 @@ ProfilingStack* MozGlueLabelEnter(const 
 
 // This basically duplicates AutoProfilerLabel's destructor.
 void MozGlueLabelExit(ProfilingStack* sProfilingStack) {
   if (sProfilingStack) {
     sProfilingStack->pop();
   }
 }
 
-static nsTArray<const char*> SplitAtCommas(const char* aString,
-                                           UniquePtr<char[]>& aStorage) {
+static Vector<const char*> SplitAtCommas(const char* aString,
+                                         UniquePtr<char[]>& aStorage) {
   size_t len = strlen(aString);
   aStorage = MakeUnique<char[]>(len + 1);
   PodCopy(aStorage.get(), aString, len + 1);
 
   // Iterate over all characters in aStorage and split at commas, by
   // overwriting commas with the null char.
-  nsTArray<const char*> array;
+  Vector<const char*> array;
   size_t currentElementStart = 0;
   for (size_t i = 0; i <= len; i++) {
     if (aStorage[i] == ',') {
       aStorage[i] = '\0';
     }
     if (aStorage[i] == '\0') {
-      array.AppendElement(&aStorage[currentElementStart]);
+      MOZ_RELEASE_ASSERT(array.append(&aStorage[currentElementStart]));
       currentElementStart = i + 1;
     }
   }
   return array;
 }
 
 void profiler_init(void* aStackTop) {
   LOG("profiler_init");
@@ -2739,20 +2741,20 @@ void profiler_init(void* aStackTop) {
       ProfilerFeature::JS | ProfilerFeature::Leaf |
 #if defined(HAVE_NATIVE_UNWIND)
       ProfilerFeature::StackWalk |
 #endif
       ProfilerFeature::Threads | ProfilerFeature::Responsiveness | 0;
 
   UniquePtr<char[]> filterStorage;
 
-  nsTArray<const char*> filters;
-  filters.AppendElement("GeckoMain");
-  filters.AppendElement("Compositor");
-  filters.AppendElement("DOM Worker");
+  Vector<const char*> filters;
+  MOZ_RELEASE_ASSERT(filters.append("GeckoMain"));
+  MOZ_RELEASE_ASSERT(filters.append("Compositor"));
+  MOZ_RELEASE_ASSERT(filters.append("DOM Worker"));
 
   int capacity = PROFILER_DEFAULT_ENTRIES;
   Maybe<double> duration = Nothing();
   double interval = PROFILER_DEFAULT_INTERVAL;
 
   {
     PSAutoLock lock(gPSMutex);
 
@@ -2851,38 +2853,38 @@ void profiler_init(void* aStackTop) {
         PrintUsageThenExit(1);
       }
     } else {
       const char* startupFeatures = getenv("MOZ_PROFILER_STARTUP_FEATURES");
       if (startupFeatures && startupFeatures[0] != '\0') {
         // Interpret startupFeatures as a list of feature strings, separated by
         // commas.
         UniquePtr<char[]> featureStringStorage;
-        nsTArray<const char*> featureStringArray =
+        Vector<const char*> featureStringArray =
             SplitAtCommas(startupFeatures, featureStringStorage);
-        features = ParseFeaturesFromStringArray(featureStringArray.Elements(),
-                                                featureStringArray.Length());
+        features = ParseFeaturesFromStringArray(featureStringArray.begin(),
+                                                featureStringArray.length());
         LOG("- MOZ_PROFILER_STARTUP_FEATURES = %d", features);
       }
     }
 
     const char* startupFilters = getenv("MOZ_PROFILER_STARTUP_FILTERS");
     if (startupFilters && startupFilters[0] != '\0') {
       filters = SplitAtCommas(startupFilters, filterStorage);
       LOG("- MOZ_PROFILER_STARTUP_FILTERS = %s", startupFilters);
     }
 
-    locked_profiler_start(lock, capacity, interval, features,
-                          filters.Elements(), filters.Length(), duration);
+    locked_profiler_start(lock, capacity, interval, features, filters.begin(),
+                          filters.length(), duration);
   }
 
   // We do this with gPSMutex unlocked. The comment in profiler_stop() explains
   // why.
-  NotifyProfilerStarted(capacity, duration, interval, features,
-                        filters.Elements(), filters.Length());
+  NotifyProfilerStarted(capacity, duration, interval, features, filters.begin(),
+                        filters.length());
 }
 
 static void locked_profiler_save_profile_to_file(PSLockRef aLock,
                                                  const char* aFilename,
                                                  bool aIsShuttingDown);
 
 static SamplerThread* locked_profiler_stop(PSLockRef aLock);
 
@@ -3067,20 +3069,20 @@ void profiler_received_exit_profile(cons
   MOZ_RELEASE_ASSERT(CorePS::Exists());
   PSAutoLock lock(gPSMutex);
   if (!ActivePS::Exists(lock)) {
     return;
   }
   ActivePS::AddExitProfile(lock, aExitProfile);
 }
 
-nsTArray<nsCString> profiler_move_exit_profiles() {
+Vector<nsCString> profiler_move_exit_profiles() {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
   PSAutoLock lock(gPSMutex);
-  nsTArray<nsCString> profiles;
+  Vector<nsCString> profiles;
   if (ActivePS::Exists(lock)) {
     profiles = ActivePS::MoveExitProfiles(lock);
   }
   return profiles;
 }
 
 static void locked_profiler_save_profile_to_file(PSLockRef aLock,
                                                  const char* aFilename,
@@ -3094,17 +3096,17 @@ static void locked_profiler_save_profile
   if (stream.is_open()) {
     SpliceableJSONWriter w(MakeUnique<OStreamJSONWriteFunc>(stream));
     w.Start();
     {
       locked_profiler_stream_json_for_this_process(aLock, w, /* sinceTime */ 0,
                                                    aIsShuttingDown);
 
       w.StartArrayProperty("processes");
-      nsTArray<nsCString> exitProfiles = ActivePS::MoveExitProfiles(aLock);
+      Vector<nsCString> exitProfiles = ActivePS::MoveExitProfiles(aLock);
       for (auto& exitProfile : exitProfiles) {
         if (!exitProfile.IsEmpty()) {
           w.Splice(exitProfile.get());
         }
       }
       w.EndArray();
     }
     w.End();
@@ -3245,17 +3247,17 @@ static void locked_profiler_start(PSLock
   }
   double interval = aInterval > 0 ? aInterval : PROFILER_DEFAULT_INTERVAL;
 
   ActivePS::Create(aLock, capacity, interval, aFeatures, aFilters, aFilterCount,
                    duration);
 
   // Set up profiling for each registered thread, if appropriate.
   int tid = Thread::GetCurrentId();
-  const nsTArray<UniquePtr<RegisteredThread>>& registeredThreads =
+  const Vector<UniquePtr<RegisteredThread>>& registeredThreads =
       CorePS::RegisteredThreads(aLock);
   for (auto& registeredThread : registeredThreads) {
     RefPtr<ThreadInfo> info = registeredThread->Info();
 
     if (ActivePS::ShouldProfileThread(aLock, info)) {
       registeredThread->RacyRegisteredThread().SetIsBeingProfiled(true);
       nsCOMPtr<nsIEventTarget> eventTarget = registeredThread->GetEventTarget();
       ProfiledThreadData* profiledThreadData = ActivePS::AddLiveProfiledThread(
@@ -3410,17 +3412,17 @@ static MOZ_MUST_USE SamplerThread* locke
 #ifdef MOZ_TASK_TRACER
   if (ActivePS::FeatureTaskTracer(aLock)) {
     tasktracer::StopLogging();
   }
 #endif
 
   // Stop sampling live threads.
   int tid = Thread::GetCurrentId();
-  const nsTArray<LiveProfiledThreadData>& liveProfiledThreads =
+  const Vector<LiveProfiledThreadData>& liveProfiledThreads =
       ActivePS::LiveProfiledThreads(aLock);
   for (auto& thread : liveProfiledThreads) {
     RegisteredThread* registeredThread = thread.mRegisteredThread;
     registeredThread->RacyRegisteredThread().SetIsBeingProfiled(false);
     if (ActivePS::FeatureJS(aLock)) {
       registeredThread->StopJSSampling();
       RefPtr<ThreadInfo> info = registeredThread->Info();
       if (info->ThreadId() == tid) {
@@ -3864,17 +3866,17 @@ void profiler_add_marker_for_thread(int 
   TimeDuration delta = origin - CorePS::ProcessStartTime();
   ProfilerMarker* marker =
       new ProfilerMarker(aMarkerName, aCategoryPair, aThreadId,
                          std::move(aPayload), delta.ToMilliseconds());
 
 #ifdef DEBUG
   // Assert that our thread ID makes sense
   bool realThread = false;
-  const nsTArray<UniquePtr<RegisteredThread>>& registeredThreads =
+  const Vector<UniquePtr<RegisteredThread>>& registeredThreads =
       CorePS::RegisteredThreads(lock);
   for (auto& thread : registeredThreads) {
     RefPtr<ThreadInfo> info = thread->Info();
     if (info->ThreadId() == aThreadId) {
       realThread = true;
       break;
     }
   }
@@ -4012,17 +4014,17 @@ int profiler_current_thread_id() { retur
 // Doing things in those methods like allocating -- which may try to claim
 // locks -- is a surefire way to deadlock.
 void profiler_suspend_and_sample_thread(int aThreadId, uint32_t aFeatures,
                                         ProfilerStackCollector& aCollector,
                                         bool aSampleNative /* = true */) {
   // Lock the profiler mutex
   PSAutoLock lock(gPSMutex);
 
-  const nsTArray<UniquePtr<RegisteredThread>>& registeredThreads =
+  const Vector<UniquePtr<RegisteredThread>>& registeredThreads =
       CorePS::RegisteredThreads(lock);
   for (auto& thread : registeredThreads) {
     RefPtr<ThreadInfo> info = thread->Info();
     RegisteredThread& registeredThread = *thread.get();
 
     if (info->ThreadId() == aThreadId) {
       if (info->IsMainThread()) {
         aCollector.SetIsMainThread();
--- a/tools/profiler/core/platform.h
+++ b/tools/profiler/core/platform.h
@@ -28,18 +28,18 @@
 
 #ifndef TOOLS_PLATFORM_H_
 #define TOOLS_PLATFORM_H_
 
 #include "PlatformMacros.h"
 
 #include "mozilla/Logging.h"
 #include "mozilla/UniquePtr.h"
+#include "mozilla/Vector.h"
 #include "nsString.h"
-#include "nsTArray.h"
 
 #include <functional>
 #include <stdint.h>
 
 // We need a definition of gettid(), but old glibc versions don't provide a
 // wrapper for it.
 #if defined(__GLIBC__)
 #  include <unistd.h>
@@ -124,11 +124,11 @@ enum class JSSamplingFlags {
   TraceLogging = 0x4
 };
 
 // Record an exit profile from a child process.
 void profiler_received_exit_profile(const nsCString& aExitProfile);
 
 // Extract all received exit profiles that have not yet expired (i.e., they
 // still intersect with this process' buffer range).
-nsTArray<nsCString> profiler_move_exit_profiles();
+mozilla::Vector<nsCString> profiler_move_exit_profiles();
 
 #endif /* ndef TOOLS_PLATFORM_H_ */
--- a/tools/profiler/gecko/nsProfiler.cpp
+++ b/tools/profiler/gecko/nsProfiler.cpp
@@ -600,17 +600,17 @@ RefPtr<nsProfiler::GatheringPromise> nsP
     // stopped on a different thread since that call. Either way, we need to
     // reject the promise and stop gathering.
     return GatheringPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
   }
 
   mWriter->StartArrayProperty("processes");
 
   // If we have any process exit profiles, add them immediately.
-  nsTArray<nsCString> exitProfiles = profiler_move_exit_profiles();
+  Vector<nsCString> exitProfiles = profiler_move_exit_profiles();
   for (auto& exitProfile : exitProfiles) {
     if (!exitProfile.IsEmpty()) {
       mWriter->Splice(exitProfile.get());
     }
   }
 
   mPromiseHolder.emplace();
   RefPtr<GatheringPromise> promise = mPromiseHolder->Ensure(__func__);
--- a/tools/profiler/gecko/nsProfiler.h
+++ b/tools/profiler/gecko/nsProfiler.h
@@ -8,16 +8,17 @@
 #define nsProfiler_h
 
 #include "nsIProfiler.h"
 #include "nsIObserver.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/TimeStamp.h"
+#include "mozilla/Vector.h"
 #include "nsServiceManagerUtils.h"
 #include "ProfileJSONWriter.h"
 
 class nsProfiler final : public nsIProfiler, public nsIObserver {
  public:
   nsProfiler();
 
   NS_DECL_ISUPPORTS
@@ -63,17 +64,17 @@ class nsProfiler final : public nsIProfi
   bool mLockedForPrivateBrowsing;
 
   struct ExitProfile {
     nsCString mJSON;
     uint64_t mBufferPositionAtGatherTime;
   };
 
   // These fields are all related to profile gathering.
-  nsTArray<ExitProfile> mExitProfiles;
+  mozilla::Vector<ExitProfile> mExitProfiles;
   mozilla::Maybe<mozilla::MozPromiseHolder<GatheringPromise>> mPromiseHolder;
   nsCOMPtr<nsIThread> mSymbolTableThread;
   mozilla::Maybe<SpliceableChunkedJSONWriter> mWriter;
   uint32_t mPendingProfiles;
   bool mGathering;
 };
 
 #endif  // nsProfiler_h
--- a/tools/profiler/gecko/nsProfilerStartParams.cpp
+++ b/tools/profiler/gecko/nsProfilerStartParams.cpp
@@ -5,22 +5,22 @@
 
 #include "nsProfilerStartParams.h"
 #include "ipc/IPCMessageUtils.h"
 
 NS_IMPL_ISUPPORTS(nsProfilerStartParams, nsIProfilerStartParams)
 
 nsProfilerStartParams::nsProfilerStartParams(
     uint32_t aEntries, const mozilla::Maybe<double>& aDuration,
-    double aInterval, uint32_t aFeatures, const nsTArray<nsCString>& aFilters)
+    double aInterval, uint32_t aFeatures, nsTArray<nsCString>&& aFilters)
     : mEntries(aEntries),
       mDuration(aDuration),
       mInterval(aInterval),
       mFeatures(aFeatures),
-      mFilters(aFilters) {}
+      mFilters(std::move(aFilters)) {}
 
 nsProfilerStartParams::~nsProfilerStartParams() {}
 
 NS_IMETHODIMP
 nsProfilerStartParams::GetEntries(uint32_t* aEntries) {
   NS_ENSURE_ARG_POINTER(aEntries);
   *aEntries = mEntries;
   return NS_OK;
--- a/tools/profiler/gecko/nsProfilerStartParams.h
+++ b/tools/profiler/gecko/nsProfilerStartParams.h
@@ -16,17 +16,17 @@ class nsProfilerStartParams : public nsI
   // observer notification from profiler_start, which can run on any thread but
   // posts the notification to the main thread.
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIPROFILERSTARTPARAMS
 
   nsProfilerStartParams(uint32_t aEntries,
                         const mozilla::Maybe<double>& aDuration,
                         double aInterval, uint32_t aFeatures,
-                        const nsTArray<nsCString>& aFilters);
+                        nsTArray<nsCString>&& aFilters);
 
  private:
   virtual ~nsProfilerStartParams();
   uint32_t mEntries;
   mozilla::Maybe<double> mDuration;
   double mInterval;
   uint32_t mFeatures;
   nsTArray<nsCString> mFilters;