Bug 1267412 - Use MutableHandleValue instead of pointer-to-AutoValueVector; r=sfink
authorTerrence Cole <terrence@mozilla.com>
Mon, 25 Apr 2016 15:42:19 -0700
changeset 295535 9e97e2282142b206ef97d13045eac502b58201ed
parent 295508 1d4795f0b4e28db3ddf6a5751653c179fef68726
child 295536 01067412db32dd8eee38f64e6d66942b437fa924
push id19015
push usercbook@mozilla.com
push dateMon, 02 May 2016 09:39:23 +0000
treeherderfx-team@2080375bc69d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1267412
milestone49.0a1
Bug 1267412 - Use MutableHandleValue instead of pointer-to-AutoValueVector; r=sfink
js/src/builtin/MapObject.cpp
js/src/builtin/MapObject.h
js/src/builtin/Promise.cpp
js/src/builtin/Promise.h
js/src/builtin/RegExp.cpp
js/src/builtin/TestingFunctions.cpp
js/src/jit/BaselineBailouts.cpp
js/src/jit/BaselineFrame.cpp
js/src/jit/BaselineFrame.h
js/src/jit/BaselineJIT.cpp
js/src/jit/Ion.cpp
js/src/jit/Ion.h
js/src/jsarray.cpp
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsobj.cpp
js/src/vm/Debugger.cpp
js/src/vm/ScopeObject.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/src/vm/StructuredClone.cpp
js/src/vm/UnboxedObject.cpp
js/src/vm/UnboxedObject.h
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -405,25 +405,25 @@ WriteBarrierPost(JSRuntime* rt, ValueSet
     if (MOZ_UNLIKELY(key.isObject() && IsInsideNursery(&key.toObject()))) {
         rt->gc.storeBuffer.putGeneric(OrderedHashTableRef<UnbarrieredSet>(
                     reinterpret_cast<UnbarrieredSet*>(set), key));
     }
 }
 
 bool
 MapObject::getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj,
-                                       JS::AutoValueVector* entries)
+                                       JS::MutableHandle<GCVector<JS::Value>> entries)
 {
     ValueMap* map = obj->as<MapObject>().getData();
     if (!map)
         return false;
 
     for (ValueMap::Range r = map->all(); !r.empty(); r.popFront()) {
-        if (!entries->append(r.front().key.get()) ||
-            !entries->append(r.front().value))
+        if (!entries.append(r.front().key.get()) ||
+            !entries.append(r.front().value))
         {
             return false;
         }
     }
 
     return true;
 }
 
@@ -1070,24 +1070,24 @@ SetObject::initClass(JSContext* cx, JSOb
         if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
             return nullptr;
     }
     return proto;
 }
 
 
 bool
-SetObject::keys(JSContext* cx, HandleObject obj, JS::AutoValueVector* keys)
+SetObject::keys(JSContext* cx, HandleObject obj, JS::MutableHandle<GCVector<JS::Value>> keys)
 {
     ValueSet* set = obj->as<SetObject>().getData();
     if (!set)
         return false;
 
     for (ValueSet::Range r = set->all(); !r.empty(); r.popFront()) {
-        if (!keys->append(r.front().get()))
+        if (!keys.append(r.front().get()))
             return false;
     }
 
     return true;
 }
 
 bool
 SetObject::add(JSContext* cx, HandleObject obj, HandleValue k)
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -84,17 +84,17 @@ class MapObject : public NativeObject {
     static_assert(Entries == ITEM_KIND_KEY_AND_VALUE,
                   "IteratorKind Entries must match self-hosting define for item kind "
                   "key-and-value.");
 
     static JSObject* initClass(JSContext* cx, JSObject* obj);
     static const Class class_;
 
     static bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj,
-                                            JS::AutoValueVector* entries);
+                                            JS::MutableHandle<GCVector<JS::Value>> entries);
     static bool entries(JSContext* cx, unsigned argc, Value* vp);
     static bool has(JSContext* cx, unsigned argc, Value* vp);
     static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
 
     // Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
     // interfaces, etc.)
     static uint32_t size(JSContext *cx, HandleObject obj);
     static bool get(JSContext *cx, HandleObject obj, HandleValue key, MutableHandleValue rval);
@@ -173,17 +173,17 @@ class MapIteratorObject : public NativeO
 };
 
 class SetObject : public NativeObject {
   public:
     enum IteratorKind { Values, Entries };
     static JSObject* initClass(JSContext* cx, JSObject* obj);
     static const Class class_;
 
-    static bool keys(JSContext *cx, HandleObject obj, JS::AutoValueVector *keys);
+    static bool keys(JSContext *cx, HandleObject obj, JS::MutableHandle<GCVector<JS::Value>> keys);
     static bool values(JSContext *cx, unsigned argc, Value *vp);
     static bool add(JSContext *cx, HandleObject obj, HandleValue key);
     static bool has(JSContext *cx, unsigned argc, Value *vp);
 
     // Publicly exposed Set calls for JSAPI access (webidl maplike/setlike
     // interfaces, etc.)
     static SetObject* create(JSContext *cx, HandleObject proto = nullptr);
     static uint32_t size(JSContext *cx, HandleObject obj);
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -217,17 +217,17 @@ PromiseObject::getID()
  *
  * For the all() case, our reject callback knows what the next promise is, but
  * our resolve callback doesn't.
  *
  * So we walk over our _reject_ callbacks and ask each of them what promise
  * its dependent promise is.
  */
 bool
-PromiseObject::dependentPromises(JSContext* cx, AutoValueVector& values)
+PromiseObject::dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values)
 {
     RootedValue rejectReactionsVal(cx, getReservedSlot(PROMISE_REJECT_REACTIONS_SLOT));
     RootedObject rejectReactions(cx, rejectReactionsVal.toObjectOrNull());
     if (!rejectReactions)
         return true;
 
     AutoIdVector keys(cx);
     if (!GetPropertyKeys(cx, rejectReactions, JSITER_OWNONLY, &keys))
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -49,15 +49,15 @@ class PromiseObject : public NativeObjec
     double lifetime() {
         double now = JS::TimeClip(static_cast<double>(PRMJ_Now()) / PRMJ_USEC_PER_MSEC).toDouble();
         return now - allocationTime();
     }
     double timeToResolution() {
         MOZ_ASSERT(state() != JS::PromiseState::Pending);
         return resolutionTime() - allocationTime();
     }
-    bool dependentPromises(JSContext* cx, AutoValueVector& values);
+    bool dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values);
     double getID();
 };
 
 } // namespace js
 
 #endif /* builtin_Promise_h */
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -1185,17 +1185,17 @@ GetParen(JSLinearString* matched, JS::Va
     }
     JSLinearString& captureLinear = capture.toString()->asLinear();
     out->init(&captureLinear, 0, captureLinear.length());
 }
 
 template <typename CharT>
 static bool
 InterpretDollar(JSLinearString* matched, JSLinearString* string, size_t position, size_t tailPos,
-                AutoValueVector& captures, JSLinearString* replacement,
+                MutableHandle<GCVector<Value>> captures, JSLinearString* replacement,
                 const CharT* replacementBegin, const CharT* currentDollar,
                 const CharT* replacementEnd,
                 JSSubString* out, size_t* skip)
 {
     MOZ_ASSERT(*currentDollar == '$');
 
     /* If there is only a dollar, bail now. */
     if (currentDollar + 1 >= replacementEnd)
@@ -1260,17 +1260,17 @@ InterpretDollar(JSLinearString* matched,
         break;
     }
     return true;
 }
 
 template <typename CharT>
 static bool
 FindReplaceLengthString(JSContext* cx, HandleLinearString matched, HandleLinearString string,
-                        size_t position, size_t tailPos, AutoValueVector& captures,
+                        size_t position, size_t tailPos, MutableHandle<GCVector<Value>> captures,
                         HandleLinearString replacement, size_t firstDollarIndex, size_t* sizep)
 {
     CheckedInt<uint32_t> replen = replacement->length();
 
     JS::AutoCheckCannotGC nogc;
     MOZ_ASSERT(firstDollarIndex < replacement->length());
     const CharT* replacementBegin = replacement->chars<CharT>(nogc);
     const CharT* currentDollar = replacementBegin + firstDollarIndex;
@@ -1299,17 +1299,17 @@ FindReplaceLengthString(JSContext* cx, H
     }
 
     *sizep = replen.value();
     return true;
 }
 
 static bool
 FindReplaceLength(JSContext* cx, HandleLinearString matched, HandleLinearString string,
-                  size_t position, size_t tailPos, AutoValueVector& captures,
+                  size_t position, size_t tailPos, MutableHandle<GCVector<Value>> captures,
                   HandleLinearString replacement, size_t firstDollarIndex, size_t* sizep)
 {
     return replacement->hasLatin1Chars()
            ? FindReplaceLengthString<Latin1Char>(cx, matched, string, position, tailPos, captures,
                                                  replacement, firstDollarIndex, sizep)
            : FindReplaceLengthString<char16_t>(cx, matched, string, position, tailPos, captures,
                                                replacement, firstDollarIndex, sizep);
 }
@@ -1317,17 +1317,17 @@ FindReplaceLength(JSContext* cx, HandleL
 /*
  * Precondition: |sb| already has necessary growth space reserved (as
  * derived from FindReplaceLength), and has been inflated to TwoByte if
  * necessary.
  */
 template <typename CharT>
 static void
 DoReplace(HandleLinearString matched, HandleLinearString string,
-          size_t position, size_t tailPos, AutoValueVector& captures,
+          size_t position, size_t tailPos, MutableHandle<GCVector<Value>> captures,
           HandleLinearString replacement, size_t firstDollarIndex, StringBuffer &sb)
 {
     JS::AutoCheckCannotGC nogc;
     const CharT* replacementBegin = replacement->chars<CharT>(nogc);
     const CharT* currentChar = replacementBegin;
 
     MOZ_ASSERT(firstDollarIndex < replacement->length());
     const CharT* currentDollar = replacementBegin + firstDollarIndex;
@@ -1373,17 +1373,17 @@ js::RegExpGetSubstitution(JSContext* cx,
     // Step 6.
     MOZ_ASSERT(position <= string->length());
 
     // Step 10 (reordered).
     uint32_t nCaptures;
     if (!GetLengthProperty(cx, capturesObj, &nCaptures))
         return false;
 
-    AutoValueVector captures(cx);
+    Rooted<GCVector<Value>> captures(cx, GCVector<Value>(cx));
     if (!captures.reserve(nCaptures))
         return false;
 
     // Step 7.
     RootedValue capture(cx);
     for (uint32_t i = 0; i < nCaptures; i++) {
         if (!GetElement(cx, capturesObj, capturesObj, i, &capture))
             return false;
@@ -1409,36 +1409,36 @@ js::RegExpGetSubstitution(JSContext* cx,
     if (!checkedTailPos.isValid()) {
         ReportAllocationOverflow(cx);
         return false;
     }
     uint32_t tailPos = checkedTailPos.value();
 
     // Step 11.
     size_t reserveLength;
-    if (!FindReplaceLength(cx, matched, string, position, tailPos, captures, replacement,
+    if (!FindReplaceLength(cx, matched, string, position, tailPos, &captures, replacement,
                            firstDollarIndex, &reserveLength))
     {
         return false;
     }
 
     StringBuffer result(cx);
     if (string->hasTwoByteChars() || replacement->hasTwoByteChars()) {
         if (!result.ensureTwoByteChars())
             return false;
     }
 
     if (!result.reserve(reserveLength))
         return false;
 
     if (replacement->hasLatin1Chars()) {
-        DoReplace<Latin1Char>(matched, string, position, tailPos, captures,
+        DoReplace<Latin1Char>(matched, string, position, tailPos, &captures,
                               replacement, firstDollarIndex, result);
     } else {
-        DoReplace<char16_t>(matched, string, position, tailPos, captures,
+        DoReplace<char16_t>(matched, string, position, tailPos, &captures,
                             replacement, firstDollarIndex, result);
     }
 
     // Step 12.
     JSString* resultString = result.finishString();
     if (!resultString)
         return false;
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2506,17 +2506,17 @@ class BackEdge {
 };
 
 // A path-finding handler class for use with JS::ubi::BreadthFirst.
 struct FindPathHandler {
     typedef BackEdge NodeData;
     typedef JS::ubi::BreadthFirst<FindPathHandler> Traversal;
 
     FindPathHandler(JSContext*cx, JS::ubi::Node start, JS::ubi::Node target,
-                    AutoValueVector& nodes, Vector<EdgeName>& edges)
+                    MutableHandle<GCVector<Value>> nodes, Vector<EdgeName>& edges)
       : cx(cx), start(start), target(target), foundPath(false),
         nodes(nodes), edges(edges) { }
 
     bool
     operator()(Traversal& traversal, JS::ubi::Node origin, const JS::ubi::Edge& edge,
                BackEdge* backEdge, bool first)
     {
         // We take care of each node the first time we visit it, so there's
@@ -2575,17 +2575,17 @@ struct FindPathHandler {
     bool foundPath;
 
     // The nodes and edges of the path --- should we find one. The path is
     // stored in reverse order, because that's how it's easiest for us to
     // construct it:
     // - edges[i] is the name of the edge from nodes[i] to nodes[i-1].
     // - edges[0] is the name of the edge from nodes[0] to the target.
     // - The last node, nodes[n-1], is the start node.
-    AutoValueVector& nodes;
+    MutableHandle<GCVector<Value>> nodes;
     Vector<EdgeName>& edges;
 };
 
 } // namespace heaptools
 
 static bool
 FindPath(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -2608,27 +2608,27 @@ FindPath(JSContext* cx, unsigned argc, V
 
     if (!args[1].isObject() && !args[1].isString() && !args[1].isSymbol()) {
         ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
                               JSDVG_SEARCH_STACK, args[0], nullptr,
                               "not an object, string, or symbol", NULL);
         return false;
     }
 
-    AutoValueVector nodes(cx);
+    Rooted<GCVector<Value>> nodes(cx, GCVector<Value>(cx));
     Vector<heaptools::EdgeName> edges(cx);
 
     {
         // 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 handler(cx, start, target, &nodes, edges);
         heaptools::FindPathHandler::Traversal traversal(cx->runtime(), handler, autoCannotGC);
         if (!traversal.init() || !traversal.addStart(start))
             return false;
 
         if (!traversal.traverse())
             return false;
 
         if (!handler.foundPath) {
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -575,17 +575,17 @@ HasLiveIteratorAtStackDepth(JSScript* sc
 //                      +---------------+
 //                      |  ReturnAddr   | <-- return into ArgumentsRectifier after call
 //                      +===============+
 //
 static bool
 InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
                 HandleFunction fun, HandleScript script, IonScript* ionScript,
                 SnapshotIterator& iter, bool invalidate, BaselineStackBuilder& builder,
-                AutoValueVector& startFrameFormals, MutableHandleFunction nextCallee,
+                MutableHandle<GCVector<Value>> startFrameFormals, MutableHandleFunction nextCallee,
                 jsbytecode** callPC, const ExceptionBailoutInfo* excInfo)
 {
     // The Baseline frames we will reconstruct on the heap are not rooted, so GC
     // must be suppressed here.
     MOZ_ASSERT(cx->mainThread().suppressGC);
 
     MOZ_ASSERT(script->hasBaselineScript());
 
@@ -1525,17 +1525,17 @@ jit::BailoutIonToBaseline(JSContext* cx,
 
     JitSpew(JitSpew_BaselineBailouts, "  Restoring frames:");
     size_t frameNo = 0;
 
     // Reconstruct baseline frames using the builder.
     RootedScript caller(cx);
     jsbytecode* callerPC = nullptr;
     RootedFunction fun(cx, callee);
-    AutoValueVector startFrameFormals(cx);
+    Rooted<GCVector<Value>> startFrameFormals(cx, GCVector<Value>(cx));
 
     gc::AutoSuppressGC suppress(cx);
 
     while (true) {
         // Skip recover instructions as they are already recovered by |initInstructionResults|.
         snapIter.settleOnFrame();
 
         if (frameNo > 0) {
@@ -1555,17 +1555,17 @@ jit::BailoutIonToBaseline(JSContext* cx,
 
         // We also need to pass excInfo if we're bailing out in place for
         // debug mode.
         bool passExcInfo = handleException || propagatingExceptionForDebugMode;
 
         jsbytecode* callPC = nullptr;
         RootedFunction nextCallee(cx, nullptr);
         if (!InitFromBailout(cx, caller, callerPC, fun, scr, iter.ionScript(),
-                             snapIter, invalidate, builder, startFrameFormals,
+                             snapIter, invalidate, builder, &startFrameFormals,
                              &nextCallee, &callPC, passExcInfo ? excInfo : nullptr))
         {
             return BAILOUT_RETURN_FATAL_ERROR;
         }
 
         if (!snapIter.moreFrames()) {
             MOZ_ASSERT(!callPC);
             break;
--- a/js/src/jit/BaselineFrame.cpp
+++ b/js/src/jit/BaselineFrame.cpp
@@ -87,27 +87,27 @@ BaselineFrame::trace(JSTracer* trc, JitF
 bool
 BaselineFrame::isNonGlobalEvalFrame() const
 {
     return isEvalFrame() &&
            script()->enclosingStaticScope()->as<StaticEvalScope>().isNonGlobal();
 }
 
 bool
-BaselineFrame::copyRawFrameSlots(AutoValueVector* vec) const
+BaselineFrame::copyRawFrameSlots(MutableHandle<GCVector<Value>> vec) const
 {
     unsigned nfixed = script()->nfixed();
     unsigned nformals = numFormalArgs();
 
-    if (!vec->resize(nformals + nfixed))
+    if (!vec.resize(nformals + nfixed))
         return false;
 
-    mozilla::PodCopy(vec->begin(), argv(), nformals);
+    mozilla::PodCopy(vec.begin(), argv(), nformals);
     for (unsigned i = 0; i < nfixed; i++)
-        (*vec)[nformals + i].set(*valueSlot(i));
+        vec[nformals + i].set(*valueSlot(i));
     return true;
 }
 
 bool
 BaselineFrame::initStrictEvalScopeObjects(JSContext* cx)
 {
     MOZ_ASSERT(isStrictEvalFrame());
 
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -224,17 +224,17 @@ class BaselineFrame
         if (isConstructing()) {
             return *(Value*)(reinterpret_cast<const uint8_t*>(this) +
                              BaselineFrame::Size() +
                              offsetOfArg(Max(numFormalArgs(), numActualArgs())));
         }
         return UndefinedValue();
     }
 
-    bool copyRawFrameSlots(AutoValueVector* vec) const;
+    bool copyRawFrameSlots(MutableHandle<GCVector<Value>> vec) const;
 
     bool hasReturnValue() const {
         return flags_ & HAS_RVAL;
     }
     MutableHandleValue returnValue() {
         if (!hasReturnValue())
             addressOfReturnValue()->setUndefined();
         return MutableHandleValue::fromMarkedLocation(addressOfReturnValue());
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -176,18 +176,18 @@ EnterBaseline(JSContext* cx, EnterJitDat
 JitExecStatus
 jit::EnterBaselineMethod(JSContext* cx, RunState& state)
 {
     BaselineScript* baseline = state.script()->baselineScript();
 
     EnterJitData data(cx);
     data.jitcode = baseline->method()->raw();
 
-    AutoValueVector vals(cx);
-    if (!SetEnterJitData(cx, data, state, vals))
+    Rooted<GCVector<Value>> vals(cx, GCVector<Value>(cx));
+    if (!SetEnterJitData(cx, data, state, &vals))
         return JitExec_Error;
 
     JitExecStatus status = EnterBaseline(cx, data);
     if (status != JitExec_Ok)
         return status;
 
     state.setReturnValue(data.result);
     return JitExec_Ok;
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2780,17 +2780,18 @@ EnterIon(JSContext* cx, EnterJitData& da
     // Release temporary buffer used for OSR into Ion.
     cx->runtime()->getJitRuntime(cx)->freeOsrTempData();
 
     MOZ_ASSERT_IF(data.result.isMagic(), data.result.isMagic(JS_ION_ERROR));
     return data.result.isMagic() ? JitExec_Error : JitExec_Ok;
 }
 
 bool
-jit::SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state, AutoValueVector& vals)
+jit::SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state,
+                     MutableHandle<GCVector<Value>> vals)
 {
     data.osrFrame = nullptr;
 
     if (state.isInvoke()) {
         const CallArgs& args = state.asInvoke()->args();
         unsigned numFormals = state.script()->functionNonDelazifying()->nargs();
         data.constructing = state.asInvoke()->constructing();
         data.numActualArgs = args.length();
@@ -2850,18 +2851,18 @@ jit::SetEnterJitData(JSContext* cx, Ente
 JitExecStatus
 jit::IonCannon(JSContext* cx, RunState& state)
 {
     IonScript* ion = state.script()->ionScript();
 
     EnterJitData data(cx);
     data.jitcode = ion->method()->raw();
 
-    AutoValueVector vals(cx);
-    if (!SetEnterJitData(cx, data, state, vals))
+    Rooted<GCVector<Value>> vals(cx, GCVector<Value>(cx));
+    if (!SetEnterJitData(cx, data, state, &vals))
         return JitExec_Error;
 
     JitExecStatus status = EnterIon(cx, data);
 
     if (status == JitExec_Ok)
         state.setReturnValue(data.result);
 
     return status;
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -109,17 +109,18 @@ enum JitExecStatus
 static inline bool
 IsErrorStatus(JitExecStatus status)
 {
     return status == JitExec_Error || status == JitExec_Aborted;
 }
 
 struct EnterJitData;
 
-bool SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state, AutoValueVector& vals);
+bool SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state,
+                     MutableHandle<GCVector<Value>> vals);
 
 JitExecStatus IonCannon(JSContext* cx, RunState& state);
 
 // Used to enter Ion from C++ natives like Array.map. Called from FastInvokeGuard.
 JitExecStatus FastInvoke(JSContext* cx, HandleFunction fun, CallArgs& args);
 
 // Walk the stack and invalidate active Ion frames for the invalid scripts.
 void Invalidate(TypeZone& types, FreeOp* fop,
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1716,19 +1716,19 @@ MatchNumericComparator(JSContext* cx, co
     if (arg0 == 1 && arg1 == 0)
         return Match_RightMinusLeft;
 
     return Match_None;
 }
 
 template <typename K, typename C>
 static inline bool
-MergeSortByKey(K keys, size_t len, K scratch, C comparator, AutoValueVector* vec)
+MergeSortByKey(K keys, size_t len, K scratch, C comparator, MutableHandle<GCVector<Value>> vec)
 {
-    MOZ_ASSERT(vec->length() >= len);
+    MOZ_ASSERT(vec.length() >= len);
 
     /* Sort keys. */
     if (!MergeSort(keys, len, scratch, comparator))
         return false;
 
     /*
      * Reorder vec by keys in-place, going element by element.  When an out-of-
      * place element is encountered, move that element to its proper position,
@@ -1742,58 +1742,58 @@ MergeSortByKey(K keys, size_t len, K scr
      * Θ(len) + O(len) == O(2*len), with each element visited at most twice.
      */
     for (size_t i = 0; i < len; i++) {
         size_t j = keys[i].elementIndex;
         if (i == j)
             continue; // fixed point
 
         MOZ_ASSERT(j > i, "Everything less than |i| should be in the right place!");
-        Value tv = (*vec)[j];
+        Value tv = vec[j];
         do {
             size_t k = keys[j].elementIndex;
             keys[j].elementIndex = j;
-            (*vec)[j].set((*vec)[k]);
+            vec[j].set(vec[k]);
             j = k;
         } while (j != i);
 
         // We could assert the loop invariant that |i == keys[i].elementIndex|
         // here if we synced |keys[i].elementIndex|.  But doing so would render
         // the assertion vacuous, so don't bother, even in debug builds.
-        (*vec)[i].set(tv);
+        vec[i].set(tv);
     }
 
     return true;
 }
 
 /*
  * Sort Values as strings.
  *
  * To minimize #conversions, SortLexicographically() first converts all Values
  * to strings at once, then sorts the elements by these cached strings.
  */
 static bool
-SortLexicographically(JSContext* cx, AutoValueVector* vec, size_t len)
+SortLexicographically(JSContext* cx, MutableHandle<GCVector<Value>> vec, size_t len)
 {
-    MOZ_ASSERT(vec->length() >= len);
+    MOZ_ASSERT(vec.length() >= len);
 
     StringBuffer sb(cx);
     Vector<StringifiedElement, 0, TempAllocPolicy> strElements(cx);
 
     /* MergeSort uses the upper half as scratch space. */
     if (!strElements.resize(2 * len))
         return false;
 
     /* Convert Values to strings. */
     size_t cursor = 0;
     for (size_t i = 0; i < len; i++) {
         if (!CheckForInterrupt(cx))
             return false;
 
-        if (!ValueToStringBuffer(cx, (*vec)[i], sb))
+        if (!ValueToStringBuffer(cx, vec[i], sb))
             return false;
 
         strElements[i] = { cursor, sb.length(), i };
         cursor = sb.length();
     }
 
     /* Sort Values in vec alphabetically. */
     return MergeSortByKey(strElements.begin(), len, strElements.begin() + len,
@@ -1802,33 +1802,34 @@ SortLexicographically(JSContext* cx, Aut
 
 /*
  * Sort Values as numbers.
  *
  * To minimize #conversions, SortNumerically first converts all Values to
  * numerics at once, then sorts the elements by these cached numerics.
  */
 static bool
-SortNumerically(JSContext* cx, AutoValueVector* vec, size_t len, ComparatorMatchResult comp)
+SortNumerically(JSContext* cx, MutableHandle<GCVector<Value>> vec, size_t len,
+                ComparatorMatchResult comp)
 {
-    MOZ_ASSERT(vec->length() >= len);
+    MOZ_ASSERT(vec.length() >= len);
 
     Vector<NumericElement, 0, TempAllocPolicy> numElements(cx);
 
     /* MergeSort uses the upper half as scratch space. */
     if (!numElements.resize(2 * len))
         return false;
 
     /* Convert Values to numerics. */
     for (size_t i = 0; i < len; i++) {
         if (!CheckForInterrupt(cx))
             return false;
 
         double dv;
-        if (!ToNumber(cx, (*vec)[i], &dv))
+        if (!ToNumber(cx, vec[i], &dv))
             return false;
 
         numElements[i] = { dv, i };
     }
 
     /* Sort Values in vec numerically. */
     return MergeSortByKey(numElements.begin(), len, numElements.begin() + len,
                           SortComparatorNumerics[comp], vec);
@@ -1907,17 +1908,17 @@ js::array_sort(JSContext* cx, unsigned a
      * property at the corresponding index exists and its value must be rooted.
      *
      * In this way when sorting a huge mostly sparse array we will not
      * access the tail of vec corresponding to properties that do not
      * exist, allowing OS to avoiding committing RAM. See bug 330812.
      */
     size_t n, undefs;
     {
-        AutoValueVector vec(cx);
+        Rooted<GCVector<Value>> vec(cx, GCVector<Value>(cx));
         if (!vec.reserve(2 * size_t(len)))
             return false;
 
         /*
          * By ECMA 262, 15.4.4.11, a property that does not exist (which we
          * call a "hole") is always greater than an existing property with
          * value undefined and that is always greater than any other property.
          * Thus to sort holes and undefs we simply count them, sort the rest
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -501,16 +501,26 @@ JSCompartment::wrap(JSContext* cx, Mutab
     if (desc.hasSetterObject()) {
         if (!wrap(cx, desc.setterObject()))
             return false;
     }
 
     return wrap(cx, desc.value());
 }
 
+bool
+JSCompartment::wrap(JSContext* cx, MutableHandle<GCVector<Value>> vec)
+{
+    for (size_t i = 0; i < vec.length(); ++i) {
+        if (!wrap(cx, vec[i]))
+            return false;
+    }
+    return true;
+}
+
 ClonedBlockObject*
 JSCompartment::getOrCreateNonSyntacticLexicalScope(JSContext* cx,
                                                    HandleObject enclosingStatic,
                                                    HandleObject enclosingScope)
 {
     if (!nonSyntacticLexicalScopes_) {
         nonSyntacticLexicalScopes_ = cx->new_<ObjectWeakMap>(cx);
         if (!nonSyntacticLexicalScopes_ || !nonSyntacticLexicalScopes_->init())
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -525,25 +525,17 @@ struct JSCompartment
 
     MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp,
                                             JS::HandleObject existing = nullptr);
 
     MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandleString strp);
     MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandleObject obj,
                                      JS::HandleObject existingArg = nullptr);
     MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
-
-    template<typename T> MOZ_MUST_USE bool wrap(JSContext* cx,
-                                                JS::AutoVectorRooter<T>& vec) {
-        for (size_t i = 0; i < vec.length(); ++i) {
-            if (!wrap(cx, vec[i]))
-                return false;
-        }
-        return true;
-    };
+    MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<JS::GCVector<JS::Value>> vec);
 
     MOZ_MUST_USE bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped,
                                  const js::Value& wrapper);
 
     js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) const {
         return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(wrapped));
     }
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1171,17 +1171,17 @@ js::CloneObject(JSContext* cx, HandleObj
         if (!CopyProxyObject(cx, obj.as<ProxyObject>(), clone.as<ProxyObject>()))
             return nullptr;
     }
 
     return clone;
 }
 
 static bool
-GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, AutoValueVector& values)
+GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle<GCVector<Value>> values)
 {
     MOZ_ASSERT(!obj->isSingleton());
     MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
 
     size_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
     if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), length))
         return false;
 
@@ -1281,18 +1281,18 @@ js::DeepCloneObjectLiteral(JSContext* cx
     /* NB: Keep this in sync with XDRObjectLiteral. */
     MOZ_ASSERT_IF(obj->isSingleton(),
                   cx->compartment()->behaviors().getSingletonsAsTemplates());
     MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() ||
                obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
     MOZ_ASSERT(newKind != SingletonObject);
 
     if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) {
-        AutoValueVector values(cx);
-        if (!GetScriptArrayObjectElements(cx, obj, values))
+        Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
+        if (!GetScriptArrayObjectElements(cx, obj, &values))
             return nullptr;
 
         // Deep clone any elements.
         for (uint32_t i = 0; i < values.length(); ++i) {
             if (!DeepCloneValue(cx, values[i].address(), newKind))
                 return nullptr;
         }
 
@@ -1410,18 +1410,18 @@ js::XDRObjectLiteral(XDRState<mode>* xdr
         if (!xdr->codeUint32(&isArray))
             return false;
     }
 
     RootedValue tmpValue(cx), tmpIdValue(cx);
     RootedId tmpId(cx);
 
     if (isArray) {
-        AutoValueVector values(cx);
-        if (mode == XDR_ENCODE && !GetScriptArrayObjectElements(cx, obj, values))
+        Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
+        if (mode == XDR_ENCODE && !GetScriptArrayObjectElements(cx, obj, &values))
             return false;
 
         uint32_t initialized;
         if (mode == XDR_ENCODE)
             initialized = values.length();
         if (!xdr->codeUint32(&initialized))
             return false;
         if (mode == XDR_DECODE && !values.appendN(MagicValue(JS_ELEMENTS_HOLE), initialized))
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -8065,17 +8065,17 @@ DebuggerObject_getPromiseID(JSContext* c
     return true;
 }
 
 static bool
 DebuggerObject_getPromiseDependentPromises(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, "get promiseDependentPromises", args, dbg, refobj);
 
-    AutoValueVector values(cx);
+    Rooted<GCVector<Value>> values(cx, GCVector<Value>());
     {
         JSAutoCompartment ac(cx, promise);
         if (!promise->dependentPromises(cx, values))
             return false;
     }
     for (size_t i = 0; i < values.length(); i++) {
         if (!dbg->wrapDebuggeeValue(cx, values[i]))
             return false;
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -2724,17 +2724,17 @@ DebugScopes::onPopCall(AbstractFramePtr 
      * invariants since DebugScopeObject::maybeSnapshot can already be nullptr.
      */
     if (debugScope) {
         /*
          * Copy all frame values into the snapshot, regardless of
          * aliasing. This unnecessarily includes aliased variables
          * but it simplifies later indexing logic.
          */
-        AutoValueVector vec(cx);
+        Rooted<GCVector<Value>> vec(cx, GCVector<Value>(cx));
         if (!frame.copyRawFrameSlots(&vec) || vec.length() == 0)
             return;
 
         /*
          * Copy in formals that are not aliased via the scope chain
          * but are aliased via the arguments object.
          */
         RootedScript script(cx, frame.script());
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -752,17 +752,17 @@ AbstractFramePtr::initArgsObj(ArgumentsO
     if (isInterpreterFrame()) {
         asInterpreterFrame()->initArgsObj(argsobj);
         return;
     }
     asBaselineFrame()->initArgsObj(argsobj);
 }
 
 inline bool
-AbstractFramePtr::copyRawFrameSlots(AutoValueVector* vec) const
+AbstractFramePtr::copyRawFrameSlots(MutableHandle<GCVector<Value>> vec) const
 {
     if (isInterpreterFrame())
         return asInterpreterFrame()->copyRawFrameSlots(vec);
     return asBaselineFrame()->copyRawFrameSlots(vec);
 }
 
 inline bool
 AbstractFramePtr::prevUpToDate() const
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -76,22 +76,22 @@ InterpreterFrame::initExecuteFrame(JSCon
 bool
 InterpreterFrame::isNonGlobalEvalFrame() const
 {
     return isEvalFrame() &&
            script()->enclosingStaticScope()->as<StaticEvalScope>().isNonGlobal();
 }
 
 bool
-InterpreterFrame::copyRawFrameSlots(AutoValueVector* vec)
+InterpreterFrame::copyRawFrameSlots(MutableHandle<GCVector<Value>> vec)
 {
-    if (!vec->resize(numFormalArgs() + script()->nfixed()))
+    if (!vec.resize(numFormalArgs() + script()->nfixed()))
         return false;
-    PodCopy(vec->begin(), argv(), numFormalArgs());
-    PodCopy(vec->begin() + numFormalArgs(), slots(), script()->nfixed());
+    PodCopy(vec.begin(), argv(), numFormalArgs());
+    PodCopy(vec.begin() + numFormalArgs(), slots(), script()->nfixed());
     return true;
 }
 
 JSObject*
 InterpreterFrame::createRestParameter(JSContext* cx)
 {
     MOZ_ASSERT(callee().hasRest());
     unsigned nformal = callee().nargs() - 1, nactual = numActualArgs();
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -228,17 +228,17 @@ class AbstractFramePtr
     inline Value* argv() const;
 
     inline bool hasArgs() const;
     inline bool hasArgsObj() const;
     inline ArgumentsObject& argsObj() const;
     inline void initArgsObj(ArgumentsObject& argsobj) const;
     inline bool createSingleton() const;
 
-    inline bool copyRawFrameSlots(AutoValueVector* vec) const;
+    inline bool copyRawFrameSlots(MutableHandle<GCVector<Value>> vec) const;
 
     inline Value& unaliasedLocal(uint32_t i);
     inline Value& unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value& unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     template <class Op> inline void unaliasedForEachActual(JSContext* cx, Op op);
 
     inline bool prevUpToDate() const;
     inline void setPrevUpToDate() const;
@@ -495,17 +495,17 @@ class InterpreterFrame
 
     inline Value& unaliasedLocal(uint32_t i);
 
     bool hasArgs() const { return isFunctionFrame(); }
     inline Value& unaliasedFormal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
     inline Value& unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
     template <class Op> inline void unaliasedForEachActual(Op op);
 
-    bool copyRawFrameSlots(AutoValueVector* v);
+    bool copyRawFrameSlots(MutableHandle<GCVector<Value>> v);
 
     unsigned numFormalArgs() const { MOZ_ASSERT(hasArgs()); return callee().nargs(); }
     unsigned numActualArgs() const { MOZ_ASSERT(hasArgs()); return nactual_; }
 
     /* Watch out, this exposes a pointer to the unaliased formal arg array. */
     Value* argv() const { MOZ_ASSERT(hasArgs()); return argv_; }
 
     /*
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -989,26 +989,26 @@ JSStructuredCloneWriter::traverseObject(
     if (!GetBuiltinClass(context(), obj, &cls))
         return false;
     return out.writePair(cls == ESClass_Array ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0);
 }
 
 bool
 JSStructuredCloneWriter::traverseMap(HandleObject obj)
 {
-    AutoValueVector newEntries(context());
+    Rooted<GCVector<Value>> newEntries(context(), GCVector<Value>(context()));
     {
         // If there is no wrapper, the compartment munging is a no-op.
         RootedObject unwrapped(context(), CheckedUnwrap(obj));
         MOZ_ASSERT(unwrapped);
         JSAutoCompartment ac(context(), unwrapped);
         if (!MapObject::getKeysAndValuesInterleaved(context(), unwrapped, &newEntries))
             return false;
     }
-    if (!context()->compartment()->wrap(context(), newEntries))
+    if (!context()->compartment()->wrap(context(), &newEntries))
         return false;
 
     for (size_t i = newEntries.length(); i > 0; --i) {
         if (!entries.append(newEntries[i - 1]))
             return false;
     }
 
     /* Push obj and count to the stack. */
@@ -1019,26 +1019,26 @@ JSStructuredCloneWriter::traverseMap(Han
 
     /* Write the header for obj. */
     return out.writePair(SCTAG_MAP_OBJECT, 0);
 }
 
 bool
 JSStructuredCloneWriter::traverseSet(HandleObject obj)
 {
-    AutoValueVector keys(context());
+    Rooted<GCVector<Value>> keys(context(), GCVector<Value>(context()));
     {
         // If there is no wrapper, the compartment munging is a no-op.
         RootedObject unwrapped(context(), CheckedUnwrap(obj));
         MOZ_ASSERT(unwrapped);
         JSAutoCompartment ac(context(), unwrapped);
         if (!SetObject::keys(context(), unwrapped, &keys))
             return false;
     }
-    if (!context()->compartment()->wrap(context(), keys))
+    if (!context()->compartment()->wrap(context(), &keys))
         return false;
 
     for (size_t i = keys.length(); i > 0; --i) {
         if (!entries.append(keys[i - 1]))
             return false;
     }
 
     /* Push obj and count to the stack. */
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -948,34 +948,35 @@ const Class UnboxedPlainObject::class_ =
 };
 
 /////////////////////////////////////////////////////////////////////
 // UnboxedArrayObject
 /////////////////////////////////////////////////////////////////////
 
 template <JSValueType Type>
 DenseElementResult
-AppendUnboxedDenseElements(UnboxedArrayObject* obj, uint32_t initlen, AutoValueVector* values)
+AppendUnboxedDenseElements(UnboxedArrayObject* obj, uint32_t initlen,
+                           MutableHandle<GCVector<Value>> values)
 {
     for (size_t i = 0; i < initlen; i++)
-        values->infallibleAppend(obj->getElementSpecific<Type>(i));
+        values.infallibleAppend(obj->getElementSpecific<Type>(i));
     return DenseElementResult::Success;
 }
 
 DefineBoxedOrUnboxedFunctor3(AppendUnboxedDenseElements,
-                             UnboxedArrayObject*, uint32_t, AutoValueVector*);
+                             UnboxedArrayObject*, uint32_t, MutableHandle<GCVector<Value>>);
 
 /* static */ bool
 UnboxedArrayObject::convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj,
                                              ObjectGroup* group, Shape* shape)
 {
     size_t length = obj->as<UnboxedArrayObject>().length();
     size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
 
-    AutoValueVector values(cx);
+    Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
     if (!values.reserve(initlen))
         return false;
 
     AppendUnboxedDenseElementsFunctor functor(&obj->as<UnboxedArrayObject>(), initlen, &values);
     DebugOnly<DenseElementResult> result = CallBoxedOrUnboxedSpecialization(functor, obj);
     MOZ_ASSERT(result.value == DenseElementResult::Success);
 
     obj->setGroup(group);
@@ -1843,38 +1844,38 @@ SetLayoutTraceList(ExclusiveContext* cx,
         PodCopy(traceList, entries.begin(), entries.length());
         layout->setTraceList(traceList);
     }
 
     return true;
 }
 
 static inline Value
-NextValue(const AutoValueVector& values, size_t* valueCursor)
+NextValue(Handle<GCVector<Value>> values, size_t* valueCursor)
 {
     return values[(*valueCursor)++];
 }
 
 static bool
-GetValuesFromPreliminaryArrayObject(ArrayObject* obj, AutoValueVector& values)
+GetValuesFromPreliminaryArrayObject(ArrayObject* obj, MutableHandle<GCVector<Value>> values)
 {
     if (!values.append(Int32Value(obj->length())))
         return false;
     if (!values.append(Int32Value(obj->getDenseInitializedLength())))
         return false;
     for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) {
         if (!values.append(obj->getDenseElement(i)))
             return false;
     }
     return true;
 }
 
 void
 UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx,
-                                     const AutoValueVector& values, size_t* valueCursor)
+                                     Handle<GCVector<Value>> values, size_t* valueCursor)
 {
     MOZ_ASSERT(CapacityArray[1] == 0);
     setCapacityIndex(1);
     setInitializedLengthNoBarrier(0);
     setInlineElements();
 
     setLength(cx, NextValue(values, valueCursor).toInt32());
 
@@ -1888,28 +1889,28 @@ UnboxedArrayObject::fillAfterConvert(Exc
 
     setInitializedLength(initlen);
 
     for (size_t i = 0; i < size_t(initlen); i++)
         JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor)));
 }
 
 static bool
-GetValuesFromPreliminaryPlainObject(PlainObject* obj, AutoValueVector& values)
+GetValuesFromPreliminaryPlainObject(PlainObject* obj, MutableHandle<GCVector<Value>> values)
 {
     for (size_t i = 0; i < obj->slotSpan(); i++) {
         if (!values.append(obj->getSlot(i)))
             return false;
     }
     return true;
 }
 
 void
 UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx,
-                                     const AutoValueVector& values, size_t* valueCursor)
+                                     Handle<GCVector<Value>> values, size_t* valueCursor)
 {
     initExpando();
     memset(data(), 0, layout().size());
     for (size_t i = 0; i < layout().properties().length(); i++)
         JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor)));
 }
 
 bool
@@ -2035,27 +2036,27 @@ js::TryConvertToUnboxedLayout(ExclusiveC
     Shape* newShape = EmptyShape::getInitialShape(cx, clasp, group->proto(), 0);
     if (!newShape) {
         cx->recoverFromOutOfMemory();
         return false;
     }
 
     // Accumulate a list of all the values in each preliminary object, and
     // update their shapes.
-    AutoValueVector values(cx);
+    Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
     for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
         JSObject* obj = objects->get(i);
         if (!obj)
             continue;
 
         bool ok;
         if (isArray)
-            ok = GetValuesFromPreliminaryArrayObject(&obj->as<ArrayObject>(), values);
+            ok = GetValuesFromPreliminaryArrayObject(&obj->as<ArrayObject>(), &values);
         else
-            ok = GetValuesFromPreliminaryPlainObject(&obj->as<PlainObject>(), values);
+            ok = GetValuesFromPreliminaryPlainObject(&obj->as<PlainObject>(), &values);
 
         if (!ok) {
             cx->recoverFromOutOfMemory();
             return false;
         }
     }
 
     if (TypeNewScript* newScript = group->newScript())
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -298,17 +298,17 @@ class UnboxedPlainObject : public JSObje
 
     static bool convertToNative(JSContext* cx, JSObject* obj);
     static UnboxedPlainObject* create(ExclusiveContext* cx, HandleObjectGroup group,
                                       NewObjectKind newKind);
     static JSObject* createWithProperties(ExclusiveContext* cx, HandleObjectGroup group,
                                           NewObjectKind newKind, IdValuePair* properties);
 
     void fillAfterConvert(ExclusiveContext* cx,
-                          const AutoValueVector& values, size_t* valueCursor);
+                          Handle<GCVector<Value>> values, size_t* valueCursor);
 
     static void trace(JSTracer* trc, JSObject* object);
 
     static size_t offsetOfExpando() {
         return offsetof(UnboxedPlainObject, expando_);
     }
 
     static size_t offsetOfData() {
@@ -421,17 +421,17 @@ class UnboxedArrayObject : public JSObje
                                       uint32_t length, NewObjectKind newKind,
                                       uint32_t maxLength = MaximumCapacity);
 
     static bool convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj,
                                          ObjectGroup* group, Shape* shape);
     bool convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group);
 
     void fillAfterConvert(ExclusiveContext* cx,
-                          const AutoValueVector& values, size_t* valueCursor);
+                          Handle<GCVector<Value>> values, size_t* valueCursor);
 
     static void trace(JSTracer* trc, JSObject* object);
     static void objectMoved(JSObject* obj, const JSObject* old);
     static void finalize(FreeOp* fop, JSObject* obj);
 
     static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src,
                                            gc::AllocKind allocKind);