Bug 1534967 - Part 1: use RootedIdVector. r=jonco
authorYoshi Cheng-Hao Huang <allstars.chh@gmail.com>
Wed, 13 Mar 2019 13:33:15 +0100
changeset 468303 427b854cdb1c47ce6a643f83245914d66dca4382
parent 468302 1c0ed04569945302bf7d99ca5c8787623adfbbb6
child 468304 fbbc1ac9d28a55b23613e33ac660656d20336936
push id112702
push userallstars.chh@gmail.com
push dateMon, 08 Apr 2019 02:51:20 +0000
treeherdermozilla-inbound@2c5c5fd10cd6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1534967
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 1534967 - Part 1: use RootedIdVector. r=jonco Differential Revision: https://phabricator.services.mozilla.com/D25042
dom/base/ChromeUtils.cpp
dom/base/MaybeCrossOriginObject.cpp
dom/base/MaybeCrossOriginObject.h
dom/base/RemoteOuterWindowProxy.cpp
dom/base/WindowNamedPropertiesHandler.cpp
dom/base/WindowNamedPropertiesHandler.h
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowInner.h
dom/base/nsGlobalWindowOuter.cpp
dom/base/nsObjectLoadingContent.cpp
dom/base/nsObjectLoadingContent.h
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/DOMJSClass.h
dom/bindings/DOMJSProxyHandler.cpp
dom/bindings/DOMJSProxyHandler.h
dom/bindings/RemoteObjectProxy.cpp
dom/bindings/RemoteObjectProxy.h
dom/bindings/WebIDLGlobalNameHash.cpp
dom/bindings/WebIDLGlobalNameHash.h
dom/plugins/base/nsJSNPRuntime.cpp
js/ipc/WrapperAnswer.cpp
js/ipc/WrapperOwner.cpp
js/ipc/WrapperOwner.h
js/public/Class.h
js/public/Proxy.h
js/public/TypeDecls.h
js/public/Wrapper.h
js/src/NamespaceImports.h
js/src/builtin/Array.cpp
js/src/builtin/JSON.cpp
js/src/builtin/ModuleObject.cpp
js/src/builtin/ModuleObject.h
js/src/builtin/Object.cpp
js/src/builtin/TestingFunctions.cpp
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/proxy/BaseProxyHandler.cpp
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/proxy/DeadObjectProxy.cpp
js/src/proxy/DeadObjectProxy.h
js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
js/src/proxy/Proxy.cpp
js/src/proxy/Proxy.h
js/src/proxy/ScriptedProxyHandler.cpp
js/src/proxy/ScriptedProxyHandler.h
js/src/proxy/Wrapper.cpp
js/src/shell/js.cpp
js/src/shell/jsshell.cpp
js/src/vm/Debugger.cpp
js/src/vm/EnvironmentObject.cpp
js/src/vm/EnvironmentObject.h
js/src/vm/Iteration.cpp
js/src/vm/Iteration.h
js/src/vm/JSObject.cpp
js/src/vm/JSObject.h
js/src/vm/SelfHosting.cpp
js/src/vm/Shape.cpp
js/src/vm/StructuredClone.cpp
js/src/wasm/WasmModule.cpp
js/xpconnect/idl/nsIXPCScriptable.idl
js/xpconnect/public/xpc_make_class.h
js/xpconnect/public/xpc_map_end.h
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCRuntimeService.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/FilteringWrapper.cpp
js/xpconnect/wrappers/FilteringWrapper.h
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -222,17 +222,17 @@ void ChromeUtils::ShallowClone(GlobalObj
                                JS::MutableHandleObject aRetval,
                                ErrorResult& aRv) {
   JSContext* cx = aGlobal.Context();
 
   auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
 
   JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
   JS::RootedVector<JS::Value> values(cx);
-  JS::AutoIdVector valuesIds(cx);
+  JS::RootedVector<jsid> valuesIds(cx);
 
   {
     // cx represents our current Realm, so it makes sense to use it for the
     // CheckedUnwrapDynamic call.  We do want CheckedUnwrapDynamic, in case
     // someone is shallow-cloning a Window.
     JS::RootedObject obj(cx, js::CheckedUnwrapDynamic(aObj, cx));
     if (!obj) {
       js::ReportAccessDenied(cx);
--- a/dom/base/MaybeCrossOriginObject.cpp
+++ b/dom/base/MaybeCrossOriginObject.cpp
@@ -432,28 +432,28 @@ bool MaybeCrossOriginObject<Base>::defin
   JS_MarkCrossZoneId(cx, id);
 
   return definePropertySameOrigin(cx, proxy, id, descCopy, result);
 }
 
 template <typename Base>
 bool MaybeCrossOriginObject<Base>::enumerate(JSContext* cx,
                                              JS::Handle<JSObject*> proxy,
-                                             JS::AutoIdVector& props) const {
+                                             JS::MutableHandleVector<jsid> props) const {
   // Just get the property keys from ourselves, in whatever Realm we happen to
   // be in. It's important to not enter the Realm of "proxy" here, because that
   // would affect the list of keys we claim to have. We wrap the proxy in the
   // current compartment just to be safe; it doesn't affect behavior as far as
   // CrossOriginObjectWrapper and MaybeCrossOriginObject are concerned.
   JS::Rooted<JSObject*> self(cx, proxy);
   if (!MaybeWrapObject(cx, &self)) {
     return false;
   }
 
-  return js::GetPropertyKeys(cx, self, 0, &props);
+  return js::GetPropertyKeys(cx, self, 0, props);
 }
 
 template <typename Base>
 bool MaybeCrossOriginObject<Base>::hasInstance(JSContext* cx,
                                                JS::Handle<JSObject*> proxy,
                                                JS::MutableHandle<JS::Value> v,
                                                bool* bp) const {
   if (!IsPlatformObjectSameOrigin(cx, proxy)) {
--- a/dom/base/MaybeCrossOriginObject.h
+++ b/dom/base/MaybeCrossOriginObject.h
@@ -311,17 +311,17 @@ class MaybeCrossOriginObject : public Ba
    */
   bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                JS::ObjectOpResult& result) const override = 0;
 
   /**
    * Spidermonkey-internal hook for enumerating objects.
    */
   bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
-                 JS::AutoIdVector& props) const final;
+                 JS::MutableHandleVector<jsid> props) const final;
 
   /**
    * Spidermonkey-internal hook used for instanceof.  We need to override this
    * because otherwise we can end up doing instanceof work in the wrong
    * compartment.
    */
   bool hasInstance(JSContext* cx, JS::Handle<JSObject*> proxy,
                    JS::MutableHandle<JS::Value> v, bool* bp) const final;
--- a/dom/base/RemoteOuterWindowProxy.cpp
+++ b/dom/base/RemoteOuterWindowProxy.cpp
@@ -37,21 +37,21 @@ class RemoteOuterWindowProxy
   constexpr RemoteOuterWindowProxy()
       : RemoteObjectProxy(prototypes::id::Window) {}
 
   // Standard internal methods
   bool getOwnPropertyDescriptor(
       JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
       JS::MutableHandle<JS::PropertyDescriptor> aDesc) const final;
   bool ownPropertyKeys(JSContext* aCx, JS::Handle<JSObject*> aProxy,
-                       JS::AutoIdVector& aProps) const final;
+                       JS::MutableHandleVector<jsid> aProps) const final;
 
   // SpiderMonkey extensions
   bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
-                                    JS::AutoIdVector& props) const final;
+                                    JS::MutableHandleVector<jsid> props) const final;
 
   void NoteChildren(JSObject* aProxy,
                     nsCycleCollectionTraversalCallback& aCb) const override {
     CycleCollectionNoteChild(aCb,
                              static_cast<BrowsingContext*>(GetNative(aProxy)),
                              "js::GetObjectPrivate(obj)");
   }
 };
@@ -123,44 +123,44 @@ bool RemoteOuterWindowProxy::getOwnPrope
       }
     }
   }
 
   return CrossOriginPropertyFallback(aCx, aProxy, aId, aDesc);
 }
 
 bool AppendIndexedPropertyNames(JSContext* aCx, BrowsingContext* aContext,
-                                JS::AutoIdVector& aIndexedProps) {
+                                JS::MutableHandleVector<jsid> aIndexedProps) {
   int32_t length = aContext->GetChildren().Length();
   if (!aIndexedProps.reserve(aIndexedProps.length() + length)) {
     return false;
   }
 
   for (int32_t i = 0; i < length; ++i) {
     aIndexedProps.infallibleAppend(INT_TO_JSID(i));
   }
   return true;
 }
 
 bool RemoteOuterWindowProxy::ownPropertyKeys(JSContext* aCx,
                                              JS::Handle<JSObject*> aProxy,
-                                             JS::AutoIdVector& aProps) const {
+                                             JS::MutableHandleVector<jsid> aProps) const {
   BrowsingContext* bc = GetBrowsingContext(aProxy);
 
   // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys:crossoriginownpropertykeys-(-o-)
   // step 3 to 5
   if (!AppendIndexedPropertyNames(aCx, bc, aProps)) {
     return false;
   }
 
   // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys:crossoriginownpropertykeys-(-o-)
   // step 7
   return RemoteObjectProxy::ownPropertyKeys(aCx, aProxy, aProps);
 }
 
 bool RemoteOuterWindowProxy::getOwnEnumerablePropertyKeys(
     JSContext* aCx, JS::Handle<JSObject*> aProxy,
-    JS::AutoIdVector& aProps) const {
+    JS::MutableHandleVector<jsid> aProps) const {
   return AppendIndexedPropertyNames(aCx, GetBrowsingContext(aProxy), aProps);
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -152,17 +152,17 @@ bool WindowNamedPropertiesHandler::defin
   ErrorResult rv;
   rv.ThrowTypeError<MSG_DEFINEPROPERTY_ON_GSP>();
   MOZ_ALWAYS_TRUE(rv.MaybeSetPendingException(aCx));
   return false;
 }
 
 bool WindowNamedPropertiesHandler::ownPropNames(
     JSContext* aCx, JS::Handle<JSObject*> aProxy, unsigned flags,
-    JS::AutoIdVector& aProps) const {
+    JS::MutableHandleVector<jsid> aProps) const {
   if (!(flags & JSITER_HIDDEN)) {
     // None of our named properties are enumerable.
     return true;
   }
 
   // Grab the DOM window.
   nsGlobalWindowInner* win = xpc::WindowGlobalOrNull(aProxy);
   nsTArray<nsString> names;
@@ -201,18 +201,18 @@ bool WindowNamedPropertiesHandler::ownPr
   if (!htmlDoc) {
     return true;
   }
   nsHTMLDocument* document = static_cast<nsHTMLDocument*>(htmlDoc.get());
   // Document names are enumerable, so we want to get them no matter what flags
   // is.
   document->GetSupportedNames(names);
 
-  JS::AutoIdVector docProps(aCx);
-  if (!AppendNamedPropertyIds(aCx, aProxy, names, false, docProps)) {
+  JS::RootedVector<jsid> docProps(aCx);
+  if (!AppendNamedPropertyIds(aCx, aProxy, names, false, &docProps)) {
     return false;
   }
 
   return js::AppendUnique(aCx, aProps, docProps);
 }
 
 bool WindowNamedPropertiesHandler::delete_(JSContext* aCx,
                                            JS::Handle<JSObject*> aProxy,
--- a/dom/base/WindowNamedPropertiesHandler.h
+++ b/dom/base/WindowNamedPropertiesHandler.h
@@ -21,17 +21,17 @@ class WindowNamedPropertiesHandler : pub
       bool /* unused */,
       JS::MutableHandle<JS::PropertyDescriptor> aDesc) const override;
   virtual bool defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy,
                               JS::Handle<jsid> aId,
                               JS::Handle<JS::PropertyDescriptor> aDesc,
                               JS::ObjectOpResult& result) const override;
   virtual bool ownPropNames(JSContext* aCx, JS::Handle<JSObject*> aProxy,
                             unsigned flags,
-                            JS::AutoIdVector& aProps) const override;
+                            JS::MutableHandleVector<jsid> aProps) const override;
   virtual bool delete_(JSContext* aCx, JS::Handle<JSObject*> aProxy,
                        JS::Handle<jsid> aId,
                        JS::ObjectOpResult& aResult) const override;
 
   // No need for getPrototypeIfOrdinary here: window named-properties objects
   // have static prototypes, so the version inherited from BaseDOMProxyHandler
   // will do the right thing.
 
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -2784,17 +2784,17 @@ bool nsGlobalWindowInner::MayResolve(jsi
     // non-chrome windows, but let's not worry about any of that stuff.
     return true;
   }
 
   return WebIDLGlobalNameHash::MayResolve(aId);
 }
 
 void nsGlobalWindowInner::GetOwnPropertyNames(JSContext* aCx,
-                                              JS::AutoIdVector& aNames,
+                                              JS::MutableHandleVector<jsid> aNames,
                                               bool aEnumerableOnly,
                                               ErrorResult& aRv) {
   if (aEnumerableOnly) {
     // The names we would return from here get defined on the window via one of
     // two codepaths.  The ones coming from the WebIDLGlobalNameHash will end up
     // in the DefineConstructor function in BindingUtils, which always defines
     // things as non-enumerable.  The ones coming from the script namespace
     // manager get defined by our resolve hook using FillPropertyDescriptor with
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -376,17 +376,17 @@ class nsGlobalWindowInner final : public
 
   bool DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
                  JS::Handle<jsid> aId,
                  JS::MutableHandle<JS::PropertyDescriptor> aDesc);
   // The return value is whether DoResolve might end up resolving the given id.
   // If in doubt, return true.
   static bool MayResolve(jsid aId);
 
-  void GetOwnPropertyNames(JSContext* aCx, JS::AutoIdVector& aNames,
+  void GetOwnPropertyNames(JSContext* aCx, JS::MutableHandleVector<jsid> aNames,
                            bool aEnumerableOnly, mozilla::ErrorResult& aRv);
 
   nsPIDOMWindowOuter* GetScriptableTop() override;
   inline nsGlobalWindowOuter* GetTopInternal();
 
   inline nsGlobalWindowOuter* GetScriptableTopInternal();
 
   already_AddRefed<mozilla::dom::BrowsingContext> GetChildWindow(
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -384,17 +384,17 @@ class nsOuterWindowProxy : public MaybeC
    * Implementation of [[OwnPropertyKeys]] as defined at
    *
    * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys
    *
    * "proxy" is the WindowProxy object involved.  It may not be same-compartment
    * with cx.
    */
   bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
-                       JS::AutoIdVector& props) const override;
+                       JS::MutableHandleVector<jsid> props) const override;
   /**
    * Implementation of [[Delete]] as defined at
    * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-delete
    *
    * "proxy" is the WindowProxy object involved.  It may not be same-compartment
    * with cx.
    */
   bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
@@ -472,17 +472,17 @@ class nsOuterWindowProxy : public MaybeC
    *
    * We have to override this because js::Wrapper overrides it, but we want
    * different behavior from js::Wrapper.
    *
    * "proxy" is the WindowProxy object involved.  It may not be same-compartment
    * with cx.
    */
   bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
-                                    JS::AutoIdVector& props) const override;
+                                    JS::MutableHandleVector<jsid> props) const override;
 
   /**
    * Hook used by SpiderMonkey to implement Object.prototype.toString.
    */
   const char* className(JSContext* cx,
                         JS::Handle<JSObject*> wrapper) const override;
 
   void finalize(JSFreeOp* fop, JSObject* proxy) const override;
@@ -508,17 +508,17 @@ class nsOuterWindowProxy : public MaybeC
                          bool& found) const;
 
   // Returns a non-null window only if id is an index and we have a
   // window at that index.
   already_AddRefed<nsPIDOMWindowOuter> GetSubframeWindow(
       JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const;
 
   bool AppendIndexedPropertyNames(JSObject* proxy,
-                                  JS::AutoIdVector& props) const;
+                                  JS::MutableHandleVector<jsid> props) const;
 
   using MaybeCrossOriginObjectMixins::EnsureHolder;
   bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> proxy,
                     JS::MutableHandle<JSObject*> holder) const override;
 };
 
 const char* nsOuterWindowProxy::className(JSContext* cx,
                                           JS::Handle<JSObject*> proxy) const {
@@ -730,47 +730,47 @@ bool nsOuterWindowProxy::definePropertyS
 #endif
 
   result.succeed();
   return true;
 }
 
 bool nsOuterWindowProxy::ownPropertyKeys(JSContext* cx,
                                          JS::Handle<JSObject*> proxy,
-                                         JS::AutoIdVector& props) const {
+                                         JS::MutableHandleVector<jsid> props) const {
   // Just our indexed stuff followed by our "normal" own property names.
   if (!AppendIndexedPropertyNames(proxy, props)) {
     return false;
   }
 
   if (IsPlatformObjectSameOrigin(cx, proxy)) {
     // When forwarding to js::Wrapper, we should just enter the Realm of proxy
     // for now.  That's what js::Wrapper expects, and since we're same-origin
     // anyway this is not changing any security behavior.
-    JS::AutoIdVector innerProps(cx);
+    JS::RootedVector<jsid> innerProps(cx);
     {  // Scope for JSAutoRealm so we can mark the ids once we exit it
       JSAutoRealm ar(cx, proxy);
-      if (!js::Wrapper::ownPropertyKeys(cx, proxy, innerProps)) {
+      if (!js::Wrapper::ownPropertyKeys(cx, proxy, &innerProps)) {
         return false;
       }
     }
     for (auto& id : innerProps) {
       JS_MarkCrossZoneId(cx, id);
     }
     return js::AppendUnique(cx, props, innerProps);
   }
 
   // In the cross-origin case we purposefully exclude subframe names from the
   // list of property names we report here.
   JS::Rooted<JSObject*> holder(cx);
   if (!EnsureHolder(cx, proxy, &holder)) {
     return false;
   }
 
-  JS::AutoIdVector crossOriginProps(cx);
+  JS::RootedVector<jsid> crossOriginProps(cx);
   if (!js::GetPropertyKeys(cx, holder,
                            JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
                            &crossOriginProps) ||
       !js::AppendUnique(cx, props, crossOriginProps)) {
     return false;
   }
 
   return xpc::AppendCrossOriginWhitelistedPropNames(cx, props);
@@ -933,17 +933,17 @@ bool nsOuterWindowProxy::set(JSContext* 
   }
 
   JS_MarkCrossZoneId(cx, id);
 
   return js::Wrapper::set(cx, proxy, id, wrappedArg, wrappedReceiver, result);
 }
 
 bool nsOuterWindowProxy::getOwnEnumerablePropertyKeys(
-    JSContext* cx, JS::Handle<JSObject*> proxy, JS::AutoIdVector& props) const {
+    JSContext* cx, JS::Handle<JSObject*> proxy, JS::MutableHandleVector<jsid> props) const {
   // We could just stop overring getOwnEnumerablePropertyKeys and let our
   // superclasses deal (by falling back on the BaseProxyHandler implementation
   // that uses a combination of ownPropertyKeys and getOwnPropertyDescriptor to
   // only return the enumerable ones.  But maybe there's value in having
   // somewhat faster for-in iteration on Window objects...
 
   // Like ownPropertyKeys, our indexed stuff followed by our "normal" enumerable
   // own property names.
@@ -955,20 +955,20 @@ bool nsOuterWindowProxy::getOwnEnumerabl
     // All the cross-origin properties other than the indexed props are
     // non-enumerable, so we're done here.
     return true;
   }
 
   // When forwarding to js::Wrapper, we should just enter the Realm of proxy
   // for now.  That's what js::Wrapper expects, and since we're same-origin
   // anyway this is not changing any security behavior.
-  JS::AutoIdVector innerProps(cx);
+  JS::RootedVector<jsid> innerProps(cx);
   {  // Scope for JSAutoRealm so we can mark the ids once we exit it.
     JSAutoRealm ar(cx, proxy);
-    if (!js::Wrapper::getOwnEnumerablePropertyKeys(cx, proxy, innerProps)) {
+    if (!js::Wrapper::getOwnEnumerablePropertyKeys(cx, proxy, &innerProps)) {
       return false;
     }
   }
 
   for (auto& id : innerProps) {
     JS_MarkCrossZoneId(cx, id);
   }
 
@@ -1009,17 +1009,17 @@ already_AddRefed<nsPIDOMWindowOuter> nsO
     return nullptr;
   }
 
   nsGlobalWindowOuter* win = GetOuterWindow(proxy);
   return win->IndexedGetterOuter(index);
 }
 
 bool nsOuterWindowProxy::AppendIndexedPropertyNames(
-    JSObject* proxy, JS::AutoIdVector& props) const {
+    JSObject* proxy, JS::MutableHandleVector<jsid> props) const {
   uint32_t length = GetOuterWindow(proxy)->Length();
   MOZ_ASSERT(int32_t(length) >= 0);
   if (!props.reserve(props.length() + length)) {
     return false;
   }
   for (int32_t i = 0; i < int32_t(length); ++i) {
     if (!props.append(INT_TO_JSID(i))) {
       return false;
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -3504,17 +3504,17 @@ bool nsObjectLoadingContent::DoResolve(
 
 /* static */
 bool nsObjectLoadingContent::MayResolve(jsid aId) {
   // We can resolve anything, really.
   return true;
 }
 
 void nsObjectLoadingContent::GetOwnPropertyNames(JSContext* aCx,
-                                                 JS::AutoIdVector& /* unused */,
+                                                 JS::MutableHandleVector<jsid> /* unused */,
                                                  bool /* unused */,
                                                  ErrorResult& aRv) {
   // Just like DoResolve, just make sure we're instantiated.  That will do
   // the work our Enumerate hook needs to do.  This purposefully does not fire
   // for xray resolves, see bug 967694
   Unused << ScriptRequestPluginInstance(aCx);
 }
 
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -184,17 +184,17 @@ class nsObjectLoadingContent : public ns
   bool DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
                  JS::Handle<jsid> aId,
                  JS::MutableHandle<JS::PropertyDescriptor> aDesc);
   // The return value is whether DoResolve might end up resolving the given
   // id.  If in doubt, return true.
   static bool MayResolve(jsid aId);
 
   // Helper for WebIDL enumeration
-  void GetOwnPropertyNames(JSContext* aCx, JS::AutoIdVector& /* unused */,
+  void GetOwnPropertyNames(JSContext* aCx, JS::MutableHandleVector<jsid> /* unused */,
                            bool /* unused */, mozilla::ErrorResult& aRv);
 
   // WebIDL API
   mozilla::dom::Document* GetContentDocument(nsIPrincipal& aSubjectPrincipal);
   void GetActualType(nsAString& aType) const {
     CopyUTF8toUTF16(mContentType, aType);
   }
   uint32_t DisplayedType() const { return mType; }
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1794,17 +1794,17 @@ bool XrayDefineProperty(JSContext* cx, J
   const DOMProxyHandler* handler = GetDOMProxyHandler(obj);
   return handler->defineProperty(cx, wrapper, id, desc, result, defined);
 }
 
 template <typename SpecType>
 bool XrayAppendPropertyKeys(JSContext* cx, JS::Handle<JSObject*> obj,
                             const Prefable<const SpecType>* pref,
                             const PropertyInfo* infos, unsigned flags,
-                            JS::AutoIdVector& props) {
+                            JS::MutableHandleVector<jsid> props) {
   do {
     bool prefIsEnabled = pref->isEnabled(cx, obj);
     if (prefIsEnabled) {
       const SpecType* spec = pref->specs;
       do {
         const jsid id = infos++->Id();
         if (((flags & JSITER_HIDDEN) || (spec->flags & JSPROP_ENUMERATE)) &&
             ((flags & JSITER_SYMBOLS) || !JSID_IS_SYMBOL(id)) &&
@@ -1827,17 +1827,17 @@ bool XrayAppendPropertyKeys(JSContext* c
 
   return true;
 }
 
 template <>
 bool XrayAppendPropertyKeys<ConstantSpec>(
     JSContext* cx, JS::Handle<JSObject*> obj,
     const Prefable<const ConstantSpec>* pref, const PropertyInfo* infos,
-    unsigned flags, JS::AutoIdVector& props) {
+    unsigned flags, JS::MutableHandleVector<jsid> props) {
   do {
     bool prefIsEnabled = pref->isEnabled(cx, obj);
     if (prefIsEnabled) {
       const ConstantSpec* spec = pref->specs;
       do {
         if (!props.append(infos++->Id())) {
           return false;
         }
@@ -1865,17 +1865,17 @@ bool XrayAppendPropertyKeys<ConstantSpec
                                 nativeProperties->FieldName##PropertyInfos(), \
                                 flags, props)) {                              \
       return false;                                                           \
     }                                                                         \
   }
 
 bool XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
                          JS::Handle<JSObject*> obj, unsigned flags,
-                         JS::AutoIdVector& props, DOMObjectType type,
+                         JS::MutableHandleVector<jsid> props, DOMObjectType type,
                          const NativeProperties* nativeProperties) {
   MOZ_ASSERT(type != eNamedPropertiesObject);
 
   if (IsInstance(type)) {
     ADD_KEYS_IF_DEFINED(UnforgeableMethod);
     ADD_KEYS_IF_DEFINED(UnforgeableAttribute);
     if (type == eGlobalInstance) {
       ADD_KEYS_IF_DEFINED(Method);
@@ -1897,17 +1897,17 @@ bool XrayOwnPropertyKeys(JSContext* cx, 
   return true;
 }
 
 #undef ADD_KEYS_IF_DEFINED
 
 bool XrayOwnNativePropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
                                const NativePropertyHooks* nativePropertyHooks,
                                DOMObjectType type, JS::Handle<JSObject*> obj,
-                               unsigned flags, JS::AutoIdVector& props) {
+                               unsigned flags, JS::MutableHandleVector<jsid> props) {
   MOZ_ASSERT(type != eNamedPropertiesObject);
 
   if (type == eInterface &&
       nativePropertyHooks->mPrototypeID != prototypes::id::_ID_Count &&
       !AddStringToIDVector(cx, props, "prototype")) {
     return false;
   }
 
@@ -1934,17 +1934,17 @@ bool XrayOwnNativePropertyKeys(JSContext
     return false;
   }
 
   return true;
 }
 
 bool XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
                          JS::Handle<JSObject*> obj, unsigned flags,
-                         JS::AutoIdVector& props) {
+                         JS::MutableHandleVector<jsid> props) {
   DOMObjectType type;
   const NativePropertyHooks* nativePropertyHooks =
       GetNativePropertyHooks(cx, obj, type);
   EnumerateOwnProperties enumerateOwnProperties =
       nativePropertyHooks->mEnumerateOwnProperties;
 
   if (type == eNamedPropertiesObject) {
     MOZ_ASSERT(!enumerateOwnProperties,
@@ -2077,17 +2077,17 @@ bool HasPropertyOnPrototype(JSContext* c
   }
 
   return JS_HasPropertyById(cx, proto, id, has);
 }
 
 bool AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
                             nsTArray<nsString>& names,
                             bool shadowPrototypeProperties,
-                            JS::AutoIdVector& props) {
+                            JS::MutableHandleVector<jsid> props) {
   for (uint32_t i = 0; i < names.Length(); ++i) {
     JS::Rooted<JS::Value> v(cx);
     if (!xpc::NonVoidStringToJsval(cx, names[i], &v)) {
       return false;
     }
 
     JS::Rooted<jsid> id(cx);
     if (!JS_ValueToId(cx, v, &id)) {
@@ -2734,17 +2734,17 @@ bool ResolveGlobal(JSContext* aCx, JS::H
 }
 
 bool MayResolveGlobal(const JSAtomState& aNames, jsid aId,
                       JSObject* aMaybeObj) {
   return JS_MayResolveStandardClass(aNames, aId, aMaybeObj);
 }
 
 bool EnumerateGlobal(JSContext* aCx, JS::HandleObject aObj,
-                     JS::AutoIdVector& aProperties, bool aEnumerableOnly) {
+                     JS::MutableHandleVector<jsid> aProperties, bool aEnumerableOnly) {
   MOZ_ASSERT(JS_IsGlobalObject(aObj),
              "Should have a global here, since we plan to enumerate standard "
              "classes!");
 
   return JS_NewEnumerateStandardClasses(aCx, aObj, aProperties,
                                         aEnumerableOnly);
 }
 
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1821,17 +1821,17 @@ bool HasPropertyOnPrototype(JSContext* c
 
 // Append the property names in "names" to "props". If
 // shadowPrototypeProperties is false then skip properties that are also
 // present on the proto chain of proxy.  If shadowPrototypeProperties is true,
 // then the "proxy" argument is ignored.
 bool AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
                             nsTArray<nsString>& names,
                             bool shadowPrototypeProperties,
-                            JS::AutoIdVector& props);
+                            JS::MutableHandleVector<jsid> props);
 
 enum StringificationBehavior { eStringify, eEmpty, eNull };
 
 template <typename T>
 static inline bool ConvertJSValueToString(
     JSContext* cx, JS::Handle<JS::Value> v,
     StringificationBehavior nullBehavior,
     StringificationBehavior undefinedBehavior, T& result) {
@@ -2187,17 +2187,17 @@ class MOZ_STACK_CLASS NullableRootedUnio
   }
 };
 
 inline bool IdEquals(jsid id, const char* string) {
   return JSID_IS_STRING(id) &&
          JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
 }
 
-inline bool AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector,
+inline bool AddStringToIDVector(JSContext* cx, JS::MutableHandleVector<jsid> vector,
                                 const char* name) {
   return vector.growBy(1) &&
          AtomizeAndPinJSString(cx, *(vector[vector.length() - 1]).address(),
                                name);
 }
 
 // We use one constructor JSNative to represent all DOM interface objects (so
 // we can easily detect when we need to wrap them in an Xray wrapper). We store
@@ -2248,17 +2248,17 @@ bool XrayDefineProperty(JSContext* cx, J
  *
  * wrapper is the Xray JS object.
  * obj is the target object of the Xray, a binding's instance object or a
  *     interface or interface prototype object.
  * flags are JSITER_* flags.
  */
 bool XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
                          JS::Handle<JSObject*> obj, unsigned flags,
-                         JS::AutoIdVector& props);
+                         JS::MutableHandleVector<jsid> props);
 
 /**
  * Returns the prototype to use for an Xray for a DOM object, wrapped in cx's
  * compartment. This always returns the prototype that would be used for a DOM
  * object if we ignore any changes that might have been done to the prototype
  * chain by JS, the XBL code or plugins.
  *
  * cx should be in the Xray's compartment.
@@ -2773,17 +2773,17 @@ class GetCCParticipant<T, true> {
 void FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
 
 bool ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
                    JS::Handle<jsid> aId, bool* aResolvedp);
 
 bool MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj);
 
 bool EnumerateGlobal(JSContext* aCx, JS::HandleObject aObj,
-                     JS::AutoIdVector& aProperties, bool aEnumerableOnly);
+                     JS::MutableHandleVector<jsid> aProperties, bool aEnumerableOnly);
 
 struct CreateGlobalOptionsGeneric {
   static void TraceGlobal(JSTracer* aTrc, JSObject* aObj) {
     mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
   }
   static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal) {
     MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal));
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5004,17 +5004,17 @@ def getJSToNativeConversionInfo(type, de
                 assert recordType.keyType.isUSVString()
                 keyConversionFunction = "ConvertJSValueToUSVString"
 
         templateBody = fill(
             """
             auto& recordEntries = ${recordRef}.Entries();
 
             JS::Rooted<JSObject*> recordObj(cx, &$${val}.toObject());
-            JS::AutoIdVector ids(cx);
+            JS::RootedVector<jsid> ids(cx);
             if (!js::GetPropertyKeys(cx, recordObj,
                                      JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) {
               $*{exceptionCode}
             }
             if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
               JS_ReportOutOfMemory(cx);
               $*{exceptionCode}
             }
@@ -9005,17 +9005,17 @@ class CGEnumerateHook(CGAbstractBindingM
     """
     Enumerate hook for objects with custom hooks.
     """
     def __init__(self, descriptor):
         assert descriptor.interface.getExtendedAttribute("NeedResolve")
 
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'obj'),
-                Argument('JS::AutoIdVector&', 'properties'),
+                Argument('JS::MutableHandleVector<jsid>', 'properties'),
                 Argument('bool', 'enumerableOnly')]
         # Our "self" is actually the "obj" argument in this case, not the thisval.
         CGAbstractBindingMethod.__init__(
             self, descriptor, NEW_ENUMERATE_HOOK_NAME,
             args, getThisObj="", callArgs="")
 
     def generate_code(self):
         return CGGeneric(dedent("""
@@ -11220,34 +11220,34 @@ class CGResolveOwnPropertyViaResolve(CGA
             """))
 
 
 class CGEnumerateOwnProperties(CGAbstractStaticMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'wrapper'),
                 Argument('JS::Handle<JSObject*>', 'obj'),
-                Argument('JS::AutoIdVector&', 'props')]
+                Argument('JS::MutableHandleVector<jsid>', 'props')]
         CGAbstractStaticMethod.__init__(self, descriptor,
                                         "EnumerateOwnProperties", "bool", args)
 
     def definition_body(self):
         return "return js::GetProxyHandler(obj)->ownPropertyKeys(cx, wrapper, props);\n"
 
 
 class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
     """
     An implementation of Xray EnumerateOwnProperties stuff for things
     that have a resolve hook.
     """
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'wrapper'),
                 Argument('JS::Handle<JSObject*>', 'obj'),
-                Argument('JS::AutoIdVector&', 'props')]
+                Argument('JS::MutableHandleVector<jsid>', 'props')]
         CGAbstractBindingMethod.__init__(self, descriptor,
                                          "EnumerateOwnPropertiesViaGetOwnPropertyNames",
                                          args, getThisObj="",
                                          callArgs="")
 
     def generate_code(self):
         return CGGeneric(dedent("""
             FastErrorResult rv;
@@ -12043,17 +12043,17 @@ class CGDOMJSProxyHandler_delete(ClassMe
         return delete
 
 
 class CGDOMJSProxyHandler_ownPropNames(ClassMethod):
     def __init__(self, descriptor, ):
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'proxy'),
                 Argument('unsigned', 'flags'),
-                Argument('JS::AutoIdVector&', 'props')]
+                Argument('JS::MutableHandleVector<jsid>', 'props')]
         ClassMethod.__init__(self, "ownPropNames", "bool", args,
                              virtual=True, override=True, const=True)
         self.descriptor = descriptor
 
     def getBody(self):
         if self.descriptor.isMaybeCrossOriginObject():
             xrayDecl = dedent(
                 """
@@ -12064,17 +12064,17 @@ class CGDOMJSProxyHandler_ownPropNames(C
                     return true;
                   }
 
                   JS::Rooted<JSObject*> holder(cx);
                   if (!EnsureHolder(cx, proxy, &holder)) {
                     return false;
                   }
 
-                  if (!js::GetPropertyKeys(cx, holder, flags, &props)) {
+                  if (!js::GetPropertyKeys(cx, holder, flags, props)) {
                     return false;
                   }
 
                   return xpc::AppendCrossOriginWhitelistedPropNames(cx, props);
                 }
 
                 """)
             xrayCheck = ""
@@ -12130,17 +12130,17 @@ class CGDOMJSProxyHandler_ownPropNames(C
             addNames = "\n" + addNames
         else:
             addNames = ""
 
         addExpandoProps = fill(
             """
             JS::Rooted<JSObject*> expando(cx);
             if (${xrayCheck}(expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
-                !js::GetPropertyKeys(cx, expando, flags, &props)) {
+                !js::GetPropertyKeys(cx, expando, flags, props)) {
               return false;
             }
             """,
             xrayCheck=xrayCheck)
             
         if self.descriptor.isMaybeCrossOriginObject():
             # We need to enter our compartment (which we might not be
             # in right now) to get the expando props.
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -69,17 +69,17 @@ inline bool IsSecureContextOrObjectIsFro
 
 typedef bool (*ResolveOwnProperty)(
     JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> obj,
     JS::Handle<jsid> id, JS::MutableHandle<JS::PropertyDescriptor> desc);
 
 typedef bool (*EnumerateOwnProperties)(JSContext* cx,
                                        JS::Handle<JSObject*> wrapper,
                                        JS::Handle<JSObject*> obj,
-                                       JS::AutoIdVector& props);
+                                       JS::MutableHandleVector<jsid> props);
 
 typedef bool (*DeleteNamedProperty)(JSContext* cx,
                                     JS::Handle<JSObject*> wrapper,
                                     JS::Handle<JSObject*> obj,
                                     JS::Handle<jsid> id,
                                     JS::ObjectOpResult& opresult);
 
 // Returns true if the given global is of a type whose bit is set in
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -250,31 +250,31 @@ bool DOMProxyHandler::delete_(JSContext*
     return JS_DeletePropertyById(cx, expando, id, result);
   }
 
   return result.succeed();
 }
 
 bool BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx,
                                           JS::Handle<JSObject*> proxy,
-                                          JS::AutoIdVector& props) const {
+                                          JS::MutableHandleVector<jsid> props) const {
   return ownPropNames(cx, proxy,
                       JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
 }
 
 bool BaseDOMProxyHandler::getPrototypeIfOrdinary(
     JSContext* cx, JS::Handle<JSObject*> proxy, bool* isOrdinary,
     JS::MutableHandle<JSObject*> proto) const {
   *isOrdinary = true;
   proto.set(GetStaticPrototype(proxy));
   return true;
 }
 
 bool BaseDOMProxyHandler::getOwnEnumerablePropertyKeys(
-    JSContext* cx, JS::Handle<JSObject*> proxy, JS::AutoIdVector& props) const {
+    JSContext* cx, JS::Handle<JSObject*> proxy, JS::MutableHandleVector<jsid> props) const {
   return ownPropNames(cx, proxy, JSITER_OWNONLY, props);
 }
 
 bool DOMProxyHandler::setCustom(JSContext* cx, JS::Handle<JSObject*> proxy,
                                 JS::Handle<jsid> id, JS::Handle<JS::Value> v,
                                 bool* done) const {
   *done = false;
   return true;
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -48,37 +48,37 @@ class BaseDOMProxyHandler : public js::B
       : js::BaseProxyHandler(aProxyFamily, aHasPrototype) {}
 
   // Implementations of methods that can be implemented in terms of
   // other lower-level methods.
   bool getOwnPropertyDescriptor(
       JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
       JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
   virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
-                               JS::AutoIdVector& props) const override;
+                               JS::MutableHandleVector<jsid> props) const override;
 
   virtual bool getPrototypeIfOrdinary(
       JSContext* cx, JS::Handle<JSObject*> proxy, bool* isOrdinary,
       JS::MutableHandle<JSObject*> proto) const override;
 
   // We override getOwnEnumerablePropertyKeys() and implement it directly
   // instead of using the default implementation, which would call
   // ownPropertyKeys and then filter out the non-enumerable ones. This avoids
   // unnecessary work during enumeration.
   virtual bool getOwnEnumerablePropertyKeys(
       JSContext* cx, JS::Handle<JSObject*> proxy,
-      JS::AutoIdVector& props) const override;
+      JS::MutableHandleVector<jsid> props) const override;
 
  protected:
   // Hook for subclasses to implement shared ownPropertyKeys()/keys()
   // functionality.  The "flags" argument is either JSITER_OWNONLY (for keys())
   // or JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS (for
   // ownPropertyKeys()).
   virtual bool ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy,
-                            unsigned flags, JS::AutoIdVector& props) const = 0;
+                            unsigned flags, JS::MutableHandleVector<jsid> props) const = 0;
 
   // Hook for subclasses to allow set() to ignore named props while other things
   // that look at property descriptors see them.  This is intentionally not
   // named getOwnPropertyDescriptor to avoid subclasses that override it hiding
   // our public getOwnPropertyDescriptor.
   virtual bool getOwnPropDescriptor(
       JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
       bool ignoreNamedProps,
--- a/dom/bindings/RemoteObjectProxy.cpp
+++ b/dom/bindings/RemoteObjectProxy.cpp
@@ -30,25 +30,25 @@ bool RemoteObjectProxyBase::defineProper
   // step 3 and
   // https://html.spec.whatwg.org/multipage/browsers.html#location-defineownproperty
   // step 2
   return ReportCrossOriginDenial(aCx, aId, NS_LITERAL_CSTRING("define"));
 }
 
 bool RemoteObjectProxyBase::ownPropertyKeys(JSContext* aCx,
                                             JS::Handle<JSObject*> aProxy,
-                                            JS::AutoIdVector& aProps) const {
+                                            JS::MutableHandleVector<jsid> aProps) const {
   // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
   // step 2 and
   // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginproperties-(-o-)
   JS::Rooted<JSObject*> holder(aCx);
   if (!EnsureHolder(aCx, aProxy, &holder) ||
       !js::GetPropertyKeys(aCx, holder,
                            JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
-                           &aProps)) {
+                           aProps)) {
     return false;
   }
 
   // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
   // step 3 and 4
   return xpc::AppendCrossOriginWhitelistedPropNames(aCx, aProps);
 }
 
@@ -154,17 +154,17 @@ bool RemoteObjectProxyBase::hasOwn(JSCon
     *aBp = xpc::IsCrossOriginWhitelistedProp(aCx, aId);
   }
 
   return true;
 }
 
 bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys(
     JSContext* aCx, JS::Handle<JSObject*> aProxy,
-    JS::AutoIdVector& aProps) const {
+    JS::MutableHandleVector<jsid> aProps) const {
   return true;
 }
 
 const char* RemoteObjectProxyBase::className(
     JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
   MOZ_ASSERT(js::IsProxy(aProxy));
 
   return "Object";
--- a/dom/bindings/RemoteObjectProxy.h
+++ b/dom/bindings/RemoteObjectProxy.h
@@ -30,17 +30,17 @@ class RemoteObjectProxyBase : public js:
  public:
   bool finalizeInBackground(const JS::Value& priv) const final { return false; }
 
   // Standard internal methods
   bool getOwnPropertyDescriptor(
       JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
       JS::MutableHandle<JS::PropertyDescriptor> aDesc) const override;
   bool ownPropertyKeys(JSContext* aCx, JS::Handle<JSObject*> aProxy,
-                       JS::AutoIdVector& aProps) const override;
+                       JS::MutableHandleVector<jsid> aProps) const override;
   bool defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy,
                       JS::Handle<jsid> aId,
                       JS::Handle<JS::PropertyDescriptor> aDesc,
                       JS::ObjectOpResult& result) const final;
   bool delete_(JSContext* aCx, JS::Handle<JSObject*> aProxy,
                JS::Handle<jsid> aId, JS::ObjectOpResult& aResult) const final;
 
   bool getPrototype(JSContext* aCx, JS::Handle<JSObject*> aProxy,
@@ -64,17 +64,17 @@ class RemoteObjectProxyBase : public js:
            JS::Handle<JS::Value> aValue, JS::Handle<JS::Value> aReceiver,
            JS::ObjectOpResult& aResult) const final;
 
   // SpiderMonkey extensions
   bool hasOwn(JSContext* aCx, JS::Handle<JSObject*> aProxy,
               JS::Handle<jsid> aId, bool* aBp) const override;
   bool getOwnEnumerablePropertyKeys(JSContext* aCx,
                                     JS::Handle<JSObject*> aProxy,
-                                    JS::AutoIdVector& aProps) const override;
+                                    JS::MutableHandleVector<jsid> aProps) const override;
   const char* className(JSContext* aCx,
                         JS::Handle<JSObject*> aProxy) const final;
 
   bool isCallable(JSObject* aObj) const final { return false; }
   bool isConstructor(JSObject* aObj) const final { return false; }
 
   virtual void NoteChildren(JSObject* aProxy,
                             nsCycleCollectionTraversalCallback& aCb) const = 0;
--- a/dom/bindings/WebIDLGlobalNameHash.cpp
+++ b/dom/bindings/WebIDLGlobalNameHash.cpp
@@ -176,17 +176,17 @@ bool WebIDLGlobalNameHash::DefineIfEnabl
 /* static */
 bool WebIDLGlobalNameHash::MayResolve(jsid aId) {
   return GetEntry(JSID_TO_FLAT_STRING(aId)) != nullptr;
 }
 
 /* static */
 bool WebIDLGlobalNameHash::GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
                                     NameType aNameType,
-                                    JS::AutoIdVector& aNames) {
+                                    JS::MutableHandleVector<jsid> aNames) {
   // aObj is always a Window here, so GetProtoAndIfaceCache on it is safe.
   ProtoAndIfaceCache* cache = GetProtoAndIfaceCache(aObj);
   for (size_t i = 0; i < sCount; ++i) {
     const WebIDLNameTableEntry& entry = sEntries[i];
     // If aNameType is not AllNames, only include things whose entry slot in the
     // ProtoAndIfaceCache is null.
     if ((aNameType == AllNames ||
          !cache->HasEntryInSlot(entry.mConstructorId)) &&
@@ -238,17 +238,17 @@ bool WebIDLGlobalNameHash::ResolveForSys
 
     *aResolvedp = true;
   }
   return true;
 }
 
 /* static */
 bool WebIDLGlobalNameHash::NewEnumerateSystemGlobal(
-    JSContext* aCx, JS::Handle<JSObject*> aObj, JS::AutoIdVector& aProperties,
+    JSContext* aCx, JS::Handle<JSObject*> aObj, JS::MutableHandleVector<jsid> aProperties,
     bool aEnumerableOnly) {
   MOZ_ASSERT(JS_IsGlobalObject(aObj));
 
   if (!JS_NewEnumerateStandardClasses(aCx, aObj, aProperties,
                                       aEnumerableOnly)) {
     return false;
   }
 
--- a/dom/bindings/WebIDLGlobalNameHash.h
+++ b/dom/bindings/WebIDLGlobalNameHash.h
@@ -54,27 +54,27 @@ class WebIDLGlobalNameHash {
     // All WebIDL names enabled for aObj.
     AllNames,
     // Only the names that are enabled for aObj and have not been resolved for
     // aObj in the past (and therefore can't have been deleted).
     UnresolvedNamesOnly
   };
   // Returns false if an exception has been thrown on aCx.
   static bool GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
-                       NameType aNameType, JS::AutoIdVector& aNames);
+                       NameType aNameType, JS::MutableHandleVector<jsid> aNames);
 
   // Helpers for resolving & enumerating names on the system global.
   // NOTE: These are distinct as it currently lacks a ProtoAndIfaceCache, and is
   // an XPCOM global.
   static bool ResolveForSystemGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
                                      JS::Handle<jsid> aId, bool* aResolvedp);
 
   static bool NewEnumerateSystemGlobal(JSContext* aCx,
                                        JS::Handle<JSObject*> aObj,
-                                       JS::AutoIdVector& aProperties,
+                                       JS::MutableHandleVector<jsid> aProperties,
                                        bool aEnumerableOnly);
 
  private:
   friend struct WebIDLNameTableEntry;
 
   // Look up an entry by key name. `nullptr` if the entry was not found.
   // The impl of GetEntry is generated by Codegen.py in RegisterBindings.cpp
   static const WebIDLNameTableEntry* GetEntry(JSFlatString* aKey);
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -181,17 +181,17 @@ class NPObjWrapperProxyHandler : public 
     return true;
   }
 
   bool getOwnPropertyDescriptor(
       JSContext *cx, JS::Handle<JSObject *> proxy, JS::Handle<jsid> id,
       JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
 
   bool ownPropertyKeys(JSContext *cx, JS::Handle<JSObject *> proxy,
-                       JS::AutoIdVector &properties) const override;
+                       JS::MutableHandleVector<jsid> properties) const override;
 
   bool delete_(JSContext *cx, JS::Handle<JSObject *> proxy, JS::Handle<jsid> id,
                JS::ObjectOpResult &result) const override;
 
   bool get(JSContext *cx, JS::Handle<JSObject *> proxy,
            JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
            JS::MutableHandle<JS::Value> vp) const override;
 
@@ -1510,17 +1510,17 @@ bool NPObjWrapperProxyHandler::getOwnPro
   // correctly (it will call getOwnPropertyDescriptor to check enumerability).
   JS::Rooted<JS::Value> val(cx, JS::ObjectOrNullValue(method));
   desc.initFields(proxy, val, JSPROP_ENUMERATE, nullptr, nullptr);
   return true;
 }
 
 bool NPObjWrapperProxyHandler::ownPropertyKeys(
     JSContext *cx, JS::Handle<JSObject *> proxy,
-    JS::AutoIdVector &properties) const {
+    JS::MutableHandleVector<jsid> properties) const {
   NPObject *npobj = GetNPObject(cx, proxy);
   if (!npobj || !npobj->_class) {
     ThrowJSExceptionASCII(cx, "Bad NPObject as private data!");
     return false;
   }
 
   PluginDestructionGuard pdg(LookupNPP(npobj));
 
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -794,17 +794,17 @@ bool WrapperAnswer::RecvGetPropertyKeys(
 
   RootedObject obj(cx, findObjectById(cx, objId));
   if (!obj) {
     return deadCPOW(jsapi, rs);
   }
 
   LOG("%s.getPropertyKeys()", ReceiverObj(objId));
 
-  AutoIdVector props(cx);
+  RootedIdVector props(cx);
   if (!js::GetPropertyKeys(cx, obj, flags, &props)) {
     return fail(jsapi, rs);
   }
 
   for (size_t i = 0; i < props.length(); i++) {
     JSIDVariant id;
     if (!toJSIDVariant(cx, props[i], &id)) {
       return fail(jsapi, rs);
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -83,21 +83,21 @@ class CPOWProxyHandler : public BaseProx
 
   virtual bool getOwnPropertyDescriptor(
       JSContext* cx, HandleObject proxy, HandleId id,
       MutableHandle<PropertyDescriptor> desc) const override;
   virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
                               Handle<PropertyDescriptor> desc,
                               ObjectOpResult& result) const override;
   virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                               AutoIdVector& props) const override;
+                               MutableHandleIdVector props) const override;
   virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
                        ObjectOpResult& result) const override;
   virtual bool enumerate(JSContext* cx, HandleObject proxy,
-                         AutoIdVector& props) const override;
+                         MutableHandleIdVector props) const override;
   virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
                                  ObjectOpResult& result) const override;
   virtual bool isExtensible(JSContext* cx, HandleObject proxy,
                             bool* extensible) const override;
   virtual bool has(JSContext* cx, HandleObject proxy, HandleId id,
                    bool* bp) const override;
   virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
                    HandleId id, MutableHandleValue vp) const override;
@@ -107,17 +107,17 @@ class CPOWProxyHandler : public BaseProx
   virtual bool call(JSContext* cx, HandleObject proxy,
                     const CallArgs& args) const override;
   virtual bool construct(JSContext* cx, HandleObject proxy,
                          const CallArgs& args) const override;
 
   virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
                       bool* bp) const override;
   virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
-                                            AutoIdVector& props) const override;
+                                            MutableHandleIdVector props) const override;
   virtual bool hasInstance(JSContext* cx, HandleObject proxy,
                            MutableHandleValue v, bool* bp) const override;
   virtual bool getBuiltinClass(JSContext* cx, HandleObject obj,
                                js::ESClass* cls) const override;
   virtual bool isArray(JSContext* cx, HandleObject obj,
                        IsArrayAnswer* answer) const override;
   virtual const char* className(JSContext* cx,
                                 HandleObject proxy) const override;
@@ -211,22 +211,22 @@ bool WrapperOwner::defineProperty(JSCont
   }
 
   LOG_STACK();
 
   return ok(cx, status, result);
 }
 
 bool CPOWProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                                       AutoIdVector& props) const {
+                                       MutableHandleIdVector props) const {
   FORWARD(ownPropertyKeys, (cx, proxy, props), false);
 }
 
 bool WrapperOwner::ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                                   AutoIdVector& props) {
+                                   MutableHandleIdVector props) {
   return getPropertyKeys(
       cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
 }
 
 bool CPOWProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id,
                                ObjectOpResult& result) const {
   FORWARD(delete_, (cx, proxy, id, result), false);
 }
@@ -246,17 +246,17 @@ bool WrapperOwner::delete_(JSContext* cx
   }
 
   LOG_STACK();
 
   return ok(cx, status, result);
 }
 
 bool CPOWProxyHandler::enumerate(JSContext* cx, HandleObject proxy,
-                                 AutoIdVector& props) const {
+                                 MutableHandleIdVector props) const {
   // Call the base hook. That will use our implementation of
   // getOwnEnumerablePropertyKeys and follow the proto chain.
   return BaseProxyHandler::enumerate(cx, proxy, props);
 }
 
 bool CPOWProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id,
                            bool* bp) const {
   FORWARD(has, (cx, proxy, id, bp), false);
@@ -513,23 +513,23 @@ bool WrapperOwner::set(JSContext* cx, JS
 
   LOG_STACK();
 
   return ok(cx, status, result);
 }
 
 bool CPOWProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx,
                                                     HandleObject proxy,
-                                                    AutoIdVector& props) const {
+                                                    MutableHandleIdVector props) const {
   FORWARD(getOwnEnumerablePropertyKeys, (cx, proxy, props), false);
 }
 
 bool WrapperOwner::getOwnEnumerablePropertyKeys(JSContext* cx,
                                                 HandleObject proxy,
-                                                AutoIdVector& props) {
+                                                MutableHandleIdVector props) {
   return getPropertyKeys(cx, proxy, JSITER_OWNONLY, props);
 }
 
 bool CPOWProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy,
                                          ObjectOpResult& result) const {
   FORWARD(preventExtensions, (cx, proxy, result), false);
 }
 
@@ -884,17 +884,17 @@ void WrapperOwner::drop(JSObject* obj) {
 
 void WrapperOwner::updatePointer(JSObject* obj, const JSObject* old) {
   ObjectId objId = idOfUnchecked(obj);
   MOZ_ASSERT(hasCPOW(objId, old));
   cpows_.add(objId, obj);
 }
 
 bool WrapperOwner::getPropertyKeys(JSContext* cx, HandleObject proxy,
-                                   uint32_t flags, AutoIdVector& props) {
+                                   uint32_t flags, MutableHandleIdVector props) {
   ObjectId objId = idOf(proxy);
 
   ReturnStatus status;
   InfallibleTArray<JSIDVariant> ids;
   if (!SendGetPropertyKeys(objId, flags, &status, &ids)) {
     return ipcfail(cx);
   }
 
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -27,17 +27,17 @@ class WrapperOwner : public virtual Java
   // (The traps should be in the same order like js/Proxy.h)
   bool getOwnPropertyDescriptor(JSContext* cx, JS::HandleObject proxy,
                                 JS::HandleId id,
                                 JS::MutableHandle<JS::PropertyDescriptor> desc);
   bool defineProperty(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
                       JS::Handle<JS::PropertyDescriptor> desc,
                       JS::ObjectOpResult& result);
   bool ownPropertyKeys(JSContext* cx, JS::HandleObject proxy,
-                       JS::AutoIdVector& props);
+                       JS::MutableHandleIdVector props);
   bool delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
                JS::ObjectOpResult& result);
   bool preventExtensions(JSContext* cx, JS::HandleObject proxy,
                          JS::ObjectOpResult& result);
   bool isExtensible(JSContext* cx, JS::HandleObject proxy, bool* extensible);
   bool has(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, bool* bp);
   bool get(JSContext* cx, JS::HandleObject proxy, JS::HandleValue receiver,
            JS::HandleId id, JS::MutableHandleValue vp);
@@ -45,17 +45,17 @@ class WrapperOwner : public virtual Java
            JS::HandleValue v, JS::HandleValue receiver,
            JS::ObjectOpResult& result);
   bool callOrConstruct(JSContext* cx, JS::HandleObject proxy,
                        const JS::CallArgs& args, bool construct);
 
   // SpiderMonkey extensions.
   bool hasOwn(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, bool* bp);
   bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::HandleObject proxy,
-                                    JS::AutoIdVector& props);
+                                    JS::MutableHandleIdVector props);
   bool hasInstance(JSContext* cx, JS::HandleObject proxy,
                    JS::MutableHandleValue v, bool* bp);
   bool getBuiltinClass(JSContext* cx, JS::HandleObject proxy, js::ESClass* cls);
   bool isArray(JSContext* cx, JS::HandleObject proxy,
                JS::IsArrayAnswer* answer);
   const char* className(JSContext* cx, JS::HandleObject proxy);
   bool getPrototype(JSContext* cx, JS::HandleObject proxy,
                     JS::MutableHandleObject protop);
@@ -94,17 +94,17 @@ class WrapperOwner : public virtual Java
 
  protected:
   ObjectId idOf(JSObject* obj);
 
  private:
   ObjectId idOfUnchecked(JSObject* obj);
 
   bool getPropertyKeys(JSContext* cx, JS::HandleObject proxy, uint32_t flags,
-                       JS::AutoIdVector& props);
+                       JS::MutableHandleIdVector props);
 
   // Catastrophic IPC failure.
   bool ipcfail(JSContext* cx);
 
   // Check whether a return status is okay, and if not, propagate its error.
   //
   // If 'status' might be a ReturnObjectOpResult, which is only possible for
   // a subset of the operations below, 'result' must be passed.
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -414,17 +414,17 @@ typedef bool (*JSDeletePropertyOp)(JSCon
  * loop will iterate over. All of this is nonstandard.
  *
  * An object is "enumerated" when it's the target of a for-in loop or
  * JS_Enumerate(). The callback's job is to populate 'properties' with the
  * object's property keys. If `enumerableOnly` is true, the callback should only
  * add enumerable properties.
  */
 typedef bool (*JSNewEnumerateOp)(JSContext* cx, JS::HandleObject obj,
-                                 JS::AutoIdVector& properties,
+                                 JS::MutableHandleIdVector properties,
                                  bool enumerableOnly);
 
 /**
  * The old-style JSClass.enumerate op should define all lazy properties not
  * yet reflected in obj.
  */
 typedef bool (*JSEnumerateOp)(JSContext* cx, JS::HandleObject obj);
 
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -11,24 +11,24 @@
 
 #include "jsfriendapi.h"
 
 #include "js/CallNonGenericMethod.h"
 #include "js/Class.h"
 
 namespace js {
 
-using JS::AutoIdVector;
 using JS::CallArgs;
 using JS::Handle;
 using JS::HandleId;
 using JS::HandleObject;
 using JS::HandleValue;
 using JS::IsAcceptableThis;
 using JS::MutableHandle;
+using JS::MutableHandleIdVector;
 using JS::MutableHandleObject;
 using JS::MutableHandleValue;
 using JS::NativeImpl;
 using JS::ObjectOpResult;
 using JS::PrivateValue;
 using JS::PropertyDescriptor;
 using JS::Value;
 
@@ -270,17 +270,17 @@ class JS_FRIEND_API BaseProxyHandler {
   /* Standard internal methods. */
   virtual bool getOwnPropertyDescriptor(
       JSContext* cx, HandleObject proxy, HandleId id,
       MutableHandle<PropertyDescriptor> desc) const = 0;
   virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
                               Handle<PropertyDescriptor> desc,
                               ObjectOpResult& result) const = 0;
   virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                               AutoIdVector& props) const = 0;
+                               MutableHandleIdVector props) const = 0;
   virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
                        ObjectOpResult& result) const = 0;
 
   /*
    * These methods are standard, but the engine does not normally call them.
    * They're opt-in. See "Proxy prototype chains" above.
    *
    * getPrototype() crashes if called. setPrototype() throws a TypeError.
@@ -333,21 +333,21 @@ class JS_FRIEND_API BaseProxyHandler {
    */
   virtual bool call(JSContext* cx, HandleObject proxy,
                     const CallArgs& args) const;
   virtual bool construct(JSContext* cx, HandleObject proxy,
                          const CallArgs& args) const;
 
   /* SpiderMonkey extensions. */
   virtual bool enumerate(JSContext* cx, HandleObject proxy,
-                         AutoIdVector& props) const;
+                         MutableHandleIdVector props) const;
   virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
                       bool* bp) const;
   virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
-                                            AutoIdVector& props) const;
+                                            MutableHandleIdVector props) const;
   virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                           const CallArgs& args) const;
   virtual bool hasInstance(JSContext* cx, HandleObject proxy,
                            MutableHandleValue v, bool* bp) const;
   virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
                                ESClass* cls) const;
   virtual bool isArray(JSContext* cx, HandleObject proxy,
                        JS::IsArrayAnswer* answer) const;
--- a/js/public/TypeDecls.h
+++ b/js/public/TypeDecls.h
@@ -70,39 +70,42 @@ typedef Handle<PropertyKey> HandleId;
 typedef Handle<JSObject*> HandleObject;
 typedef Handle<JSScript*> HandleScript;
 typedef Handle<JSString*> HandleString;
 typedef Handle<JS::Symbol*> HandleSymbol;
 typedef Handle<JS::BigInt*> HandleBigInt;
 typedef Handle<Value> HandleValue;
 typedef Handle<StackGCVector<Value>> HandleValueVector;
 typedef Handle<StackGCVector<JSObject*>> HandleObjectVector;
+typedef Handle<StackGCVector<JS::PropertyKey>> HandleIdVector;
 
 typedef MutableHandle<JSFunction*> MutableHandleFunction;
 typedef MutableHandle<PropertyKey> MutableHandleId;
 typedef MutableHandle<JSObject*> MutableHandleObject;
 typedef MutableHandle<JSScript*> MutableHandleScript;
 typedef MutableHandle<JSString*> MutableHandleString;
 typedef MutableHandle<JS::Symbol*> MutableHandleSymbol;
 typedef MutableHandle<JS::BigInt*> MutableHandleBigInt;
 typedef MutableHandle<Value> MutableHandleValue;
 typedef MutableHandle<StackGCVector<Value>> MutableHandleValueVector;
 typedef MutableHandle<StackGCVector<JSObject*>> MutableHandleObjectVector;
+typedef MutableHandle<StackGCVector<JS::PropertyKey>> MutableHandleIdVector;
 
 typedef Rooted<JSObject*> RootedObject;
 typedef Rooted<JSFunction*> RootedFunction;
 typedef Rooted<JSScript*> RootedScript;
 typedef Rooted<JSString*> RootedString;
 typedef Rooted<JS::Symbol*> RootedSymbol;
 typedef Rooted<JS::BigInt*> RootedBigInt;
 typedef Rooted<PropertyKey> RootedId;
 typedef Rooted<JS::Value> RootedValue;
 
 typedef RootedVector<JS::Value> RootedValueVector;
 typedef RootedVector<JSObject*> RootedObjectVector;
+typedef RootedVector<JS::PropertyKey> RootedIdVector;
 
 typedef PersistentRooted<JSFunction*> PersistentRootedFunction;
 typedef PersistentRooted<PropertyKey> PersistentRootedId;
 typedef PersistentRooted<JSObject*> PersistentRootedObject;
 typedef PersistentRooted<JSScript*> PersistentRootedScript;
 typedef PersistentRooted<JSString*> PersistentRootedString;
 typedef PersistentRooted<JS::Symbol*> PersistentRootedSymbol;
 typedef PersistentRooted<JS::BigInt*> PersistentRootedBigInt;
--- a/js/public/Wrapper.h
+++ b/js/public/Wrapper.h
@@ -47,21 +47,21 @@ class JS_FRIEND_API ForwardingProxyHandl
   /* Standard internal methods. */
   virtual bool getOwnPropertyDescriptor(
       JSContext* cx, HandleObject proxy, HandleId id,
       MutableHandle<PropertyDescriptor> desc) const override;
   virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
                               Handle<PropertyDescriptor> desc,
                               ObjectOpResult& result) const override;
   virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                               AutoIdVector& props) const override;
+                               MutableHandleIdVector props) const override;
   virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
                        ObjectOpResult& result) const override;
   virtual bool enumerate(JSContext* cx, HandleObject proxy,
-                         AutoIdVector& props) const override;
+                         MutableHandleIdVector props) const override;
   virtual bool getPrototype(JSContext* cx, HandleObject proxy,
                             MutableHandleObject protop) const override;
   virtual bool setPrototype(JSContext* cx, HandleObject proxy,
                             HandleObject proto,
                             ObjectOpResult& result) const override;
   virtual bool getPrototypeIfOrdinary(
       JSContext* cx, HandleObject proxy, bool* isOrdinary,
       MutableHandleObject protop) const override;
@@ -82,17 +82,17 @@ class JS_FRIEND_API ForwardingProxyHandl
                     const CallArgs& args) const override;
   virtual bool construct(JSContext* cx, HandleObject proxy,
                          const CallArgs& args) const override;
 
   /* SpiderMonkey extensions. */
   virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
                       bool* bp) const override;
   virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
-                                            AutoIdVector& props) const override;
+                                            MutableHandleIdVector props) const override;
   virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                           const CallArgs& args) const override;
   virtual bool hasInstance(JSContext* cx, HandleObject proxy,
                            MutableHandleValue v, bool* bp) const override;
   virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
                                ESClass* cls) const override;
   virtual bool isArray(JSContext* cx, HandleObject proxy,
                        JS::IsArrayAnswer* answer) const override;
@@ -186,21 +186,21 @@ class JS_FRIEND_API CrossCompartmentWrap
   /* Standard internal methods. */
   virtual bool getOwnPropertyDescriptor(
       JSContext* cx, HandleObject wrapper, HandleId id,
       MutableHandle<PropertyDescriptor> desc) const override;
   virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
                               Handle<PropertyDescriptor> desc,
                               ObjectOpResult& result) const override;
   virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
-                               AutoIdVector& props) const override;
+                               MutableHandleIdVector props) const override;
   virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
                        ObjectOpResult& result) const override;
   virtual bool enumerate(JSContext* cx, HandleObject proxy,
-                         AutoIdVector& props) const override;
+                         MutableHandleIdVector props) const override;
   virtual bool getPrototype(JSContext* cx, HandleObject proxy,
                             MutableHandleObject protop) const override;
   virtual bool setPrototype(JSContext* cx, HandleObject proxy,
                             HandleObject proto,
                             ObjectOpResult& result) const override;
 
   virtual bool getPrototypeIfOrdinary(
       JSContext* cx, HandleObject proxy, bool* isOrdinary,
@@ -222,17 +222,17 @@ class JS_FRIEND_API CrossCompartmentWrap
                     const CallArgs& args) const override;
   virtual bool construct(JSContext* cx, HandleObject wrapper,
                          const CallArgs& args) const override;
 
   /* SpiderMonkey extensions. */
   virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
                       bool* bp) const override;
   virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
-                                            AutoIdVector& props) const override;
+                                            MutableHandleIdVector props) const override;
   virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                           const CallArgs& args) const override;
   virtual bool hasInstance(JSContext* cx, HandleObject wrapper,
                            MutableHandleValue v, bool* bp) const override;
   virtual const char* className(JSContext* cx,
                                 HandleObject proxy) const override;
   virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
                                  bool isToSource) const override;
@@ -257,21 +257,21 @@ class JS_FRIEND_API OpaqueCrossCompartme
   /* Standard internal methods. */
   virtual bool getOwnPropertyDescriptor(
       JSContext* cx, HandleObject wrapper, HandleId id,
       MutableHandle<PropertyDescriptor> desc) const override;
   virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
                               Handle<PropertyDescriptor> desc,
                               ObjectOpResult& result) const override;
   virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
-                               AutoIdVector& props) const override;
+                               MutableHandleIdVector props) const override;
   virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
                        ObjectOpResult& result) const override;
   virtual bool enumerate(JSContext* cx, HandleObject proxy,
-                         AutoIdVector& props) const override;
+                         MutableHandleIdVector props) const override;
   virtual bool getPrototype(JSContext* cx, HandleObject wrapper,
                             MutableHandleObject protop) const override;
   virtual bool setPrototype(JSContext* cx, HandleObject wrapper,
                             HandleObject proto,
                             ObjectOpResult& result) const override;
   virtual bool getPrototypeIfOrdinary(
       JSContext* cx, HandleObject wrapper, bool* isOrdinary,
       MutableHandleObject protop) const override;
@@ -292,17 +292,17 @@ class JS_FRIEND_API OpaqueCrossCompartme
                     const CallArgs& args) const override;
   virtual bool construct(JSContext* cx, HandleObject wrapper,
                          const CallArgs& args) const override;
 
   /* SpiderMonkey extensions. */
   virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
                       bool* bp) const override;
   virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
-                                            AutoIdVector& props) const override;
+                                            MutableHandleIdVector props) const override;
   virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper,
                                ESClass* cls) const override;
   virtual bool isArray(JSContext* cx, HandleObject obj,
                        JS::IsArrayAnswer* answer) const override;
   virtual bool hasInstance(JSContext* cx, HandleObject wrapper,
                            MutableHandleValue v, bool* bp) const override;
   virtual const char* className(JSContext* cx,
                                 HandleObject wrapper) const override;
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -82,20 +82,23 @@ using JS::UTF8CharsZ;
 using JS::WTF8Chars;
 
 using JS::Ok;
 using JS::OOM;
 using JS::Result;
 
 using JS::AutoIdVector;
 
+using JS::HandleIdVector;
 using JS::HandleObjectVector;
 using JS::HandleValueVector;
+using JS::MutableHandleIdVector;
 using JS::MutableHandleObjectVector;
 using JS::MutableHandleValueVector;
+using JS::RootedIdVector;
 using JS::RootedObjectVector;
 using JS::RootedValueVector;
 
 using JS::IdVector;
 using JS::ScriptVector;
 using JS::ValueVector;
 
 using JS::GCHashMap;
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -877,17 +877,17 @@ bool js::ArraySetLength(JSContext* cx, H
       // This heuristic's kind of a huge guess -- "large number of
       // elements" and "probably sparse" are completely unprincipled
       // predictions.  In the long run, bug 586842 will support the right
       // fix: store sparse elements in a sorted data structure that
       // permits fast in-reverse-order traversal and concurrent removals.
 
       Vector<uint32_t> indexes(cx);
       {
-        AutoIdVector props(cx);
+        RootedIdVector props(cx);
         if (!GetPropertyKeys(cx, arr, JSITER_OWNONLY | JSITER_HIDDEN, &props)) {
           return false;
         }
 
         for (size_t i = 0; i < props.length(); i++) {
           if (!CheckForInterrupt(cx)) {
             return false;
           }
--- a/js/src/builtin/JSON.cpp
+++ b/js/src/builtin/JSON.cpp
@@ -192,34 +192,34 @@ static bool Quote(JSContext* cx, StringB
 
 namespace {
 
 using ObjectVector = GCVector<JSObject*, 8>;
 
 class StringifyContext {
  public:
   StringifyContext(JSContext* cx, StringBuffer& sb, const StringBuffer& gap,
-                   HandleObject replacer, const AutoIdVector& propertyList,
+                   HandleObject replacer, const RootedIdVector& propertyList,
                    bool maybeSafely)
       : sb(sb),
         gap(gap),
         replacer(cx, replacer),
         stack(cx, ObjectVector(cx)),
         propertyList(propertyList),
         depth(0),
         maybeSafely(maybeSafely) {
     MOZ_ASSERT_IF(maybeSafely, !replacer);
     MOZ_ASSERT_IF(maybeSafely, gap.empty());
   }
 
   StringBuffer& sb;
   const StringBuffer& gap;
   RootedObject replacer;
   Rooted<ObjectVector> stack;
-  const AutoIdVector& propertyList;
+  const RootedIdVector& propertyList;
   uint32_t depth;
   bool maybeSafely;
 };
 
 } /* anonymous namespace */
 
 static bool Str(JSContext* cx, const Value& v, StringifyContext* scx);
 
@@ -430,18 +430,18 @@ static bool JO(JSContext* cx, HandleObje
     return false;
   }
 
   if (!scx->sb.append('{')) {
     return false;
   }
 
   /* Steps 5-7. */
-  Maybe<AutoIdVector> ids;
-  const AutoIdVector* props;
+  Maybe<RootedIdVector> ids;
+  const RootedIdVector* props;
   if (scx->replacer && !scx->replacer->isCallable()) {
     // NOTE: We can't assert |IsArray(scx->replacer)| because the replacer
     //       might have been a revocable proxy to an array.  Such a proxy
     //       satisfies |IsArray|, but any side effect of JSON.stringify
     //       could revoke the proxy so that |!IsArray(scx->replacer)|.  See
     //       bug 1196497.
     props = &scx->propertyList;
   } else {
@@ -449,17 +449,17 @@ static bool JO(JSContext* cx, HandleObje
     ids.emplace(cx);
     if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, ids.ptr())) {
       return false;
     }
     props = ids.ptr();
   }
 
   /* My kingdom for not-quite-initialized-from-the-start references. */
-  const AutoIdVector& propertyList = *props;
+  const RootedIdVector& propertyList = *props;
 
   /* Steps 8-10, 13. */
   bool wroteMember = false;
   RootedId id(cx);
   for (size_t i = 0, len = propertyList.length(); i < len; i++) {
     if (!CheckForInterrupt(cx)) {
       return false;
     }
@@ -720,17 +720,17 @@ bool js::Stringify(JSContext* cx, Mutabl
    * consumers could get wrong, so needs a better error message.
    */
   MOZ_ASSERT(stringifyBehavior == StringifyBehavior::Normal ||
                  vp.toObject().is<PlainObject>() ||
                  vp.toObject().is<ArrayObject>(),
              "input to JS::ToJSONMaybeSafely must be a plain object or array");
 
   /* Step 4. */
-  AutoIdVector propertyList(cx);
+  RootedIdVector propertyList(cx);
   if (replacer) {
     bool isArray;
     if (replacer->isCallable()) {
       /* Step 4a(i): use replacer to transform values.  */
     } else if (!IsArray(cx, replacer, &isArray)) {
       return false;
     } else if (isArray) {
       /* Step 4b(iii). */
@@ -933,17 +933,17 @@ static bool Walk(JSContext* cx, HandleOb
           desc.setDataDescriptor(newElement, JSPROP_ENUMERATE);
           if (!DefineProperty(cx, obj, id, desc, ignored)) {
             return false;
           }
         }
       }
     } else {
       /* Step 2b(i). */
-      AutoIdVector keys(cx);
+      RootedIdVector keys(cx);
       if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &keys)) {
         return false;
       }
 
       /* Step 2b(ii). */
       RootedId id(cx);
       RootedValue newElement(cx);
       for (size_t i = 0, len = keys.length(); i < len; i++) {
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -633,17 +633,17 @@ bool ModuleNamespaceObject::ProxyHandler
   if (ns->bindings().has(id)) {
     return result.failCantDelete();
   }
 
   return result.succeed();
 }
 
 bool ModuleNamespaceObject::ProxyHandler::ownPropertyKeys(
-    JSContext* cx, HandleObject proxy, AutoIdVector& props) const {
+    JSContext* cx, HandleObject proxy, MutableHandleIdVector props) const {
   Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
   RootedObject exports(cx, &ns->exports());
   uint32_t count;
   if (!GetLengthProperty(cx, exports, &count) ||
       !props.reserve(props.length() + count + 1)) {
     return false;
   }
 
--- a/js/src/builtin/ModuleObject.h
+++ b/js/src/builtin/ModuleObject.h
@@ -170,17 +170,17 @@ class ModuleNamespaceObject : public Pro
 
     bool getOwnPropertyDescriptor(
         JSContext* cx, HandleObject proxy, HandleId id,
         MutableHandle<PropertyDescriptor> desc) const override;
     bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
                         Handle<PropertyDescriptor> desc,
                         ObjectOpResult& result) const override;
     bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                         AutoIdVector& props) const override;
+                         MutableHandleIdVector props) const override;
     bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
                  ObjectOpResult& result) const override;
     bool getPrototype(JSContext* cx, HandleObject proxy,
                       MutableHandleObject protop) const override;
     bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
                       ObjectOpResult& result) const override;
     bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy,
                                 bool* isOrdinary,
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -240,17 +240,17 @@ JSString* js::ObjectToSource(JSContext* 
   StringBuffer buf(cx);
   if (outermost && !buf.append('(')) {
     return nullptr;
   }
   if (!buf.append('{')) {
     return nullptr;
   }
 
-  AutoIdVector idv(cx);
+  RootedIdVector idv(cx);
   if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv)) {
     return nullptr;
   }
 
   bool comma = false;
 
   auto AddProperty = [cx, &comma, &buf](HandleId id, HandleValue val,
                                         PropertyKind kind) -> bool {
@@ -832,17 +832,17 @@ static bool TryAssignNative(JSContext* c
     }
   }
 
   return true;
 }
 
 static bool AssignSlow(JSContext* cx, HandleObject to, HandleObject from) {
   // Step 4.b.ii.
-  AutoIdVector keys(cx);
+  RootedIdVector keys(cx);
   if (!GetPropertyKeys(
           cx, from, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &keys)) {
     return false;
   }
 
   // Step 4.c.
   RootedId nextKey(cx);
   RootedValue propValue(cx);
@@ -991,30 +991,30 @@ static bool ObjectDefineProperties(JSCon
   // Step 1. implicit
   // Step 2.
   RootedObject props(cx, ToObject(cx, properties));
   if (!props) {
     return false;
   }
 
   // Step 3.
-  AutoIdVector keys(cx);
+  RootedIdVector keys(cx);
   if (!GetPropertyKeys(
           cx, props, JSITER_OWNONLY | JSITER_SYMBOLS | JSITER_HIDDEN, &keys)) {
     return false;
   }
 
   RootedId nextKey(cx);
   Rooted<PropertyDescriptor> desc(cx);
   RootedValue descObj(cx);
 
   // Step 4.
   Rooted<PropertyDescriptorVector> descriptors(cx,
                                                PropertyDescriptorVector(cx));
-  AutoIdVector descriptorKeys(cx);
+  RootedIdVector descriptorKeys(cx);
 
   // Step 5.
   for (size_t i = 0, len = keys.length(); i < len; i++) {
     nextKey = keys[i];
 
     // Step 5.a.
     if (!GetOwnPropertyDescriptor(cx, props, nextKey, &desc)) {
       return false;
@@ -1507,17 +1507,17 @@ static bool EnumerableOwnProperties(JSCo
   if (optimized) {
     return true;
   }
 
   // Typed arrays are always handled in the fast path.
   MOZ_ASSERT(!obj->is<TypedArrayObject>());
 
   // Step 2.
-  AutoIdVector ids(cx);
+  RootedIdVector ids(cx);
   if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &ids)) {
     return false;
   }
 
   // Step 3.
   RootedValueVector properties(cx);
   size_t len = ids.length();
   if (!properties.resize(len)) {
@@ -1680,17 +1680,17 @@ bool js::IdToStringOrSymbol(JSContext* c
 
 // ES2018 draft rev c164be80f7ea91de5526b33d54e5c9321ed03d3f
 // 19.1.2.10.1 Runtime Semantics: GetOwnPropertyKeys ( O, Type )
 bool js::GetOwnPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags,
                             MutableHandleValue rval) {
   // Step 1 (Performed in caller).
 
   // Steps 2-4.
-  AutoIdVector keys(cx);
+  RootedIdVector keys(cx);
   if (!GetPropertyKeys(cx, obj, flags, &keys)) {
     return false;
   }
 
   // Step 5 (Inlined CreateArrayFromList).
   RootedArrayObject array(cx, NewDenseFullyAllocatedArray(cx, keys.length()));
   if (!array) {
     return false;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -5378,17 +5378,17 @@ static bool AssertCorrectRealm(JSContext
 }
 
 static bool GlobalLexicals(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<LexicalEnvironmentObject*> globalLexical(
       cx, &cx->global()->lexicalEnvironment());
 
-  AutoIdVector props(cx);
+  RootedIdVector props(cx);
   if (!GetPropertyKeys(cx, globalLexical, JSITER_HIDDEN, &props)) {
     return false;
   }
 
   RootedObject res(cx, JS_NewPlainObject(cx));
   if (!res) {
     return false;
   }
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -763,17 +763,17 @@ CheckedInt32 StructMetaTypeDescr::Layout
   }
   return RoundUpToAlignment(sizeSoFar, structAlignment);
 }
 
 /* static */
 JSObject* StructMetaTypeDescr::create(JSContext* cx, HandleObject metaTypeDescr,
                                       HandleObject fields) {
   // Obtain names of fields, which are the own properties of `fields`
-  AutoIdVector ids(cx);
+  RootedIdVector ids(cx);
   if (!GetPropertyKeys(cx, fields, JSITER_OWNONLY | JSITER_SYMBOLS, &ids)) {
     return nullptr;
   }
 
   // Iterate through each field. Collect values for the various
   // vectors below and also track total size and alignment. Be wary
   // of overflow!
   RootedValueVector fieldTypeObjs(cx);  // Type descriptor of each field.
@@ -833,17 +833,17 @@ JSObject* StructMetaTypeDescr::create(JS
   return createFromArrays(cx, structTypePrototype, opaque,
                           /* allowConstruct= */ true, ids, fieldTypeObjs,
                           fieldProps);
 }
 
 /* static */
 StructTypeDescr* StructMetaTypeDescr::createFromArrays(
     JSContext* cx, HandleObject structTypePrototype, bool opaque,
-    bool allowConstruct, AutoIdVector& ids, JS::HandleValueVector fieldTypeObjs,
+    bool allowConstruct, HandleIdVector ids, JS::HandleValueVector fieldTypeObjs,
     Vector<StructFieldProps>& fieldProps) {
   StringBuffer stringBuffer(cx);       // Canonical string repr
   RootedValueVector fieldNames(cx);    // Name of each field.
   RootedValueVector fieldOffsets(cx);  // Offset of each field field.
   RootedValueVector fieldMuts(cx);     // Mutability of each field.
   RootedObject userFieldOffsets(cx);   // User-exposed {f:offset} object
   RootedObject userFieldTypes(cx);     // User-exposed {f:descr} object.
   Layout layout;                       // Field offsetter
@@ -2070,17 +2070,17 @@ bool TypedObject::obj_deleteProperty(JSC
   if (!proto) {
     return result.succeed();
   }
 
   return DeleteProperty(cx, proto, id, result);
 }
 
 bool TypedObject::obj_newEnumerate(JSContext* cx, HandleObject obj,
-                                   AutoIdVector& properties,
+                                   MutableHandleIdVector properties,
                                    bool enumerableOnly) {
   MOZ_ASSERT(obj->is<TypedObject>());
   Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
   Rooted<TypeDescr*> descr(cx, &typedObj->typeDescr());
 
   RootedId id(cx);
   switch (descr->kind()) {
     case type::Scalar:
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -431,17 +431,17 @@ class StructMetaTypeDescr : public Nativ
                           HandleObject fields);
 
  public:
   // The prototype cannot be null.
   // The names in `ids` must all be non-numeric.
   // The type objects in `fieldTypeObjs` must all be TypeDescr objects.
   static StructTypeDescr* createFromArrays(
       JSContext* cx, HandleObject structTypePrototype, bool opaque,
-      bool allowConstruct, AutoIdVector& ids, HandleValueVector fieldTypeObjs,
+      bool allowConstruct, HandleIdVector ids, HandleValueVector fieldTypeObjs,
       Vector<StructFieldProps>& fieldProps);
 
   // Properties and methods to be installed on StructType.prototype,
   // and hence inherited by all struct type objects:
   static const JSPropertySpec typeObjectProperties[];
   static const JSFunctionSpec typeObjectMethods[];
 
   // Properties and methods to be installed on StructType.prototype.prototype,
@@ -575,17 +575,17 @@ class TypedObject : public JSObject {
                                               HandleId id,
                                               ObjectOpResult& result);
 
   uint8_t* typedMem() const;
   uint8_t* typedMemBase() const;
 
  public:
   static MOZ_MUST_USE bool obj_newEnumerate(JSContext* cx, HandleObject obj,
-                                            AutoIdVector& properties,
+                                            MutableHandleIdVector properties,
                                             bool enumerableOnly);
 
   TypedProto& typedProto() const {
     // Typed objects' prototypes can't be modified.
     return staticPrototype()->as<TypedProto>();
   }
 
   TypeDescr& typeDescr() const { return group()->typeDescr(); }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -915,17 +915,17 @@ JS_PUBLIC_API bool JS_EnumerateStandardC
   CHECK_THREAD(cx);
   cx->check(obj);
   Handle<GlobalObject*> global = obj.as<GlobalObject>();
   return GlobalObject::initStandardClasses(cx, global);
 }
 
 static bool EnumerateStandardClassesInTable(JSContext* cx,
                                             Handle<GlobalObject*> global,
-                                            AutoIdVector& properties,
+                                            MutableHandleIdVector properties,
                                             const JSStdName* table,
                                             bool includeResolved) {
   for (unsigned i = 0; !table[i].isSentinel(); i++) {
     if (table[i].isDummy()) {
       continue;
     }
 
     JSProtoKey key = table[i].key;
@@ -951,17 +951,17 @@ static bool EnumerateStandardClassesInTa
       return false;
     }
   }
 
   return true;
 }
 
 static bool EnumerateStandardClasses(JSContext* cx, JS::HandleObject obj,
-                                     JS::AutoIdVector& properties,
+                                     JS::MutableHandleIdVector properties,
                                      bool enumerableOnly,
                                      bool includeResolved) {
   if (enumerableOnly) {
     // There are no enumerable standard classes and "undefined" is
     // not enumerable.
     return true;
   }
 
@@ -982,23 +982,23 @@ static bool EnumerateStandardClasses(JSC
     return false;
   }
 
   return true;
 }
 
 JS_PUBLIC_API bool JS_NewEnumerateStandardClasses(JSContext* cx,
                                                   JS::HandleObject obj,
-                                                  JS::AutoIdVector& properties,
+                                                  JS::MutableHandleIdVector properties,
                                                   bool enumerableOnly) {
   return EnumerateStandardClasses(cx, obj, properties, enumerableOnly, false);
 }
 
 JS_PUBLIC_API bool JS_NewEnumerateStandardClassesIncludingResolved(
-    JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
+    JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
     bool enumerableOnly) {
   return EnumerateStandardClasses(cx, obj, properties, enumerableOnly, true);
 }
 
 JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key,
                                      MutableHandleObject objp) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
@@ -2521,17 +2521,17 @@ JS_PUBLIC_API bool JS_DeleteElement(JSCo
 
 JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, HandleObject obj,
                                 JS::MutableHandle<IdVector> props) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(obj, props);
   MOZ_ASSERT(props.empty());
 
-  AutoIdVector ids(cx);
+  RootedIdVector ids(cx);
   if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &ids)) {
     return false;
   }
 
   return props.append(ids.begin(), ids.end());
 }
 
 JS_PUBLIC_API bool JS::IsCallable(JSObject* obj) { return obj->isCallable(); }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -647,26 +647,26 @@ extern JS_PUBLIC_API bool JS_EnumerateSt
 /**
  * Fill "properties" with a list of standard class names that have not yet been
  * resolved on "obj".  This can be used as (part of) a newEnumerate class hook
  * on a global.  Already-resolved things are excluded because they might have
  * been deleted by script after being resolved and enumeration considers
  * already-defined properties anyway.
  */
 extern JS_PUBLIC_API bool JS_NewEnumerateStandardClasses(
-    JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
+    JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
     bool enumerableOnly);
 
 /**
  * Fill "properties" with a list of standard class names.  This can be used for
  * proxies that want to define behavior that looks like enumerating a global
  * without touching the global itself.
  */
 extern JS_PUBLIC_API bool JS_NewEnumerateStandardClassesIncludingResolved(
-    JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties,
+    JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
     bool enumerableOnly);
 
 extern JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key,
                                             JS::MutableHandle<JSObject*> objp);
 
 extern JS_PUBLIC_API bool JS_GetClassPrototype(
     JSContext* cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp);
 
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -856,17 +856,17 @@ static bool FormatFrame(JSContext* cx, c
         }
       }
     }
   }
 
   if (showThisProps && thisVal.isObject()) {
     RootedObject obj(cx, &thisVal.toObject());
 
-    AutoIdVector keys(cx);
+    RootedIdVector keys(cx);
     if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &keys)) {
       if (cx->isThrowingOutOfMemory()) {
         return false;
       }
       cx->clearPendingException();
     }
 
     for (size_t i = 0; i < keys.length(); i++) {
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -952,20 +952,20 @@ inline void CopyFlatStringChars(char16_t
  *     JSITER_SYMBOLSONLY - Exclude non-symbol property keys.
  *
  * This is the closest C++ API we have to `Reflect.ownKeys(obj)`, or
  * equivalently, the ES6 [[OwnPropertyKeys]] internal method. Pass
  * `JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS` as flags to get
  * results that match the output of Reflect.ownKeys.
  */
 JS_FRIEND_API bool GetPropertyKeys(JSContext* cx, JS::HandleObject obj,
-                                   unsigned flags, JS::AutoIdVector* props);
-
-JS_FRIEND_API bool AppendUnique(JSContext* cx, JS::AutoIdVector& base,
-                                JS::AutoIdVector& others);
+                                   unsigned flags, JS::MutableHandleIdVector props);
+
+JS_FRIEND_API bool AppendUnique(JSContext* cx, JS::MutableHandleIdVector base,
+                                JS::HandleIdVector others);
 
 /**
  * Determine whether the given string is an array index in the sense of
  * <https://tc39.github.io/ecma262/#array-index>.
  *
  * If it isn't, returns false.
  *
  * If it is, returns true and outputs the index in *indexp.
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -225,17 +225,17 @@ bool js::SetPropertyIgnoringNamedGetter(
   if (!CallSetter(cx, receiver, setterValue, v)) {
     return false;
   }
   return result.succeed();
 }
 
 bool BaseProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx,
                                                     HandleObject proxy,
-                                                    AutoIdVector& props) const {
+                                                    MutableHandleIdVector props) const {
   assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
   MOZ_ASSERT(props.length() == 0);
 
   if (!ownPropertyKeys(cx, proxy, props)) {
     return false;
   }
 
   /* Select only the enumerable properties through in-place iteration. */
@@ -264,23 +264,23 @@ bool BaseProxyHandler::getOwnEnumerableP
   if (!props.resize(i)) {
     return false;
   }
 
   return true;
 }
 
 bool BaseProxyHandler::enumerate(JSContext* cx, HandleObject proxy,
-                                 AutoIdVector& props) const {
+                                 MutableHandleIdVector props) const {
   assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
 
   // GetPropertyKeys will invoke getOwnEnumerablePropertyKeys along the proto
   // chain for us.
   MOZ_ASSERT(props.empty());
-  return GetPropertyKeys(cx, proxy, 0, &props);
+  return GetPropertyKeys(cx, proxy, 0, props);
 }
 
 bool BaseProxyHandler::call(JSContext* cx, HandleObject proxy,
                             const CallArgs& args) const {
   MOZ_CRASH("callable proxies should implement call trap");
 }
 
 bool BaseProxyHandler::construct(JSContext* cx, HandleObject proxy,
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -31,17 +31,17 @@ using namespace js;
 
 #define NOTHING (true)
 
 static bool MarkAtoms(JSContext* cx, jsid id) {
   cx->markId(id);
   return true;
 }
 
-static bool MarkAtoms(JSContext* cx, const AutoIdVector& ids) {
+static bool MarkAtoms(JSContext* cx, HandleIdVector ids) {
   for (size_t i = 0; i < ids.length(); i++) {
     cx->markId(ids[i]);
   }
   return true;
 }
 
 bool CrossCompartmentWrapper::getOwnPropertyDescriptor(
     JSContext* cx, HandleObject wrapper, HandleId id,
@@ -57,17 +57,17 @@ bool CrossCompartmentWrapper::defineProp
                                              ObjectOpResult& result) const {
   Rooted<PropertyDescriptor> desc2(cx, desc);
   PIERCE(cx, wrapper, MarkAtoms(cx, id) && cx->compartment()->wrap(cx, &desc2),
          Wrapper::defineProperty(cx, wrapper, id, desc2, result), NOTHING);
 }
 
 bool CrossCompartmentWrapper::ownPropertyKeys(JSContext* cx,
                                               HandleObject wrapper,
-                                              AutoIdVector& props) const {
+                                              MutableHandleIdVector props) const {
   PIERCE(cx, wrapper, NOTHING, Wrapper::ownPropertyKeys(cx, wrapper, props),
          MarkAtoms(cx, props));
 }
 
 bool CrossCompartmentWrapper::delete_(JSContext* cx, HandleObject wrapper,
                                       HandleId id,
                                       ObjectOpResult& result) const {
   PIERCE(cx, wrapper, MarkAtoms(cx, id),
@@ -200,24 +200,24 @@ bool CrossCompartmentWrapper::set(JSCont
   RootedValue receiverCopy(cx, receiver);
   PIERCE(cx, wrapper,
          MarkAtoms(cx, id) && cx->compartment()->wrap(cx, &valCopy) &&
              WrapReceiver(cx, wrapper, &receiverCopy),
          Wrapper::set(cx, wrapper, id, valCopy, receiverCopy, result), NOTHING);
 }
 
 bool CrossCompartmentWrapper::getOwnEnumerablePropertyKeys(
-    JSContext* cx, HandleObject wrapper, AutoIdVector& props) const {
+    JSContext* cx, HandleObject wrapper, MutableHandleIdVector props) const {
   PIERCE(cx, wrapper, NOTHING,
          Wrapper::getOwnEnumerablePropertyKeys(cx, wrapper, props),
          MarkAtoms(cx, props));
 }
 
 bool CrossCompartmentWrapper::enumerate(JSContext* cx, HandleObject wrapper,
-                                        AutoIdVector& props) const {
+                                        MutableHandleIdVector props) const {
   PIERCE(cx, wrapper, NOTHING, Wrapper::enumerate(cx, wrapper, props),
          MarkAtoms(cx, props));
 }
 
 bool CrossCompartmentWrapper::call(JSContext* cx, HandleObject wrapper,
                                    const CallArgs& args) const {
   RootedObject wrapped(cx, wrappedObject(wrapper));
 
--- a/js/src/proxy/DeadObjectProxy.cpp
+++ b/js/src/proxy/DeadObjectProxy.cpp
@@ -31,17 +31,17 @@ bool DeadObjectProxy::defineProperty(JSC
                                      HandleId id,
                                      Handle<PropertyDescriptor> desc,
                                      ObjectOpResult& result) const {
   ReportDead(cx);
   return false;
 }
 
 bool DeadObjectProxy::ownPropertyKeys(JSContext* cx, HandleObject wrapper,
-                                      AutoIdVector& props) const {
+                                      MutableHandleIdVector props) const {
   ReportDead(cx);
   return false;
 }
 
 bool DeadObjectProxy::delete_(JSContext* cx, HandleObject wrapper, HandleId id,
                               ObjectOpResult& result) const {
   ReportDead(cx);
   return false;
--- a/js/src/proxy/DeadObjectProxy.h
+++ b/js/src/proxy/DeadObjectProxy.h
@@ -26,17 +26,17 @@ class DeadObjectProxy : public BaseProxy
   /* Standard internal methods. */
   virtual bool getOwnPropertyDescriptor(
       JSContext* cx, HandleObject wrapper, HandleId id,
       MutableHandle<PropertyDescriptor> desc) const override;
   virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
                               Handle<PropertyDescriptor> desc,
                               ObjectOpResult& result) const override;
   virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
-                               AutoIdVector& props) const override;
+                               MutableHandleIdVector props) const override;
   virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
                        ObjectOpResult& result) const override;
   virtual bool getPrototype(JSContext* cx, HandleObject proxy,
                             MutableHandleObject protop) const override;
   virtual bool getPrototypeIfOrdinary(
       JSContext* cx, HandleObject proxy, bool* isOrdinary,
       MutableHandleObject protop) const override;
   virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
--- a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
+++ b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
@@ -20,28 +20,28 @@ bool OpaqueCrossCompartmentWrapper::getO
 bool OpaqueCrossCompartmentWrapper::defineProperty(
     JSContext* cx, HandleObject wrapper, HandleId id,
     Handle<PropertyDescriptor> desc, ObjectOpResult& result) const {
   return result.succeed();
 }
 
 bool OpaqueCrossCompartmentWrapper::ownPropertyKeys(JSContext* cx,
                                                     HandleObject wrapper,
-                                                    AutoIdVector& props) const {
+                                                    MutableHandleIdVector props) const {
   return true;
 }
 
 bool OpaqueCrossCompartmentWrapper::delete_(JSContext* cx, HandleObject wrapper,
                                             HandleId id,
                                             ObjectOpResult& result) const {
   return result.succeed();
 }
 
 bool OpaqueCrossCompartmentWrapper::enumerate(JSContext* cx, HandleObject proxy,
-                                              AutoIdVector& props) const {
+                                              MutableHandleIdVector props) const {
   return BaseProxyHandler::enumerate(cx, proxy, props);
 }
 
 bool OpaqueCrossCompartmentWrapper::getPrototype(
     JSContext* cx, HandleObject proxy, MutableHandleObject protop) const {
   protop.set(nullptr);
   return true;
 }
@@ -112,17 +112,17 @@ bool OpaqueCrossCompartmentWrapper::cons
 }
 
 bool OpaqueCrossCompartmentWrapper::hasOwn(JSContext* cx, HandleObject wrapper,
                                            HandleId id, bool* bp) const {
   return BaseProxyHandler::hasOwn(cx, wrapper, id, bp);
 }
 
 bool OpaqueCrossCompartmentWrapper::getOwnEnumerablePropertyKeys(
-    JSContext* cx, HandleObject wrapper, AutoIdVector& props) const {
+    JSContext* cx, HandleObject wrapper, MutableHandleIdVector props) const {
   return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, wrapper, props);
 }
 
 bool OpaqueCrossCompartmentWrapper::getBuiltinClass(JSContext* cx,
                                                     HandleObject wrapper,
                                                     ESClass* cls) const {
   *cls = ESClass::Other;
   return true;
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -104,17 +104,17 @@ bool Proxy::defineProperty(JSContext* cx
     }
     return result.succeed();
   }
   return proxy->as<ProxyObject>().handler()->defineProperty(cx, proxy, id, desc,
                                                             result);
 }
 
 bool Proxy::ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                            AutoIdVector& props) {
+                            MutableHandleIdVector props) {
   if (!CheckRecursionLimit(cx)) {
     return false;
   }
   const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
   AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
                          BaseProxyHandler::ENUMERATE, true);
   if (!policy.allowed()) {
     return policy.returnValue();
@@ -134,19 +134,19 @@ bool Proxy::delete_(JSContext* cx, Handl
     if (ok) {
       result.succeed();
     }
     return ok;
   }
   return proxy->as<ProxyObject>().handler()->delete_(cx, proxy, id, result);
 }
 
-JS_FRIEND_API bool js::AppendUnique(JSContext* cx, AutoIdVector& base,
-                                    AutoIdVector& others) {
-  AutoIdVector uniqueOthers(cx);
+JS_FRIEND_API bool js::AppendUnique(JSContext* cx, MutableHandleIdVector base,
+                                    HandleIdVector others) {
+  RootedIdVector uniqueOthers(cx);
   if (!uniqueOthers.reserve(others.length())) {
     return false;
   }
   for (size_t i = 0; i < others.length(); ++i) {
     bool unique = true;
     for (size_t j = 0; j < base.length(); ++j) {
       if (others[i].get() == base[j]) {
         unique = false;
@@ -425,30 +425,30 @@ bool js::ProxySetPropertyByValue(JSConte
   RootedValue receiver(cx, ObjectValue(*proxy));
   if (!Proxy::setInternal(cx, proxy, id, val, receiver, result)) {
     return false;
   }
   return result.checkStrictErrorOrWarning(cx, proxy, id, strict);
 }
 
 bool Proxy::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
-                                         AutoIdVector& props) {
+                                         MutableHandleIdVector props) {
   if (!CheckRecursionLimit(cx)) {
     return false;
   }
   const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
   AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
                          BaseProxyHandler::ENUMERATE, true);
   if (!policy.allowed()) {
     return policy.returnValue();
   }
   return handler->getOwnEnumerablePropertyKeys(cx, proxy, props);
 }
 
-bool Proxy::enumerate(JSContext* cx, HandleObject proxy, AutoIdVector& props) {
+bool Proxy::enumerate(JSContext* cx, HandleObject proxy, MutableHandleIdVector props) {
   if (!CheckRecursionLimit(cx)) {
     return false;
   }
 
   const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
   if (handler->hasPrototype()) {
     if (!Proxy::getOwnEnumerablePropertyKeys(cx, proxy, props)) {
       return false;
@@ -459,17 +459,17 @@ bool Proxy::enumerate(JSContext* cx, Han
       return false;
     }
     if (!proto) {
       return true;
     }
 
     cx->check(proxy, proto);
 
-    AutoIdVector protoProps(cx);
+    RootedIdVector protoProps(cx);
     if (!GetPropertyKeys(cx, proto, 0, &protoProps)) {
       return false;
     }
     return AppendUnique(cx, props, protoProps);
   }
 
   AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
                          BaseProxyHandler::ENUMERATE, true);
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -28,20 +28,20 @@ class Proxy {
   /* Standard internal methods. */
   static bool getOwnPropertyDescriptor(
       JSContext* cx, HandleObject proxy, HandleId id,
       MutableHandle<JS::PropertyDescriptor> desc);
   static bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
                              Handle<JS::PropertyDescriptor> desc,
                              ObjectOpResult& result);
   static bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                              AutoIdVector& props);
+                              MutableHandleIdVector props);
   static bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
                       ObjectOpResult& result);
-  static bool enumerate(JSContext* cx, HandleObject proxy, AutoIdVector& props);
+  static bool enumerate(JSContext* cx, HandleObject proxy, MutableHandleIdVector props);
   static bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible);
   static bool preventExtensions(JSContext* cx, HandleObject proxy,
                                 ObjectOpResult& result);
   static bool getPrototype(JSContext* cx, HandleObject proxy,
                            MutableHandleObject protop);
   static bool setPrototype(JSContext* cx, HandleObject proxy,
                            HandleObject proto, ObjectOpResult& result);
   static bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy,
@@ -62,17 +62,17 @@ class Proxy {
                           ObjectOpResult& result);
   static bool call(JSContext* cx, HandleObject proxy, const CallArgs& args);
   static bool construct(JSContext* cx, HandleObject proxy,
                         const CallArgs& args);
 
   /* SpiderMonkey extensions. */
   static bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp);
   static bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
-                                           AutoIdVector& props);
+                                           MutableHandleIdVector props);
   static bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                          const CallArgs& args);
   static bool hasInstance(JSContext* cx, HandleObject proxy,
                           MutableHandleValue v, bool* bp);
   static bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls);
   static bool isArray(JSContext* cx, HandleObject proxy,
                       JS::IsArrayAnswer* answer);
   static const char* className(JSContext* cx, HandleObject proxy);
--- a/js/src/proxy/ScriptedProxyHandler.cpp
+++ b/js/src/proxy/ScriptedProxyHandler.cpp
@@ -737,17 +737,17 @@ bool ScriptedProxyHandler::definePropert
 
   // Step 17.
   return result.succeed();
 }
 
 // ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93
 // 7.3.17 CreateListFromArrayLike with elementTypes fixed to symbol/string.
 static bool CreateFilteredListFromArrayLike(JSContext* cx, HandleValue v,
-                                            AutoIdVector& props) {
+                                            MutableHandleIdVector props) {
   // Step 2.
   RootedObject obj(
       cx, NonNullObjectWithName(cx, "return value of the ownKeys trap", v));
   if (!obj) {
     return false;
   }
 
   // Step 3.
@@ -788,17 +788,17 @@ static bool CreateFilteredListFromArrayL
 
   // Step 7.
   return true;
 }
 
 // ES2018 draft rev aab1ea3bd4d03c85d6f4a91503b4169346ab7271
 // 9.5.11 Proxy.[[OwnPropertyKeys]]()
 bool ScriptedProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                                           AutoIdVector& props) const {
+                                           MutableHandleIdVector props) const {
   // Steps 1-3.
   RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy));
   if (!handler) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_PROXY_REVOKED);
     return false;
   }
 
@@ -810,29 +810,29 @@ bool ScriptedProxyHandler::ownPropertyKe
   RootedValue trap(cx);
   if (!GetProxyTrap(cx, handler, cx->names().ownKeys, &trap)) {
     return false;
   }
 
   // Step 6.
   if (trap.isUndefined()) {
     return GetPropertyKeys(
-        cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &props);
+        cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
   }
 
   // Step 7.
   RootedValue trapResultArray(cx);
   RootedValue targetVal(cx, ObjectValue(*target));
   if (!Call(cx, trap, handler, targetVal, &trapResultArray)) {
     return false;
   }
 
   // Step 8.
-  AutoIdVector trapResult(cx);
-  if (!CreateFilteredListFromArrayLike(cx, trapResultArray, trapResult)) {
+  RootedIdVector trapResult(cx);
+  if (!CreateFilteredListFromArrayLike(cx, trapResultArray, &trapResult)) {
     return false;
   }
 
   // Steps 9, 18.
   Rooted<GCHashSet<jsid>> uncheckedResultKeys(
       cx, GCHashSet<jsid>(cx, trapResult.length()));
 
   for (size_t i = 0, len = trapResult.length(); i < len; i++) {
@@ -850,26 +850,26 @@ bool ScriptedProxyHandler::ownPropertyKe
 
   // Step 10.
   bool extensibleTarget;
   if (!IsExtensible(cx, target, &extensibleTarget)) {
     return false;
   }
 
   // Steps 11-13.
-  AutoIdVector targetKeys(cx);
+  RootedIdVector targetKeys(cx);
   if (!GetPropertyKeys(cx, target,
                        JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
                        &targetKeys)) {
     return false;
   }
 
   // Steps 14-15.
-  AutoIdVector targetConfigurableKeys(cx);
-  AutoIdVector targetNonconfigurableKeys(cx);
+  RootedIdVector targetConfigurableKeys(cx);
+  RootedIdVector targetNonconfigurableKeys(cx);
 
   // Step 16.
   Rooted<PropertyDescriptor> desc(cx);
   for (size_t i = 0; i < targetKeys.length(); ++i) {
     // Step 16.a.
     if (!GetOwnPropertyDescriptor(cx, target, targetKeys[i], &desc)) {
       return false;
     }
--- a/js/src/proxy/ScriptedProxyHandler.h
+++ b/js/src/proxy/ScriptedProxyHandler.h
@@ -19,17 +19,17 @@ class ScriptedProxyHandler : public Base
   /* Standard internal methods. */
   virtual bool getOwnPropertyDescriptor(
       JSContext* cx, HandleObject proxy, HandleId id,
       MutableHandle<PropertyDescriptor> desc) const override;
   virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
                               Handle<PropertyDescriptor> desc,
                               ObjectOpResult& result) const override;
   virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                               AutoIdVector& props) const override;
+                               MutableHandleIdVector props) const override;
   virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
                        ObjectOpResult& result) const override;
 
   virtual bool getPrototype(JSContext* cx, HandleObject proxy,
                             MutableHandleObject protop) const override;
   virtual bool setPrototype(JSContext* cx, HandleObject proxy,
                             HandleObject proto,
                             ObjectOpResult& result) const override;
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -55,33 +55,33 @@ bool ForwardingProxyHandler::definePrope
                                             Handle<PropertyDescriptor> desc,
                                             ObjectOpResult& result) const {
   assertEnteredPolicy(cx, proxy, id, SET);
   RootedObject target(cx, proxy->as<ProxyObject>().target());
   return DefineProperty(cx, target, id, desc, result);
 }
 
 bool ForwardingProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                                             AutoIdVector& props) const {
+                                             MutableHandleIdVector props) const {
   assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
   RootedObject target(cx, proxy->as<ProxyObject>().target());
   return GetPropertyKeys(
-      cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &props);
+      cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
 }
 
 bool ForwardingProxyHandler::delete_(JSContext* cx, HandleObject proxy,
                                      HandleId id,
                                      ObjectOpResult& result) const {
   assertEnteredPolicy(cx, proxy, id, SET);
   RootedObject target(cx, proxy->as<ProxyObject>().target());
   return DeleteProperty(cx, target, id, result);
 }
 
 bool ForwardingProxyHandler::enumerate(JSContext* cx, HandleObject proxy,
-                                       AutoIdVector& props) const {
+                                       MutableHandleIdVector props) const {
   assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
   MOZ_ASSERT(
       !hasPrototype());  // Should never be called if there's a prototype.
   RootedObject target(cx, proxy->as<ProxyObject>().target());
   return EnumerateProperties(cx, target, props);
 }
 
 bool ForwardingProxyHandler::getPrototype(JSContext* cx, HandleObject proxy,
@@ -190,20 +190,20 @@ bool ForwardingProxyHandler::construct(J
 bool ForwardingProxyHandler::hasOwn(JSContext* cx, HandleObject proxy,
                                     HandleId id, bool* bp) const {
   assertEnteredPolicy(cx, proxy, id, GET);
   RootedObject target(cx, proxy->as<ProxyObject>().target());
   return HasOwnProperty(cx, target, id, bp);
 }
 
 bool ForwardingProxyHandler::getOwnEnumerablePropertyKeys(
-    JSContext* cx, HandleObject proxy, AutoIdVector& props) const {
+    JSContext* cx, HandleObject proxy, MutableHandleIdVector props) const {
   assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
   RootedObject target(cx, proxy->as<ProxyObject>().target());
-  return GetPropertyKeys(cx, target, JSITER_OWNONLY, &props);
+  return GetPropertyKeys(cx, target, JSITER_OWNONLY, props);
 }
 
 bool ForwardingProxyHandler::nativeCall(JSContext* cx, IsAcceptableThis test,
                                         NativeImpl impl,
                                         const CallArgs& args) const {
   args.setThis(
       ObjectValue(*args.thisv().toObject().as<ProxyObject>().target()));
   if (!test(args.thisv())) {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3715,17 +3715,17 @@ static bool ThrowError(JSContext* cx, un
 typedef struct ComplexObject {
   bool isInner;
   bool frozen;
   JSObject* inner;
   JSObject* outer;
 } ComplexObject;
 
 static bool sandbox_enumerate(JSContext* cx, JS::HandleObject obj,
-                              JS::AutoIdVector& properties,
+                              JS::MutableHandleIdVector properties,
                               bool enumerableOnly) {
   RootedValue v(cx);
 
   if (!JS_GetProperty(cx, obj, "lazy", &v)) {
     return false;
   }
 
   if (!ToBoolean(v)) {
@@ -9152,17 +9152,17 @@ static bool PrintHelp(JSContext* cx, Han
     return true;
   }
 
   return PrintHelpString(cx, usage) && PrintHelpString(cx, help);
 }
 
 static bool PrintEnumeratedHelp(JSContext* cx, HandleObject obj,
                                 HandleObject pattern, bool brief) {
-  AutoIdVector idv(cx);
+  RootedIdVector idv(cx);
   if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &idv)) {
     return false;
   }
 
   Rooted<RegExpObject*> regex(cx);
   if (pattern) {
     regex = &UncheckedUnwrap(pattern)->as<RegExpObject>();
   }
@@ -9458,17 +9458,17 @@ void js::shell::WarningReporter(JSContex
     savedExc.restore();
   }
 
   // Print the warning.
   PrintError(cx, fp, JS::ConstUTF8CharsZ(), report, reportWarnings);
 }
 
 static bool global_enumerate(JSContext* cx, JS::HandleObject obj,
-                             JS::AutoIdVector& properties,
+                             JS::MutableHandleIdVector properties,
                              bool enumerableOnly) {
 #ifdef LAZY_STANDARD_CLASSES
   return JS_NewEnumerateStandardClasses(cx, obj, properties, enumerableOnly);
 #else
   return true;
 #endif
 }
 
--- a/js/src/shell/jsshell.cpp
+++ b/js/src/shell/jsshell.cpp
@@ -28,17 +28,17 @@ namespace shell {
 //
 // .usage will be set to "<name> - interface object".
 //
 // .help will be set to a newline-separated list of functions that have either
 // 'help' or 'usage' properties. Functions are described with their usage
 // strings, if they have them, else with just their names.
 //
 bool GenerateInterfaceHelp(JSContext* cx, HandleObject obj, const char* name) {
-  AutoIdVector idv(cx);
+  RootedIdVector idv(cx);
   if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &idv)) {
     return false;
   }
 
   StringBuffer buf(cx);
   int numEntries = 0;
   for (size_t i = 0; i < idv.length(); i++) {
     RootedId id(cx, idv[i]);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -9311,17 +9311,17 @@ static bool DebuggerGenericEval(JSContex
                                 MutableHandleValue value, Debugger* dbg,
                                 HandleObject envArg, FrameIter* iter) {
   // Either we're specifying the frame, or a global.
   MOZ_ASSERT_IF(iter, !envArg);
   MOZ_ASSERT_IF(!iter, envArg && IsGlobalLexicalEnvironment(envArg));
 
   // Gather keys and values of bindings, if any. This must be done in the
   // debugger compartment, since that is where any exceptions must be thrown.
-  AutoIdVector keys(cx);
+  RootedIdVector keys(cx);
   RootedValueVector values(cx);
   if (bindings) {
     if (!GetPropertyKeys(cx, bindings, JSITER_OWNONLY, &keys) ||
         !values.growBy(keys.length())) {
       return false;
     }
     for (size_t i = 0; i < keys.length(); i++) {
       MutableHandleValue valp = values[i];
@@ -10942,17 +10942,17 @@ bool DebuggerObject::definePropertiesMet
     return false;
   }
 
   RootedValue arg(cx, args[0]);
   RootedObject props(cx, ToObject(cx, arg));
   if (!props) {
     return false;
   }
-  AutoIdVector ids(cx);
+  RootedIdVector ids(cx);
   Rooted<PropertyDescriptorVector> descs(cx, PropertyDescriptorVector(cx));
   if (!ReadPropertyDescriptors(cx, props, false, &ids, &descs)) {
     return false;
   }
   Rooted<IdVector> ids2(cx, IdVector(cx));
   if (!ids2.append(ids.begin(), ids.end())) {
     return false;
   }
@@ -11788,17 +11788,17 @@ bool DebuggerObject::getPrototypeOf(JSCo
 }
 
 /* static */
 bool DebuggerObject::getOwnPropertyNames(JSContext* cx,
                                          HandleDebuggerObject object,
                                          MutableHandle<IdVector> result) {
   RootedObject referent(cx, object->referent());
 
-  AutoIdVector ids(cx);
+  RootedIdVector ids(cx);
   {
     Maybe<AutoRealm> ar;
     EnterDebuggeeObjectRealm(cx, ar, referent);
 
     ErrorCopier ec(ar);
     if (!GetPropertyKeys(cx, referent, JSITER_OWNONLY | JSITER_HIDDEN, &ids)) {
       return false;
     }
@@ -11812,17 +11812,17 @@ bool DebuggerObject::getOwnPropertyNames
 }
 
 /* static */
 bool DebuggerObject::getOwnPropertySymbols(JSContext* cx,
                                            HandleDebuggerObject object,
                                            MutableHandle<IdVector> result) {
   RootedObject referent(cx, object->referent());
 
-  AutoIdVector ids(cx);
+  RootedIdVector ids(cx);
   {
     Maybe<AutoRealm> ar;
     EnterDebuggeeObjectRealm(cx, ar, referent);
 
     ErrorCopier ec(ar);
     if (!GetPropertyKeys(cx, referent,
                          JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS |
                              JSITER_SYMBOLSONLY,
@@ -12778,17 +12778,17 @@ bool DebuggerEnvironment::isOptimized() 
 /* static */
 bool DebuggerEnvironment::getNames(JSContext* cx,
                                    HandleDebuggerEnvironment environment,
                                    MutableHandle<IdVector> result) {
   MOZ_ASSERT(environment->isDebuggee());
 
   Rooted<Env*> referent(cx, environment->referent());
 
-  AutoIdVector ids(cx);
+  RootedIdVector ids(cx);
   {
     Maybe<AutoRealm> ar;
     ar.emplace(cx, referent);
 
     ErrorCopier ec(ar);
     if (!GetPropertyKeys(cx, referent, JSITER_HIDDEN, &ids)) {
       return false;
     }
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -542,17 +542,17 @@ bool ModuleEnvironmentObject::getOwnProp
 bool ModuleEnvironmentObject::deleteProperty(JSContext* cx, HandleObject obj,
                                              HandleId id,
                                              ObjectOpResult& result) {
   return result.failCantDelete();
 }
 
 /* static */
 bool ModuleEnvironmentObject::newEnumerate(JSContext* cx, HandleObject obj,
-                                           AutoIdVector& properties,
+                                           MutableHandleIdVector properties,
                                            bool enumerableOnly) {
   RootedModuleEnvironmentObject self(cx, &obj->as<ModuleEnvironmentObject>());
   const IndirectBindingMap& bs(self->importBindings());
 
   MOZ_ASSERT(properties.length() == 0);
   size_t count = bs.count() + self->slotSpan() - RESERVED_SLOTS;
   if (!properties.reserve(count)) {
     ReportOutOfMemory(cx);
@@ -2249,17 +2249,17 @@ class DebugEnvironmentProxyHandler : pub
     if (found) {
       return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP);
     }
 
     return JS_DefinePropertyById(cx, env, id, desc, result);
   }
 
   bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                       AutoIdVector& props) const override {
+                       MutableHandleIdVector props) const override {
     Rooted<EnvironmentObject*> env(
         cx, &proxy->as<DebugEnvironmentProxy>().environment());
 
     if (isMissingArgumentsBinding(*env)) {
       if (!props.append(NameToId(cx->names().arguments))) {
         return false;
       }
     }
@@ -2278,17 +2278,17 @@ class DebugEnvironmentProxyHandler : pub
     // examine @@unscopables.
     RootedObject target(cx);
     bool isWith = env->is<WithEnvironmentObject>();
     if (isWith) {
       target = &env->as<WithEnvironmentObject>().object();
     } else {
       target = env;
     }
-    if (!GetPropertyKeys(cx, target, JSITER_OWNONLY, &props)) {
+    if (!GetPropertyKeys(cx, target, JSITER_OWNONLY, props)) {
       return false;
     }
 
     if (isWith) {
       size_t j = 0;
       for (size_t i = 0; i < props.length(); i++) {
         bool inScope;
         if (!CheckUnscopables(cx, env, props[i], &inScope)) {
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -434,17 +434,17 @@ class ModuleEnvironmentObject : public E
                           HandleValue v, HandleValue receiver,
                           JS::ObjectOpResult& result);
   static bool getOwnPropertyDescriptor(JSContext* cx, HandleObject obj,
                                        HandleId id,
                                        MutableHandle<PropertyDescriptor> desc);
   static bool deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
                              ObjectOpResult& result);
   static bool newEnumerate(JSContext* cx, HandleObject obj,
-                           AutoIdVector& properties, bool enumerableOnly);
+                           MutableHandleIdVector properties, bool enumerableOnly);
 };
 
 typedef Rooted<ModuleEnvironmentObject*> RootedModuleEnvironmentObject;
 typedef Handle<ModuleEnvironmentObject*> HandleModuleEnvironmentObject;
 typedef MutableHandle<ModuleEnvironmentObject*>
     MutableHandleModuleEnvironmentObject;
 
 class WasmInstanceEnvironmentObject : public EnvironmentObject {
--- a/js/src/vm/Iteration.cpp
+++ b/js/src/vm/Iteration.cpp
@@ -98,17 +98,17 @@ void NativeIterator::trace(JSTracer* trc
 }
 
 using IdSet = GCHashSet<jsid, DefaultHasher<jsid>>;
 
 template <bool CheckForDuplicates>
 static inline bool Enumerate(JSContext* cx, HandleObject pobj, jsid id,
                              bool enumerable, unsigned flags,
                              MutableHandle<IdSet> visited,
-                             AutoIdVector* props) {
+                             MutableHandleIdVector props) {
   if (CheckForDuplicates) {
     // If we've already seen this, we definitely won't add it.
     IdSet::AddPtr p = visited.lookupForAdd(id);
     if (MOZ_UNLIKELY(!!p)) {
       return true;
     }
 
     // It's not necessary to add properties to the hash set at the end of
@@ -129,28 +129,28 @@ static inline bool Enumerate(JSContext* 
   // Symbol-keyed properties and nonenumerable properties are skipped unless
   // the caller specifically asks for them. A caller can also filter out
   // non-symbols by asking for JSITER_SYMBOLSONLY.
   if (JSID_IS_SYMBOL(id) ? !(flags & JSITER_SYMBOLS)
                          : (flags & JSITER_SYMBOLSONLY)) {
     return true;
   }
 
-  return props->append(id);
+  return props.append(id);
 }
 
 static bool EnumerateExtraProperties(JSContext* cx, HandleObject obj,
                                      unsigned flags,
                                      MutableHandle<IdSet> visited,
-                                     AutoIdVector* props) {
+                                     MutableHandleIdVector props) {
   MOZ_ASSERT(obj->getClass()->getNewEnumerate());
 
-  AutoIdVector properties(cx);
+  RootedIdVector properties(cx);
   bool enumerableOnly = !(flags & JSITER_HIDDEN);
-  if (!obj->getClass()->getNewEnumerate()(cx, obj, properties,
+  if (!obj->getClass()->getNewEnumerate()(cx, obj, &properties,
                                           enumerableOnly)) {
     return false;
   }
 
   RootedId id(cx);
   for (size_t n = 0; n < properties.length(); n++) {
     id = properties[n];
 
@@ -174,23 +174,23 @@ static bool SortComparatorIntegerIds(jsi
   *lessOrEqualp = (indexA <= indexB);
   return true;
 }
 
 template <bool CheckForDuplicates>
 static bool EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj,
                                       unsigned flags,
                                       MutableHandle<IdSet> visited,
-                                      AutoIdVector* props) {
+                                      MutableHandleIdVector props) {
   bool enumerateSymbols;
   if (flags & JSITER_SYMBOLSONLY) {
     enumerateSymbols = true;
   } else {
     // Collect any dense elements from this object.
-    size_t firstElemIndex = props->length();
+    size_t firstElemIndex = props.length();
     size_t initlen = pobj->getDenseInitializedLength();
     const Value* vp = pobj->getDenseElements();
     bool hasHoles = false;
     for (size_t i = 0; i < initlen; ++i, ++vp) {
       if (vp->isMagic(JS_ELEMENTS_HOLE)) {
         hasHoles = true;
       } else {
         // Dense arrays never get so large that i would not fit into an
@@ -217,49 +217,49 @@ static bool EnumerateNativeProperties(JS
     }
 
     // Collect any sparse elements from this object.
     bool isIndexed = pobj->isIndexed();
     if (isIndexed) {
       // If the dense elements didn't have holes, we don't need to include
       // them in the sort.
       if (!hasHoles) {
-        firstElemIndex = props->length();
+        firstElemIndex = props.length();
       }
 
       for (Shape::Range<NoGC> r(pobj->lastProperty()); !r.empty();
            r.popFront()) {
         Shape& shape = r.front();
         jsid id = shape.propid();
         uint32_t dummy;
         if (IdIsIndex(id, &dummy)) {
           if (!Enumerate<CheckForDuplicates>(cx, pobj, id, shape.enumerable(),
                                              flags, visited, props)) {
             return false;
           }
         }
       }
 
-      MOZ_ASSERT(firstElemIndex <= props->length());
+      MOZ_ASSERT(firstElemIndex <= props.length());
 
-      jsid* ids = props->begin() + firstElemIndex;
-      size_t n = props->length() - firstElemIndex;
+      jsid* ids = props.begin() + firstElemIndex;
+      size_t n = props.length() - firstElemIndex;
 
-      AutoIdVector tmp(cx);
+      RootedIdVector tmp(cx);
       if (!tmp.resize(n)) {
         return false;
       }
       PodCopy(tmp.begin(), ids, n);
 
       if (!MergeSort(ids, n, tmp.begin(), SortComparatorIntegerIds)) {
         return false;
       }
     }
 
-    size_t initialLength = props->length();
+    size_t initialLength = props.length();
 
     /* Collect all unique property names from this object's shape. */
     bool symbolsFound = false;
     Shape::Range<NoGC> r(pobj->lastProperty());
     for (; !r.empty(); r.popFront()) {
       Shape& shape = r.front();
       jsid id = shape.propid();
 
@@ -273,67 +273,67 @@ static bool EnumerateNativeProperties(JS
         continue;
       }
 
       if (!Enumerate<CheckForDuplicates>(cx, pobj, id, shape.enumerable(),
                                          flags, visited, props)) {
         return false;
       }
     }
-    ::Reverse(props->begin() + initialLength, props->end());
+    ::Reverse(props.begin() + initialLength, props.end());
 
     enumerateSymbols = symbolsFound && (flags & JSITER_SYMBOLS);
   }
 
   if (enumerateSymbols) {
     // Do a second pass to collect symbols. ES6 draft rev 25 (2014 May 22)
     // 9.1.12 requires that all symbols appear after all strings in the
     // result.
-    size_t initialLength = props->length();
+    size_t initialLength = props.length();
     for (Shape::Range<NoGC> r(pobj->lastProperty()); !r.empty(); r.popFront()) {
       Shape& shape = r.front();
       jsid id = shape.propid();
       if (JSID_IS_SYMBOL(id)) {
         if (!Enumerate<CheckForDuplicates>(cx, pobj, id, shape.enumerable(),
                                            flags, visited, props)) {
           return false;
         }
       }
     }
-    ::Reverse(props->begin() + initialLength, props->end());
+    ::Reverse(props.begin() + initialLength, props.end());
   }
 
   return true;
 }
 
 static bool EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj,
                                       unsigned flags,
                                       MutableHandle<IdSet> visited,
-                                      AutoIdVector* props,
+                                      MutableHandleIdVector props,
                                       bool checkForDuplicates) {
   if (checkForDuplicates) {
     return EnumerateNativeProperties<true>(cx, pobj, flags, visited, props);
   }
   return EnumerateNativeProperties<false>(cx, pobj, flags, visited, props);
 }
 
 template <bool CheckForDuplicates>
 static bool EnumerateProxyProperties(JSContext* cx, HandleObject pobj,
                                      unsigned flags,
                                      MutableHandle<IdSet> visited,
-                                     AutoIdVector* props) {
+                                     MutableHandleIdVector props) {
   MOZ_ASSERT(pobj->is<ProxyObject>());
 
-  AutoIdVector proxyProps(cx);
+  RootedIdVector proxyProps(cx);
 
   if (flags & JSITER_HIDDEN || flags & JSITER_SYMBOLS) {
     // This gets all property keys, both strings and symbols. The call to
     // Enumerate in the loop below will filter out unwanted keys, per the
     // flags.
-    if (!Proxy::ownPropertyKeys(cx, pobj, proxyProps)) {
+    if (!Proxy::ownPropertyKeys(cx, pobj, &proxyProps)) {
       return false;
     }
 
     Rooted<PropertyDescriptor> desc(cx);
     for (size_t n = 0, len = proxyProps.length(); n < len; n++) {
       bool enumerable = false;
 
       // We need to filter, if the caller just wants enumerable symbols.
@@ -349,17 +349,17 @@ static bool EnumerateProxyProperties(JSC
         return false;
       }
     }
 
     return true;
   }
 
   // Returns enumerable property names (no symbols).
-  if (!Proxy::getOwnEnumerablePropertyKeys(cx, pobj, proxyProps)) {
+  if (!Proxy::getOwnEnumerablePropertyKeys(cx, pobj, &proxyProps)) {
     return false;
   }
 
   for (size_t n = 0, len = proxyProps.length(); n < len; n++) {
     if (!Enumerate<CheckForDuplicates>(cx, pobj, proxyProps[n], true, flags,
                                        visited, props)) {
       return false;
     }
@@ -435,17 +435,17 @@ struct SortComparatorIds {
     *lessOrEqualp = (result <= 0);
     return true;
   }
 };
 
 #endif /* JS_MORE_DETERMINISTIC */
 
 static bool Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags,
-                     AutoIdVector* props) {
+                     MutableHandleIdVector props) {
   Rooted<IdSet> visited(cx, IdSet(cx));
   RootedObject pobj(cx, pobj_);
 
   // Don't check for duplicates if we're only interested in own properties.
   // This does the right thing for most objects: native objects don't have
   // duplicate property ids and we allow the [[OwnPropertyKeys]] proxy trap to
   // return duplicates.
   //
@@ -522,33 +522,33 @@ static bool Snapshot(JSContext* cx, Hand
    * follow the order in which properties are added, in certain cases.
    * Since ECMA does not specify an enumeration order for objects, both
    * behaviors are technically correct to do.
    */
 
   jsid* ids = props->begin();
   size_t n = props->length();
 
-  AutoIdVector tmp(cx);
+  RootedIdVector tmp(cx);
   if (!tmp.resize(n)) {
     return false;
   }
   PodCopy(tmp.begin(), ids, n);
 
   if (!MergeSort(ids, n, tmp.begin(), SortComparatorIds(cx))) {
     return false;
   }
 
 #endif /* JS_MORE_DETERMINISTIC */
 
   return true;
 }
 
 JS_FRIEND_API bool js::GetPropertyKeys(JSContext* cx, HandleObject obj,
-                                       unsigned flags, AutoIdVector* props) {
+                                       unsigned flags, MutableHandleIdVector props) {
   return Snapshot(cx, obj,
                   flags & (JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS |
                            JSITER_SYMBOLSONLY),
                   props);
 }
 
 static inline void RegisterEnumerator(ObjectRealm& realm, NativeIterator* ni) {
   // Register non-escaping native enumerators (for-in) with the current
@@ -588,17 +588,17 @@ static PropertyIteratorObject* NewProper
   MOZ_ASSERT(!js::gc::IsInsideNursery(res));
 
   MOZ_ASSERT(res->numFixedSlots() == PropertyIteratorObject::NUM_FIXED_SLOTS);
   return res;
 }
 
 static PropertyIteratorObject* CreatePropertyIterator(
     JSContext* cx, Handle<JSObject*> objBeingIterated,
-    const AutoIdVector& props, uint32_t numGuards, uint32_t guardKey) {
+    HandleIdVector props, uint32_t numGuards, uint32_t guardKey) {
   Rooted<PropertyIteratorObject*> propIter(cx, NewPropertyIteratorObject(cx));
   if (!propIter) {
     return nullptr;
   }
 
   static_assert(sizeof(ReceiverGuard) == 2 * sizeof(GCPtrFlatString),
                 "NativeIterators are allocated in space for 1) themselves, "
                 "2) the properties a NativeIterator iterates (as "
@@ -662,17 +662,17 @@ NativeIterator* NativeIterator::allocate
  *
  * This definition is a bit tricky: some parts of initializing are fallible, so
  * as we initialize, we must carefully keep this in GC-safe state (see
  * NativeIterator::trace).
  */
 NativeIterator::NativeIterator(JSContext* cx,
                                Handle<PropertyIteratorObject*> propIter,
                                Handle<JSObject*> objBeingIterated,
-                               const AutoIdVector& props, uint32_t numGuards,
+                               HandleIdVector props, uint32_t numGuards,
                                uint32_t guardKey, bool* hadError)
     : objectBeingIterated_(objBeingIterated),
       iterObj_(propIter),
       // NativeIterator initially acts (before full initialization) as if it
       // contains no guards...
       guardsEnd_(guardsBegin()),
       // ...and no properties.
       propertyCursor_(
@@ -865,24 +865,24 @@ static MOZ_MUST_USE bool StoreInIterator
     ReportOutOfMemory(cx);
     return false;
   }
 
   return true;
 }
 
 bool js::EnumerateProperties(JSContext* cx, HandleObject obj,
-                             AutoIdVector& props) {
+                             MutableHandleIdVector props) {
   MOZ_ASSERT(props.empty());
 
   if (MOZ_UNLIKELY(obj->is<ProxyObject>())) {
     return Proxy::enumerate(cx, obj, props);
   }
 
-  return Snapshot(cx, obj, 0, &props);
+  return Snapshot(cx, obj, 0, props);
 }
 
 static JSObject* GetIterator(JSContext* cx, HandleObject obj) {
   MOZ_ASSERT(!obj->is<PropertyIteratorObject>());
   MOZ_ASSERT(cx->compartment() == obj->compartment(),
              "We may end up allocating shapes in the wrong zone!");
 
   uint32_t numGuards = 0;
@@ -893,18 +893,18 @@ static JSObject* GetIterator(JSContext* 
     RegisterEnumerator(ObjectRealm::get(obj), ni);
     return iterobj;
   }
 
   if (numGuards > 0 && !CanStoreInIteratorCache(obj)) {
     numGuards = 0;
   }
 
-  AutoIdVector keys(cx);
-  if (!EnumerateProperties(cx, obj, keys)) {
+  RootedIdVector keys(cx);
+  if (!EnumerateProperties(cx, obj, &keys)) {
     return nullptr;
   }
 
   if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj)) {
     return nullptr;
   }
   MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED);
 
@@ -1205,17 +1205,17 @@ JSObject* js::ValueToIterator(JSContext*
     /* Common case. */
     obj = &vp.toObject();
   } else if (vp.isNullOrUndefined()) {
     /*
      * Enumerating over null and undefined gives an empty enumerator, so
      * that |for (var p in <null or undefined>) <loop>;| never executes
      * <loop>, per ES5 12.6.4.
      */
-    AutoIdVector props(cx);  // Empty
+    RootedIdVector props(cx);  // Empty
     return CreatePropertyIterator(cx, nullptr, props, 0, 0);
   } else {
     obj = ToObject(cx, vp);
     if (!obj) {
       return nullptr;
     }
   }
 
--- a/js/src/vm/Iteration.h
+++ b/js/src/vm/Iteration.h
@@ -105,17 +105,17 @@ struct NativeIterator {
    * Initialize a NativeIterator properly allocated for |props.length()|
    * properties and |numGuards| guards.
    *
    * Despite being a constructor, THIS FUNCTION CAN REPORT ERRORS.  Users
    * MUST set |*hadError = false| on entry and consider |*hadError| on return
    * to mean this function failed.
    */
   NativeIterator(JSContext* cx, Handle<PropertyIteratorObject*> propIter,
-                 Handle<JSObject*> objBeingIterated, const AutoIdVector& props,
+                 Handle<JSObject*> objBeingIterated, HandleIdVector props,
                  uint32_t numGuards, uint32_t guardKey, bool* hadError);
 
   /** Initialize an |ObjectRealm::enumerators| sentinel. */
   NativeIterator();
 
   JSObject* objectBeingIterated() const { return objectBeingIterated_; }
 
   void changeObjectBeingIterated(JSObject& obj) { objectBeingIterated_ = &obj; }
@@ -365,17 +365,17 @@ class RegExpStringIteratorObject : publi
  public:
   static const Class class_;
 };
 
 RegExpStringIteratorObject* NewRegExpStringIteratorObject(
     JSContext* cx, NewObjectKind newKind = GenericObject);
 
 MOZ_MUST_USE bool EnumerateProperties(JSContext* cx, HandleObject obj,
-                                      AutoIdVector& props);
+                                      MutableHandleIdVector props);
 
 PropertyIteratorObject* LookupInIteratorCache(JSContext* cx, HandleObject obj);
 
 JSObject* ValueToIterator(JSContext* cx, HandleValue vp);
 
 void CloseIterator(JSObject* obj);
 
 bool IteratorCloseForException(JSContext* cx, HandleObject obj);
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -464,25 +464,25 @@ void js::CompletePropertyDescriptor(Muta
     desc.attributesRef() |= JSPROP_PERMANENT;
   }
   desc.attributesRef() &= ~(JSPROP_IGNORE_PERMANENT | JSPROP_IGNORE_ENUMERATE);
 
   desc.assertComplete();
 }
 
 bool js::ReadPropertyDescriptors(
-    JSContext* cx, HandleObject props, bool checkAccessors, AutoIdVector* ids,
-    MutableHandle<PropertyDescriptorVector> descs) {
+    JSContext* cx, HandleObject props, bool checkAccessors,
+    MutableHandleIdVector ids, MutableHandle<PropertyDescriptorVector> descs) {
   if (!GetPropertyKeys(cx, props, JSITER_OWNONLY | JSITER_SYMBOLS, ids)) {
     return false;
   }
 
   RootedId id(cx);
-  for (size_t i = 0, len = ids->length(); i < len; i++) {
-    id = (*ids)[i];
+  for (size_t i = 0, len = ids.length(); i < len; i++) {
+    id = ids[i];
     Rooted<PropertyDescriptor> desc(cx);
     RootedValue v(cx);
     if (!GetProperty(cx, props, props, id, &v) ||
         !ToPropertyDescriptor(cx, v, checkAccessors, &desc) ||
         !descs.append(desc)) {
       return false;
     }
   }
@@ -562,17 +562,17 @@ bool js::SetIntegrityLevel(JSContext* cx
     // Ordinarily ArraySetLength handles this, but we're going behind its back
     // right now, so we must do this manually.
     if (level == IntegrityLevel::Frozen && obj->is<ArrayObject>()) {
       MOZ_ASSERT(!nobj->denseElementsAreCopyOnWrite());
       obj->as<ArrayObject>().setNonWritableLength(cx);
     }
   } else {
     // Steps 6-7.
-    AutoIdVector keys(cx);
+    RootedIdVector keys(cx);
     if (!GetPropertyKeys(
             cx, obj, JSITER_HIDDEN | JSITER_OWNONLY | JSITER_SYMBOLS, &keys)) {
       return false;
     }
 
     RootedId id(cx);
     Rooted<PropertyDescriptor> desc(cx);
 
@@ -627,18 +627,18 @@ bool js::SetIntegrityLevel(JSContext* cx
 static bool ResolveLazyProperties(JSContext* cx, HandleNativeObject obj) {
   const Class* clasp = obj->getClass();
   if (JSEnumerateOp enumerate = clasp->getEnumerate()) {
     if (!enumerate(cx, obj)) {
       return false;
     }
   }
   if (clasp->getNewEnumerate() && clasp->getResolve()) {
-    AutoIdVector properties(cx);
-    if (!clasp->getNewEnumerate()(cx, obj, properties,
+    RootedIdVector properties(cx);
+    if (!clasp->getNewEnumerate()(cx, obj, &properties,
                                   /* enumerableOnly = */ false)) {
       return false;
     }
 
     RootedId id(cx);
     for (size_t i = 0; i < properties.length(); i++) {
       id = properties[i];
       bool found;
@@ -712,17 +712,17 @@ bool js::TestIntegrityLevel(JSContext* c
           (level == IntegrityLevel::Frozen && shape->isDataDescriptor() &&
            shape->writable())) {
         *result = false;
         return true;
       }
     }
   } else {
     // Steps 7-8.
-    AutoIdVector props(cx);
+    RootedIdVector props(cx);
     if (!GetPropertyKeys(
             cx, obj, JSITER_HIDDEN | JSITER_OWNONLY | JSITER_SYMBOLS, &props)) {
       return false;
     }
 
     // Step 9.
     RootedId id(cx);
     Rooted<PropertyDescriptor> desc(cx);
@@ -1292,17 +1292,17 @@ JS_FRIEND_API bool JS_CopyPropertiesFrom
                                          HandleObject obj) {
   // Both |obj| and |target| must not be CCWs because we need to enter their
   // realms below and CCWs are not associated with a single realm.
   MOZ_ASSERT(!IsCrossCompartmentWrapper(obj));
   MOZ_ASSERT(!IsCrossCompartmentWrapper(target));
 
   JSAutoRealm ar(cx, obj);
 
-  AutoIdVector props(cx);
+  RootedIdVector props(cx);
   if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
                        &props)) {
     return false;
   }
 
   for (size_t i = 0; i < props.length(); ++i) {
     if (!JS_CopyPropertyFrom(cx, props[i], target, obj)) {
       return false;
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -896,18 +896,18 @@ Result<> CheckPropertyDescriptorAccessor
 
 void CompletePropertyDescriptor(MutableHandle<JS::PropertyDescriptor> desc);
 
 /*
  * Read property descriptors from props, as for Object.defineProperties. See
  * ES5 15.2.3.7 steps 3-5.
  */
 extern bool ReadPropertyDescriptors(
-    JSContext* cx, HandleObject props, bool checkAccessors, AutoIdVector* ids,
-    MutableHandle<PropertyDescriptorVector> descs);
+    JSContext* cx, HandleObject props, bool checkAccessors,
+    MutableHandleIdVector ids, MutableHandle<PropertyDescriptorVector> descs);
 
 /* Read the name using a dynamic lookup on the scopeChain. */
 extern bool LookupName(JSContext* cx, HandlePropertyName name,
                        HandleObject scopeChain, MutableHandleObject objp,
                        MutableHandleObject pobjp,
                        MutableHandle<PropertyResult> propp);
 
 extern bool LookupNameNoGC(JSContext* cx, PropertyName* name,
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -3132,17 +3132,17 @@ static bool GetUnclonedValue(JSContext* 
   MOZ_ASSERT(shape);
   MOZ_ASSERT(shape->isDataProperty());
   vp.set(selfHostedObject->getSlot(shape->slot()));
   return true;
 }
 
 static bool CloneProperties(JSContext* cx, HandleNativeObject selfHostedObject,
                             HandleObject clone) {
-  AutoIdVector ids(cx);
+  RootedIdVector ids(cx);
   Vector<uint8_t, 16> attrs(cx);
 
   for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) {
     if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
       if (!ids.append(INT_TO_JSID(i))) {
         return false;
       }
       if (!attrs.append(JSPROP_ENUMERATE)) {
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -860,17 +860,17 @@ Shape* NativeObject::addEnumerableDataPr
 }
 
 Shape* js::ReshapeForAllocKind(JSContext* cx, Shape* shape, TaggedProto proto,
                                gc::AllocKind allocKind) {
   // Compute the number of fixed slots with the new allocation kind.
   size_t nfixed = gc::GetGCKindSlots(allocKind, shape->getObjectClass());
 
   // Get all the ids in the shape, in order.
-  js::AutoIdVector ids(cx);
+  js::RootedIdVector ids(cx);
   {
     for (unsigned i = 0; i < shape->slotSpan(); i++) {
       if (!ids.append(JSID_VOID)) {
         return nullptr;
       }
     }
     Shape* nshape = shape;
     while (!nshape->isEmptyShape()) {
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -527,17 +527,17 @@ struct JSStructuredCloneWriter {
   // entered before any manipulation is performed.
   RootedValueVector objs;
 
   // counts[i] is the number of entries of objs[i] remaining to be written.
   // counts.length() == objs.length() and sum(counts) == entries.length().
   Vector<size_t> counts;
 
   // For JSObject: Property IDs as value
-  AutoIdVector objectEntries;
+  RootedIdVector objectEntries;
 
   // For Map: Key followed by value
   // For Set: Key
   // For SavedFrame: parent SavedFrame
   RootedValueVector otherEntries;
 
   // The "memory" list described in the HTML5 internal structured cloning
   // algorithm.  memory is a superset of objs; items are never removed from
@@ -1324,17 +1324,17 @@ bool JSStructuredCloneWriter::startObjec
                               JSMSG_NEED_DIET, "object graph to serialize");
     return false;
   }
 
   return true;
 }
 
 static bool TryAppendNativeProperties(JSContext* cx, HandleObject obj,
-                                      AutoIdVector& entries, size_t* properties,
+                                      MutableHandleIdVector entries, size_t* properties,
                                       bool* optimized) {
   *optimized = false;
 
   if (!obj->isNative()) {
     return true;
   }
 
   HandleNativeObject nobj = obj.as<NativeObject>();
@@ -1380,25 +1380,25 @@ static bool TryAppendNativeProperties(JS
 
   *properties = count;
   return true;
 }
 
 bool JSStructuredCloneWriter::traverseObject(HandleObject obj, ESClass cls) {
   size_t count;
   bool optimized = false;
-  if (!TryAppendNativeProperties(context(), obj, objectEntries, &count,
+  if (!TryAppendNativeProperties(context(), obj, &objectEntries, &count,
                                  &optimized)) {
     return false;
   }
 
   if (!optimized) {
     // Get enumerable property ids and put them in reverse order so that they
     // will come off the stack in forward order.
-    AutoIdVector properties(context());
+    RootedIdVector properties(context());
     if (!GetPropertyKeys(context(), obj, JSITER_OWNONLY, &properties)) {
       return false;
     }
 
     for (size_t i = properties.length(); i > 0; --i) {
       jsid id = properties[i - 1];
 
       MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id));
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -1170,17 +1170,17 @@ static bool CreateExportObject(JSContext
 
   instanceObj->initExportsObj(*exportObj);
   return true;
 }
 
 #ifdef ENABLE_WASM_GC
 static bool MakeStructField(JSContext* cx, const ValType& v, bool isMutable,
                             const char* format, uint32_t fieldNo,
-                            AutoIdVector* ids,
+                            MutableHandleIdVector ids,
                             MutableHandleValueVector fieldTypeObjs,
                             Vector<StructFieldProps>* fieldProps) {
   char buf[20];
   sprintf(buf, format, fieldNo);
 
   JSAtom* atom = Atomize(cx, buf, strlen(buf));
   if (!atom) {
     return false;
@@ -1220,17 +1220,17 @@ static bool MakeStructField(JSContext* c
       t = GlobalObject::getOrCreateReferenceTypeDescr(
           cx, cx->global(), ReferenceType::TYPE_WASM_ANYREF);
       break;
     default:
       MOZ_CRASH("Bad field type");
   }
   MOZ_ASSERT(t != nullptr);
 
-  if (!ids->append(id)) {
+  if (!ids.append(id)) {
     return false;
   }
 
   if (!fieldTypeObjs.append(ObjectValue(*t))) {
     return false;
   }
 
   if (!fieldProps->append(props)) {
@@ -1267,17 +1267,17 @@ bool Module::makeStructTypeDescrs(
 
   RootedNativeObject toModule(cx, &typedObjectModule->as<NativeObject>());
   RootedObject prototype(
       cx,
       &toModule->getReservedSlot(TypedObjectModuleObject::StructTypePrototype)
            .toObject());
 
   for (const StructType& structType : structTypes()) {
-    AutoIdVector ids(cx);
+    RootedIdVector ids(cx);
     RootedValueVector fieldTypeObjs(cx);
     Vector<StructFieldProps> fieldProps(cx);
     bool allowConstruct = true;
 
     uint32_t k = 0;
     for (StructField sf : structType.fields_) {
       const ValType& v = sf.type;
       if (v.code() == ValType::I64) {
--- a/js/xpconnect/idl/nsIXPCScriptable.idl
+++ b/js/xpconnect/idl/nsIXPCScriptable.idl
@@ -22,19 +22,19 @@ struct Class;
 
 interface nsIXPConnectWrappedNative;
 
 [ptr] native JSContextPtr(JSContext);
 [ptr] native JSObjectPtr(JSObject);
 [ptr] native JSValPtr(JS::Value);
 [ptr] native JSFreeOpPtr(JSFreeOp);
 [ref] native JSCallArgsRef(const JS::CallArgs);
-[ref] native JSAutoIdVector(JS::AutoIdVector);
 [ptr] native jsClassPtr(const js::Class);
 [ptr] native JSClassPtr(const JSClass);
+      native JSMutableHandleIdVector(JS::MutableHandleIdVector);
 
 %{ C++
     // nsIXPCScriptable flags (only 32 bits available!). They are defined via
     // #defines so they can be used in #ifndef guards in xpc_map_end.h.
 
     #define XPC_SCRIPTABLE_WANT_PRECREATE                   (1 <<  0)
     // (1 << 1) is unused
     // (1 << 2) is unused
@@ -74,17 +74,17 @@ interface nsIXPCScriptable : nsISupports
     void   preCreate(in nsISupports nativeObj, in JSContextPtr cx,
                      in JSObjectPtr globalObj, out JSObjectPtr parentObj);
 
     boolean enumerate(in nsIXPConnectWrappedNative wrapper,
                      in JSContextPtr cx, in JSObjectPtr obj);
 
     boolean newEnumerate(in nsIXPConnectWrappedNative wrapper,
                         in JSContextPtr cx, in JSObjectPtr obj,
-                        in JSAutoIdVector properties,
+                        in JSMutableHandleIdVector properties,
                         in boolean enumerableOnly);
 
     boolean resolve(in nsIXPConnectWrappedNative wrapper,
                     in JSContextPtr cx, in JSObjectPtr obj, in jsid id,
                     out boolean resolvedp);
 
     void   finalize(in nsIXPConnectWrappedNative wrapper,
                     in JSFreeOpPtr fop, in JSObjectPtr obj);
--- a/js/xpconnect/public/xpc_make_class.h
+++ b/js/xpconnect/public/xpc_make_class.h
@@ -25,17 +25,17 @@ bool XPC_WN_MaybeResolvingDeleteProperty
 bool XPC_WN_CannotDeletePropertyStub(JSContext* cx, JS::HandleObject obj,
                                      JS::HandleId id,
                                      JS::ObjectOpResult& result);
 
 bool XPC_WN_Helper_Enumerate(JSContext* cx, JS::HandleObject obj);
 bool XPC_WN_Shared_Enumerate(JSContext* cx, JS::HandleObject obj);
 
 bool XPC_WN_NewEnumerate(JSContext* cx, JS::HandleObject obj,
-                         JS::AutoIdVector& properties, bool enumerableOnly);
+                         JS::MutableHandleIdVector properties, bool enumerableOnly);
 
 bool XPC_WN_Helper_Resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
                            bool* resolvedp);
 
 void XPC_WN_Helper_Finalize(js::FreeOp* fop, JSObject* obj);
 void XPC_WN_NoHelper_Finalize(js::FreeOp* fop, JSObject* obj);
 
 bool XPC_WN_Helper_Call(JSContext* cx, unsigned argc, JS::Value* vp);
--- a/js/xpconnect/public/xpc_map_end.h
+++ b/js/xpconnect/public/xpc_map_end.h
@@ -53,17 +53,17 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::PreCrea
   NS_ERROR("never called");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 #endif
 
 #if !((XPC_MAP_FLAGS)&XPC_SCRIPTABLE_WANT_NEWENUMERATE)
 NS_IMETHODIMP XPC_MAP_CLASSNAME::NewEnumerate(
     nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj,
-    JS::AutoIdVector& properties, bool enumerableOnly, bool* _retval) {
+    JS::MutableHandleIdVector properties, bool enumerableOnly, bool* _retval) {
   NS_ERROR("never called");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 #endif
 
 #if !((XPC_MAP_FLAGS)&XPC_SCRIPTABLE_WANT_ENUMERATE)
 NS_IMETHODIMP XPC_MAP_CLASSNAME::Enumerate(nsIXPConnectWrappedNative* wrapper,
                                            JSContext* cx, JSObject* obj,
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -512,19 +512,19 @@ class SandboxProxyHandler : public js::W
                    JS::Handle<jsid> id, JS::Handle<JS::Value> v,
                    JS::Handle<JS::Value> receiver,
                    JS::ObjectOpResult& result) const override;
 
   virtual bool hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy,
                       JS::Handle<jsid> id, bool* bp) const override;
   virtual bool getOwnEnumerablePropertyKeys(
       JSContext* cx, JS::Handle<JSObject*> proxy,
-      JS::AutoIdVector& props) const override;
+      JS::MutableHandleIdVector props) const override;
   virtual bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
-                         JS::AutoIdVector& props) const override;
+                         JS::MutableHandleIdVector props) const override;
 
  private:
   // Implements the custom getPropertyDescriptor behavior. If the getOwn
   // argument is true we only look for "own" properties.
   bool getPropertyDescriptorImpl(
       JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
       bool getOwn, JS::MutableHandle<JS::PropertyDescriptor> desc) const;
 };
@@ -790,22 +790,22 @@ bool SandboxProxyHandler::get(JSContext*
 bool SandboxProxyHandler::set(JSContext* cx, JS::Handle<JSObject*> proxy,
                               JS::Handle<jsid> id, JS::Handle<Value> v,
                               JS::Handle<Value> receiver,
                               JS::ObjectOpResult& result) const {
   return BaseProxyHandler::set(cx, proxy, id, v, receiver, result);
 }
 
 bool SandboxProxyHandler::getOwnEnumerablePropertyKeys(
-    JSContext* cx, JS::Handle<JSObject*> proxy, AutoIdVector& props) const {
+    JSContext* cx, JS::Handle<JSObject*> proxy, MutableHandleIdVector props) const {
   return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
 }
 
 bool SandboxProxyHandler::enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
-                                    JS::AutoIdVector& props) const {
+                                    JS::MutableHandleIdVector props) const {
   return BaseProxyHandler::enumerate(cx, proxy, props);
 }
 
 bool xpc::GlobalProperties::Parse(JSContext* cx, JS::HandleObject obj) {
   uint32_t length;
   bool ok = JS_GetArrayLength(cx, obj, &length);
   NS_ENSURE_TRUE(ok, false);
   for (uint32_t i = 0; i < length; i++) {
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -174,17 +174,17 @@ NS_IMPL_ISUPPORTS(nsXPCComponents_Interf
 #define XPC_MAP_FLAGS                                               \
   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
 #include "xpc_map_end.h" /* This will #undef the above */
 
 NS_IMETHODIMP
 nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
                                          JSContext* cx, JSObject* obj,
-                                         JS::AutoIdVector& properties,
+                                         JS::MutableHandleIdVector properties,
                                          bool enumerableOnly, bool* _retval) {
   if (!properties.reserve(nsXPTInterfaceInfo::InterfaceCount())) {
     *_retval = false;
     return NS_OK;
   }
 
   for (uint32_t index = 0; index < nsXPTInterfaceInfo::InterfaceCount();
        index++) {
@@ -327,17 +327,17 @@ NS_IMPL_ISUPPORTS(nsXPCComponents_Classe
 #define XPC_MAP_FLAGS                                               \
   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
 #include "xpc_map_end.h" /* This will #undef the above */
 
 NS_IMETHODIMP
 nsXPCComponents_Classes::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
                                       JSContext* cx, JSObject* obj,
-                                      JS::AutoIdVector& properties,
+                                      JS::MutableHandleIdVector properties,
                                       bool enumerableOnly, bool* _retval) {
   nsCOMPtr<nsIComponentRegistrar> compMgr;
   if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) ||
       !compMgr) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsCOMPtr<nsISimpleEnumerator> e;
@@ -480,17 +480,17 @@ NS_IMPL_ISUPPORTS(nsXPCComponents_Result
 #define XPC_MAP_FLAGS                                               \
   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
 #include "xpc_map_end.h" /* This will #undef the above */
 
 NS_IMETHODIMP
 nsXPCComponents_Results::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
                                       JSContext* cx, JSObject* obj,
-                                      JS::AutoIdVector& properties,
+                                      JS::MutableHandleIdVector properties,
                                       bool enumerableOnly, bool* _retval) {
   const char* name;
   const void* iter = nullptr;
   while (nsXPCException::IterateNSResults(nullptr, &name, nullptr, &iter)) {
     RootedString idstr(cx, JS_NewStringCopyZ(cx, name));
     if (!idstr) {
       *_retval = false;
       return NS_OK;
--- a/js/xpconnect/src/XPCRuntimeService.cpp
+++ b/js/xpconnect/src/XPCRuntimeService.cpp
@@ -56,17 +56,17 @@ BackstagePass::Resolve(nsIXPConnectWrapp
   JS::RootedId id(cx, idArg);
   *_retval =
       WebIDLGlobalNameHash::ResolveForSystemGlobal(cx, obj, id, resolvedp);
   return *_retval ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 BackstagePass::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
-                            JSObject* objArg, JS::AutoIdVector& properties,
+                            JSObject* objArg, JS::MutableHandleIdVector properties,
                             bool enumerableOnly, bool* _retval) {
   JS::RootedObject obj(cx, objArg);
   *_retval = WebIDLGlobalNameHash::NewEnumerateSystemGlobal(cx, obj, properties,
                                                             enumerableOnly);
   return *_retval ? NS_OK : NS_ERROR_FAILURE;
 }
 
 /***************************************************************************/
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -845,17 +845,17 @@ bool XPC_WN_Helper_Enumerate(JSContext* 
     return Throw(rv, cx);
   }
   return retval;
 }
 
 /***************************************************************************/
 
 bool XPC_WN_NewEnumerate(JSContext* cx, HandleObject obj,
-                         AutoIdVector& properties, bool enumerableOnly) {
+                         MutableHandleIdVector properties, bool enumerableOnly) {
   XPCCallContext ccx(cx, obj);
   XPCWrappedNative* wrapper = ccx.GetWrapper();
   THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
   nsCOMPtr<nsIXPCScriptable> scr = wrapper->GetScriptable();
   if (!scr || !scr->WantNewEnumerate()) {
     return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
   }
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -742,17 +742,17 @@ void NukeJSStackFrames(JS::Realm* aRealm
 // Check whether the given jsid is a property name (string or symbol) whose
 // value can be gotten cross-origin.  Cross-origin gets always return undefined
 // as the value, unless the Xray actually provides a different value.
 bool IsCrossOriginWhitelistedProp(JSContext* cx, JS::HandleId id);
 
 // Appends to props the jsids for property names (strings or symbols) whose
 // value can be gotten cross-origin.
 bool AppendCrossOriginWhitelistedPropNames(JSContext* cx,
-                                           JS::AutoIdVector& props);
+                                           JS::MutableHandleIdVector props);
 }  // namespace xpc
 
 namespace mozilla {
 namespace dom {
 
 /**
  * A test for whether WebIDL methods that should only be visible to
  * chrome or XBL scopes should be exposed.
--- a/js/xpconnect/wrappers/FilteringWrapper.cpp
+++ b/js/xpconnect/wrappers/FilteringWrapper.cpp
@@ -40,19 +40,19 @@ static bool IsCrossOriginWhitelistedSymb
 }
 
 bool IsCrossOriginWhitelistedProp(JSContext* cx, JS::HandleId id) {
   return id == GetJSIDByIndex(cx, XPCJSContext::IDX_THEN) ||
          IsCrossOriginWhitelistedSymbol(cx, id);
 }
 
 bool AppendCrossOriginWhitelistedPropNames(JSContext* cx,
-                                           JS::AutoIdVector& props) {
+                                           JS::MutableHandleIdVector props) {
   // Add "then" if it's not already in the list.
-  AutoIdVector thenProp(cx);
+  RootedIdVector thenProp(cx);
   if (!thenProp.append(GetJSIDByIndex(cx, XPCJSContext::IDX_THEN))) {
     return false;
   }
 
   if (!AppendUnique(cx, props, thenProp)) {
     return false;
   }
 
@@ -71,17 +71,17 @@ bool AppendCrossOriginWhitelistedPropNam
   for (auto code : sCrossOriginWhitelistedSymbolCodes) {
     props.infallibleAppend(SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, code)));
   }
 
   return true;
 }
 
 template <typename Policy>
-static bool Filter(JSContext* cx, HandleObject wrapper, AutoIdVector& props) {
+static bool Filter(JSContext* cx, HandleObject wrapper, MutableHandleIdVector props) {
   size_t w = 0;
   RootedId id(cx);
   for (size_t n = 0; n < props.length(); ++n) {
     id = props[n];
     if (Policy::check(cx, wrapper, id, Wrapper::GET) ||
         Policy::check(cx, wrapper, id, Wrapper::SET)) {
       props[w++].set(id);
     } else if (JS_IsExceptionPending(cx)) {
@@ -142,34 +142,34 @@ bool FilteringWrapper<Base, Policy>::get
   if (!Base::getOwnPropertyDescriptor(cx, wrapper, id, desc)) {
     return false;
   }
   return FilterPropertyDescriptor<Policy>(cx, wrapper, id, desc);
 }
 
 template <typename Base, typename Policy>
 bool FilteringWrapper<Base, Policy>::ownPropertyKeys(
-    JSContext* cx, HandleObject wrapper, AutoIdVector& props) const {
+    JSContext* cx, HandleObject wrapper, MutableHandleIdVector props) const {
   assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
   return Base::ownPropertyKeys(cx, wrapper, props) &&
          Filter<Policy>(cx, wrapper, props);
 }
 
 template <typename Base, typename Policy>
 bool FilteringWrapper<Base, Policy>::getOwnEnumerablePropertyKeys(
-    JSContext* cx, HandleObject wrapper, AutoIdVector& props) const {
+    JSContext* cx, HandleObject wrapper, MutableHandleIdVector props) const {
   assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
   return Base::getOwnEnumerablePropertyKeys(cx, wrapper, props) &&
          Filter<Policy>(cx, wrapper, props);
 }
 
 template <typename Base, typename Policy>
 bool FilteringWrapper<Base, Policy>::enumerate(JSContext* cx,
                                                HandleObject wrapper,
-                                               JS::AutoIdVector& props) const {
+                                               JS::MutableHandleIdVector props) const {
   assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
   // Trigger the default proxy enumerate trap, which will use
   // js::GetPropertyKeys for the list of (censored) ids.
   return js::BaseProxyHandler::enumerate(cx, wrapper, props);
 }
 
 template <typename Base, typename Policy>
 bool FilteringWrapper<Base, Policy>::call(JSContext* cx,
--- a/js/xpconnect/wrappers/FilteringWrapper.h
+++ b/js/xpconnect/wrappers/FilteringWrapper.h
@@ -22,23 +22,23 @@ class FilteringWrapper : public Base {
   virtual bool enter(JSContext* cx, JS::Handle<JSObject*> wrapper,
                      JS::Handle<jsid> id, js::Wrapper::Action act,
                      bool mayThrow, bool* bp) const override;
 
   virtual bool getOwnPropertyDescriptor(
       JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
       JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
   virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                               JS::AutoIdVector& props) const override;
+                               JS::MutableHandleIdVector props) const override;
 
   virtual bool getOwnEnumerablePropertyKeys(
       JSContext* cx, JS::Handle<JSObject*> wrapper,
-      JS::AutoIdVector& props) const override;
+      JS::MutableHandleIdVector props) const override;
   virtual bool enumerate(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                         JS::AutoIdVector& props) const override;
+                         JS::MutableHandleIdVector props) const override;
 
   virtual bool call(JSContext* cx, JS::Handle<JSObject*> wrapper,
                     const JS::CallArgs& args) const override;
   virtual bool construct(JSContext* cx, JS::Handle<JSObject*> wrapper,
                          const JS::CallArgs& args) const override;
 
   virtual bool nativeCall(JSContext* cx, JS::IsAcceptableThis test,
                           JS::NativeImpl impl,
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -825,30 +825,30 @@ bool JSXrayTraits::defineProperty(JSCont
     }
     *defined = true;
     return true;
   }
 
   return true;
 }
 
-static bool MaybeAppend(jsid id, unsigned flags, AutoIdVector& props) {
+static bool MaybeAppend(jsid id, unsigned flags, MutableHandleIdVector props) {
   MOZ_ASSERT(!(flags & JSITER_SYMBOLSONLY));
   if (!(flags & JSITER_SYMBOLS) && JSID_IS_SYMBOL(id)) {
     return true;
   }
   return props.append(id);
 }
 
 // Append the names from the given function and property specs to props.
 static bool AppendNamesFromFunctionAndPropertySpecs(JSContext* cx,
                                                     const JSFunctionSpec* fs,
                                                     const JSPropertySpec* ps,
                                                     unsigned flags,
-                                                    AutoIdVector& props) {
+                                                    MutableHandleIdVector props) {
   // Convert the method and property names to jsids and pass them to the caller.
   for (; fs && fs->name; ++fs) {
     jsid id;
     if (!PropertySpecNameToPermanentId(cx, fs->name, &id)) {
       return false;
     }
     if (!MaybeAppend(id, flags, props)) {
       return false;
@@ -863,17 +863,17 @@ static bool AppendNamesFromFunctionAndPr
       return false;
     }
   }
 
   return true;
 }
 
 bool JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper,
-                                  unsigned flags, AutoIdVector& props) {
+                                  unsigned flags, MutableHandleIdVector props) {
   MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
 
   RootedObject target(cx, getTargetObject(wrapper));
   RootedObject holder(cx, ensureHolder(cx, wrapper));
   if (!holder) {
     return false;
   }
 
@@ -881,17 +881,17 @@ bool JSXrayTraits::enumerateNames(JSCont
   if (!isPrototype(holder)) {
     // For Object and Array instances, we expose some properties from the
     // underlying object, but only after filtering them carefully.
     if (key == JSProto_Object || key == JSProto_Array) {
       MOZ_ASSERT(props.empty());
       RootedObject wrapperGlobal(cx, JS::CurrentGlobalOrNull(cx));
       {
         JSAutoRealm ar(cx, target);
-        AutoIdVector targetProps(cx);
+        RootedIdVector targetProps(cx);
         if (!js::GetPropertyKeys(cx, target, flags | JSITER_OWNONLY,
                                  &targetProps)) {
           return false;
         }
         // Loop over the properties, and only pass along the ones that
         // we determine to be safe.
         if (!props.reserve(targetProps.length())) {
           return false;
@@ -1701,17 +1701,17 @@ bool DOMXrayTraits::defineProperty(JSCon
     }
   }
 
   JS::Rooted<JSObject*> obj(cx, getTargetObject(wrapper));
   return XrayDefineProperty(cx, wrapper, obj, id, desc, result, defined);
 }
 
 bool DOMXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper,
-                                   unsigned flags, AutoIdVector& props) {
+                                   unsigned flags, MutableHandleIdVector props) {
   // Put the indexed properties for a window first.
   nsGlobalWindowInner* win = AsWindow(cx, wrapper);
   if (win) {
     uint32_t length = win->Length();
     if (!props.reserve(props.length() + length)) {
       return false;
     }
     JS::RootedId indexId(cx);
@@ -2022,17 +2022,17 @@ bool XrayWrapper<Base, Traits>::definePr
   }
 
   return JS_DefinePropertyById(cx, expandoObject, id, wrappedDesc, result);
 }
 
 template <typename Base, typename Traits>
 bool XrayWrapper<Base, Traits>::ownPropertyKeys(JSContext* cx,
                                                 HandleObject wrapper,
-                                                AutoIdVector& props) const {
+                                                MutableHandleIdVector props) const {
   assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
   return getPropertyKeys(
       cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
 }
 
 template <typename Base, typename Traits>
 bool XrayWrapper<Base, Traits>::delete_(JSContext* cx, HandleObject wrapper,
                                         HandleId id,
@@ -2116,24 +2116,24 @@ template <typename Base, typename Traits
 bool XrayWrapper<Base, Traits>::hasOwn(JSContext* cx, HandleObject wrapper,
                                        HandleId id, bool* bp) const {
   // Skip our Base if it isn't already ProxyHandler.
   return js::BaseProxyHandler::hasOwn(cx, wrapper, id, bp);
 }
 
 template <typename Base, typename Traits>
 bool XrayWrapper<Base, Traits>::getOwnEnumerablePropertyKeys(
-    JSContext* cx, HandleObject wrapper, AutoIdVector& props) const {
+    JSContext* cx, HandleObject wrapper, MutableHandleIdVector props) const {
   // Skip our Base if it isn't already ProxyHandler.
   return js::BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, wrapper, props);
 }
 
 template <typename Base, typename Traits>
 bool XrayWrapper<Base, Traits>::enumerate(JSContext* cx, HandleObject wrapper,
-                                          JS::AutoIdVector& props) const {
+                                          JS::MutableHandleIdVector props) const {
   MOZ_CRASH("Shouldn't be called: we return true for hasPrototype()");
 }
 
 template <typename Base, typename Traits>
 bool XrayWrapper<Base, Traits>::call(JSContext* cx, HandleObject wrapper,
                                      const JS::CallArgs& args) const {
   assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::CALL);
   // Hard cast the singleton since SecurityWrapper doesn't have one.
@@ -2283,30 +2283,30 @@ bool XrayWrapper<Base, Traits>::setImmut
   *succeeded = false;
   return true;
 }
 
 template <typename Base, typename Traits>
 bool XrayWrapper<Base, Traits>::getPropertyKeys(JSContext* cx,
                                                 HandleObject wrapper,
                                                 unsigned flags,
-                                                AutoIdVector& props) const {
+                                                MutableHandleIdVector props) const {
   assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
 
   // Enumerate expando properties first. Note that the expando object lives
   // in the target compartment.
   RootedObject target(cx, Traits::getTargetObject(wrapper));
   RootedObject expando(cx);
   if (!Traits::singleton.getExpandoObject(cx, target, wrapper, &expando)) {
     return false;
   }
 
   if (expando) {
     JSAutoRealm ar(cx, expando);
-    if (!js::GetPropertyKeys(cx, expando, flags, &props)) {
+    if (!js::GetPropertyKeys(cx, expando, flags, props)) {
       return false;
     }
   }
   for (size_t i = 0; i < props.length(); ++i) {
     JS_MarkCrossZoneId(cx, props[i]);
   }
 
   return Traits::singleton.enumerateNames(cx, wrapper, flags, props);
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -158,17 +158,17 @@ class DOMXrayTraits : public XrayTraits 
   bool delete_(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id,
                JS::ObjectOpResult& result);
 
   bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id,
                       JS::Handle<JS::PropertyDescriptor> desc,
                       JS::Handle<JS::PropertyDescriptor> existingDesc,
                       JS::ObjectOpResult& result, bool* defined);
   virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper,
-                              unsigned flags, JS::AutoIdVector& props);
+                              unsigned flags, JS::MutableHandleIdVector props);
   static bool call(JSContext* cx, JS::HandleObject wrapper,
                    const JS::CallArgs& args, const js::Wrapper& baseInstance);
   static bool construct(JSContext* cx, JS::HandleObject wrapper,
                         const JS::CallArgs& args,
                         const js::Wrapper& baseInstance);
 
   static bool getPrototype(JSContext* cx, JS::HandleObject wrapper,
                            JS::HandleObject target,
@@ -198,17 +198,17 @@ class JSXrayTraits : public XrayTraits {
                JS::ObjectOpResult& result);
 
   bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id,
                       JS::Handle<JS::PropertyDescriptor> desc,
                       JS::Handle<JS::PropertyDescriptor> existingDesc,
                       JS::ObjectOpResult& result, bool* defined);
 
   virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper,
-                              unsigned flags, JS::AutoIdVector& props);
+                              unsigned flags, JS::MutableHandleIdVector props);
 
   static bool call(JSContext* cx, JS::HandleObject wrapper,
                    const JS::CallArgs& args, const js::Wrapper& baseInstance) {
     JSXrayTraits& self = JSXrayTraits::singleton;
     JS::RootedObject holder(cx, self.ensureHolder(cx, wrapper));
     if (xpc::JSXrayTraits::getProtoKey(holder) == JSProto_Function) {
       return baseInstance.call(cx, wrapper, args);
     }
@@ -305,17 +305,17 @@ class OpaqueXrayTraits : public XrayTrai
                       JS::Handle<JS::PropertyDescriptor> desc,
                       JS::Handle<JS::PropertyDescriptor> existingDesc,
                       JS::ObjectOpResult& result, bool* defined) {
     *defined = false;
     return true;
   }
 
   virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper,
-                              unsigned flags, JS::AutoIdVector& props) {
+                              unsigned flags, JS::MutableHandleIdVector props) {
     return true;
   }
 
   static bool call(JSContext* cx, JS::HandleObject wrapper,
                    const JS::CallArgs& args, const js::Wrapper& baseInstance) {
     JS::RootedValue v(cx, JS::ObjectValue(*wrapper));
     js::ReportIsNotFunction(cx, v);
     return false;
@@ -381,22 +381,22 @@ class XrayWrapper : public Base {
   virtual bool getOwnPropertyDescriptor(
       JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
       JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
   virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                               JS::Handle<jsid> id,
                               JS::Handle<JS::PropertyDescriptor> desc,
                               JS::ObjectOpResult& result) const override;
   virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                               JS::AutoIdVector& props) const override;
+                               JS::MutableHandleIdVector props) const override;
   virtual bool delete_(JSContext* cx, JS::Handle<JSObject*> wrapper,
                        JS::Handle<jsid> id,
                        JS::ObjectOpResult& result) const override;
   virtual bool enumerate(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                         JS::AutoIdVector& props) const override;
+                         JS::MutableHandleIdVector props) const override;
   virtual bool getPrototype(JSContext* cx, JS::HandleObject wrapper,
                             JS::MutableHandleObject protop) const override;
   virtual bool setPrototype(JSContext* cx, JS::HandleObject wrapper,
                             JS::HandleObject proto,
                             JS::ObjectOpResult& result) const override;
   virtual bool getPrototypeIfOrdinary(
       JSContext* cx, JS::HandleObject wrapper, bool* isOrdinary,
       JS::MutableHandleObject protop) const override;
@@ -420,30 +420,30 @@ class XrayWrapper : public Base {
   virtual bool construct(JSContext* cx, JS::Handle<JSObject*> wrapper,
                          const JS::CallArgs& args) const override;
 
   /* SpiderMonkey extensions. */
   virtual bool hasOwn(JSContext* cx, JS::Handle<JSObject*> wrapper,
                       JS::Handle<jsid> id, bool* bp) const override;
   virtual bool getOwnEnumerablePropertyKeys(
       JSContext* cx, JS::Handle<JSObject*> wrapper,
-      JS::AutoIdVector& props) const override;
+      JS::MutableHandleIdVector props) const override;
 
   virtual bool getBuiltinClass(JSContext* cx, JS::HandleObject wapper,
                                js::ESClass* cls) const override;
   virtual bool hasInstance(JSContext* cx, JS::HandleObject wrapper,
                            JS::MutableHandleValue v, bool* bp) const override;
   virtual const char* className(JSContext* cx,
                                 JS::HandleObject proxy) const override;
 
   static const XrayWrapper singleton;
 
  protected:
   bool getPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                       unsigned flags, JS::AutoIdVector& props) const;
+                       unsigned flags, JS::MutableHandleIdVector props) const;
 };
 
 #define PermissiveXrayDOM \
   xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::DOMXrayTraits>
 #define PermissiveXrayJS \
   xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::JSXrayTraits>
 #define PermissiveXrayOpaque \
   xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::OpaqueXrayTraits>