Merge m-c to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 26 Nov 2016 17:54:22 -0800
changeset 324360 2a0abcff5cfce087c12f3e4820b5e8b773cffaca
parent 324344 3d81e7906de637040bb850628487fd8aa921569c (current diff)
parent 324359 873a10f77413394e7e4c2374ffb966e96b533ca6 (diff)
child 324361 7bd85d3ea743e64c8fb00079808b234c2367c728
child 324368 d65261aaa7cd0084288f1135389dfb83f9ba5058
child 324399 39e0069c673e177f9998f4b0646712242b5699cc
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersmerge
milestone53.0a1
Merge m-c to m-c, a=merge
--- a/build/unix/mozconfig.linux32
+++ b/build/unix/mozconfig.linux32
@@ -1,12 +1,16 @@
 . "$topsrcdir/build/unix/mozconfig.linux"
 
 export PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/share/pkgconfig
 
+export MOZ_LINUX_32_SSE2_STARTUP_ERROR=1
+
+CFLAGS="$CFLAGS -msse -msse2 -mfpmath=sse"
+CXXFLAGS="$CXXFLAGS -msse -msse2 -mfpmath=sse"
+
 if test `uname -m` = "x86_64"; then
-  # -march=pentiumpro is what our 32-bit native toolchain defaults to
-  CC="$CC -m32 -march=pentiumpro"
-  CXX="$CXX -m32 -march=pentiumpro"
+  CC="$CC -m32 -march=pentium-m"
+  CXX="$CXX -m32 -march=pentium-m"
   ac_add_options --target=i686-pc-linux
   ac_add_options --host=i686-pc-linux
   ac_add_options --x-libraries=/usr/lib
 fi
--- a/devtools/server/actors/object.js
+++ b/devtools/server/actors/object.js
@@ -1153,21 +1153,16 @@ DebuggerServer.ObjectActorPreviewers = {
         };
       }
     }
 
     return true;
   }],
 
   RegExp: [function ({obj, hooks}, grip) {
-    // Avoid having any special preview for the RegExp.prototype itself.
-    if (!obj.proto || obj.proto.class != "RegExp") {
-      return false;
-    }
-
     let str = RegExp.prototype.toString.call(obj.unsafeDereference());
     grip.displayString = hooks.createValueGrip(str);
     return true;
   }],
 
   Date: [function ({obj, hooks}, grip) {
     let time = Date.prototype.getTime.call(obj.unsafeDereference());
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -5749,18 +5749,16 @@ nsDocShell::Create()
 }
 
 NS_IMETHODIMP
 nsDocShell::Destroy()
 {
   NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
                "Unexpected item type in docshell");
 
-  AssertOriginAttributesMatchPrivateBrowsing();
-
   if (!mIsBeingDestroyed) {
     nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
     if (serv) {
       const char* msg = mItemType == typeContent ?
         NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
       serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
     }
   }
@@ -9508,18 +9506,16 @@ public:
                         nsIURI* aNewURI,
                         nsIPrincipal* aLoadingPrincipal,
                         bool aInPrivateBrowsing)
     : mSvc(aSvc)
     , mNewURI(aNewURI)
     , mLoadingPrincipal(aLoadingPrincipal)
     , mInPrivateBrowsing(aInPrivateBrowsing)
   {
-    MOZ_DIAGNOSTIC_ASSERT(
-      (BasePrincipal::Cast(aLoadingPrincipal)->OriginAttributesRef().mPrivateBrowsingId > 0) == aInPrivateBrowsing);
   }
 
   NS_IMETHOD
   OnComplete(nsIURI* aFaviconURI, uint32_t aDataLen,
              const uint8_t* aData, const nsACString& aMimeType) override
   {
     // Continue only if there is an associated favicon.
     if (!aFaviconURI) {
@@ -9552,19 +9548,16 @@ NS_IMPL_ISUPPORTS(nsCopyFaviconCallback,
 } // namespace
 
 void
 nsDocShell::CopyFavicon(nsIURI* aOldURI,
                         nsIURI* aNewURI,
                         nsIPrincipal* aLoadingPrincipal,
                         bool aInPrivateBrowsing)
 {
-  MOZ_DIAGNOSTIC_ASSERT(
-    (BasePrincipal::Cast(aLoadingPrincipal)->OriginAttributesRef().mPrivateBrowsingId > 0) == aInPrivateBrowsing);
-
   if (XRE_IsContentProcess()) {
     dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
     if (contentChild) {
       mozilla::ipc::URIParams oldURI, newURI;
       SerializeURI(aOldURI, oldURI);
       SerializeURI(aNewURI, newURI);
       contentChild->SendCopyFavicon(oldURI, newURI,
                                     IPC::Principal(aLoadingPrincipal),
@@ -14363,17 +14356,16 @@ nsDocShell::SetOriginAttributes(const Do
 
   bool isPrivate = mOriginAttributes.mPrivateBrowsingId > 0;
   // Chrome docshell can not contain OriginAttributes.mPrivateBrowsingId
   if (mItemType == typeChrome && isPrivate) {
     mOriginAttributes.mPrivateBrowsingId = 0;
   }
 
   SetPrivateBrowsing(isPrivate);
-  AssertOriginAttributesMatchPrivateBrowsing();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetOriginAttributesBeforeLoading(JS::Handle<JS::Value> aOriginAttributes)
 {
   if (!aOriginAttributes.isObject()) {
--- a/dom/svg/SVGFEImageElement.cpp
+++ b/dom/svg/SVGFEImageElement.cpp
@@ -346,17 +346,17 @@ SVGFEImageElement::Notify(imgIRequest* a
 {
   nsresult rv = nsImageLoadingContent::Notify(aRequest, aType, aData);
 
   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     // Request a decode
     nsCOMPtr<imgIContainer> container;
     aRequest->GetImage(getter_AddRefs(container));
     MOZ_ASSERT(container, "who sent the notification then?");
-    container->StartDecoding();
+    container->StartDecoding(imgIContainer::FLAG_NONE);
   }
 
   if (aType == imgINotificationObserver::LOAD_COMPLETE ||
       aType == imgINotificationObserver::FRAME_UPDATE ||
       aType == imgINotificationObserver::SIZE_AVAILABLE) {
     Invalidate();
   }
 
--- a/dom/tests/mochitest/beacon/test_beaconRedirect.html
+++ b/dom/tests/mochitest/beacon/test_beaconRedirect.html
@@ -42,16 +42,21 @@ function queryIfRedirectSucceeded() {
   xhr.send();
 }
 
 function runTest() {
   var data = new Uint8Array([0,1,2,3]);
   navigator.sendBeacon(BEACON_URL, data);
 
   // we have to make sure the channel did follow the redirect hence
-  // we have to wait for 4 seconds before we can query the result.
-  intervalID = setInterval(queryIfRedirectSucceeded, 4000);
+  // we have to wait for a few seconds before we can query the result.
+  interval = 4000;
+  if (navigator.appVersion.indexOf("Android") >= 0) {
+    // Android Debug on an emulator can be very slow
+    interval = 10000;
+  }
+  intervalID = setInterval(queryIfRedirectSucceeded, interval);
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/image/DynamicImage.cpp
+++ b/image/DynamicImage.cpp
@@ -241,17 +241,17 @@ DynamicImage::Draw(gfxContext* aContext,
   aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
 
   gfxUtils::DrawPixelSnapped(aContext, mDrawable, drawableSize, region,
                              SurfaceFormat::B8G8R8A8, aSamplingFilter);
   return DrawResult::SUCCESS;
 }
 
 NS_IMETHODIMP
-DynamicImage::StartDecoding()
+DynamicImage::StartDecoding(uint32_t aFlags)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DynamicImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
 {
   return NS_OK;
--- a/image/ImageWrapper.cpp
+++ b/image/ImageWrapper.cpp
@@ -211,19 +211,19 @@ ImageWrapper::Draw(gfxContext* aContext,
                    const Maybe<SVGImageContext>& aSVGContext,
                    uint32_t aFlags)
 {
   return mInnerImage->Draw(aContext, aSize, aRegion, aWhichFrame,
                            aSamplingFilter, aSVGContext, aFlags);
 }
 
 NS_IMETHODIMP
-ImageWrapper::StartDecoding()
+ImageWrapper::StartDecoding(uint32_t aFlags)
 {
-  return mInnerImage->StartDecoding();
+  return mInnerImage->StartDecoding(aFlags);
 }
 
 NS_IMETHODIMP
 ImageWrapper::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
 {
   return mInnerImage->RequestDecodeForSize(aSize, aFlags);
 }
 
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -1030,28 +1030,29 @@ RasterImage::Discard()
 
 bool
 RasterImage::CanDiscard() {
   return mHasSourceData &&       // ...have the source data...
          !mAnimationState;       // Can never discard animated images
 }
 
 NS_IMETHODIMP
-RasterImage::StartDecoding()
+RasterImage::StartDecoding(uint32_t aFlags)
 {
   if (mError) {
     return NS_ERROR_FAILURE;
   }
 
   if (!mHasSize) {
     mWantFullDecode = true;
     return NS_OK;
   }
 
-  return RequestDecodeForSize(mSize, FLAG_SYNC_DECODE_IF_FAST);
+  uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST;
+  return RequestDecodeForSize(mSize, flags);
 }
 
 NS_IMETHODIMP
 RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mError) {
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -1021,17 +1021,17 @@ VectorImage::RecoverFromLossOfSurfaces()
 {
   NS_WARNING("An imgFrame became invalid. Attempting to recover...");
 
   // Discard all existing frames, since they're probably all now invalid.
   SurfaceCache::RemoveImage(ImageKey(this));
 }
 
 NS_IMETHODIMP
-VectorImage::StartDecoding()
+VectorImage::StartDecoding(uint32_t aFlags)
 {
   // Nothing to do for SVG images
   return NS_OK;
 }
 
 NS_IMETHODIMP
 VectorImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
 {
--- a/image/imgIContainer.idl
+++ b/image/imgIContainer.idl
@@ -409,18 +409,21 @@ interface imgIContainer : nsISupports
        [const] in MaybeSVGImageContext aSVGContext,
        in uint32_t aFlags);
 
   /*
    * Ensures that an image is decoding. Calling this function guarantees that
    * the image will at some point fire off decode notifications. Images that
    * can be decoded "quickly" according to some heuristic will be decoded
    * synchronously.
+   *
+   * @param aFlags Flags of the FLAG_* variety. Only FLAG_ASYNC_NOTIFY
+   *               is accepted; all others are ignored.
    */
-  [noscript] void startDecoding();
+  [noscript] void startDecoding(in uint32_t aFlags);
 
   /*
    * This method triggers decoding for an image, but unlike startDecoding() it
    * enables the caller to provide more detailed information about the decode
    * request.
    *
    * @param aSize The size to which the image should be scaled while decoding,
    *              if possible. If the image cannot be scaled to this size while
--- a/image/imgIRequest.idl
+++ b/image/imgIRequest.idl
@@ -148,17 +148,17 @@ interface imgIRequest : nsIRequest
    * Requests a synchronous decode for the image.
    *
    * imgIContainer has a startDecoding() method, but callers may want to request
    * a decode before the container has necessarily been instantiated. Calling
    * startDecoding() on the imgIRequest simply forwards along the request if the
    * container already exists, or calls it once the container becomes available
    * if it does not yet exist.
    */
-  void startDecoding();
+  void startDecoding(in uint32_t aFlags);
 
   /**
    * Locks an image. If the image does not exist yet, locks it once it becomes
    * available. The lock persists for the lifetime of the imgIRequest (until
    * unlockImage is called) even if the underlying image changes.
    *
    * If you don't call unlockImage() by the time this imgIRequest goes away, it
    * will be called for you automatically.
--- a/image/imgRequest.cpp
+++ b/image/imgRequest.cpp
@@ -1033,17 +1033,17 @@ imgRequest::FinishPreparingForNewPart(co
     MOZ_ASSERT(progressTracker->HasImage());
   }
 
   if (aResult.mShouldResetCacheEntry) {
     ResetCacheEntry();
   }
 
   if (IsDecodeRequested()) {
-    aResult.mImage->StartDecoding();
+    aResult.mImage->StartDecoding(imgIContainer::FLAG_NONE);
   }
 }
 
 NS_IMETHODIMP
 imgRequest::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
                             nsIInputStream* aInStr, uint64_t aOffset,
                             uint32_t aCount)
 {
--- a/image/imgRequestProxy.cpp
+++ b/image/imgRequestProxy.cpp
@@ -224,17 +224,17 @@ imgRequestProxy::ChangeOwner(imgRequest*
     IncrementAnimationConsumers();
   }
 
   GetOwner()->AddProxy(this);
 
   // If we'd previously requested a synchronous decode, request a decode on the
   // new image.
   if (mDecodeRequested) {
-    StartDecoding();
+    StartDecoding(imgIContainer::FLAG_NONE);
   }
 
   return NS_OK;
 }
 
 void
 imgRequestProxy::AddToLoadGroup()
 {
@@ -353,24 +353,24 @@ imgRequestProxy::CancelAndForgetObserver
   }
 
   NullOutListener();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-imgRequestProxy::StartDecoding()
+imgRequestProxy::StartDecoding(uint32_t aFlags)
 {
   // Flag this, so we know to transfer the request if our owner changes
   mDecodeRequested = true;
 
   RefPtr<Image> image = GetImage();
   if (image) {
-    return image->StartDecoding();
+    return image->StartDecoding(aFlags);
   }
 
   if (GetOwner()) {
     GetOwner()->StartDecoding();
   }
 
   return NS_OK;
 }
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -572,141 +572,188 @@ js::regexp_clone(JSContext* cx, unsigned
         return false;
 
     regexp->initAndZeroLastIndex(sourceAtom, flags, cx);
 
     args.rval().setObject(*regexp);
     return true;
 }
 
-/* ES6 draft rev32 21.2.5.4. */
+MOZ_ALWAYS_INLINE bool
+IsRegExpInstanceOrPrototype(HandleValue v)
+{
+    if (!v.isObject())
+        return false;
+
+    return StandardProtoKeyOrNull(&v.toObject()) == JSProto_RegExp;
+}
+
+// ES 2017 draft 21.2.5.4.
 MOZ_ALWAYS_INLINE bool
 regexp_global_impl(JSContext* cx, const CallArgs& args)
 {
-    MOZ_ASSERT(IsRegExpObject(args.thisv()));
+    MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
+
+    // Step 3.a.
+    if (!IsRegExpObject(args.thisv())) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    // Steps 4-6.
     Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
-
-    /* Steps 4-6. */
     args.rval().setBoolean(reObj->global());
     return true;
 }
 
 bool
 js::regexp_global(JSContext* cx, unsigned argc, JS::Value* vp)
 {
-    /* Steps 1-3. */
+    // Steps 1-3.
     CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsRegExpObject, regexp_global_impl>(cx, args);
+    return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_global_impl>(cx, args);
 }
 
-/* ES6 draft rev32 21.2.5.5. */
+// ES 2017 draft 21.2.5.5.
 MOZ_ALWAYS_INLINE bool
 regexp_ignoreCase_impl(JSContext* cx, const CallArgs& args)
 {
-    MOZ_ASSERT(IsRegExpObject(args.thisv()));
+    MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
+
+    // Step 3.a
+    if (!IsRegExpObject(args.thisv())) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    // Steps 4-6.
     Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
-
-    /* Steps 4-6. */
     args.rval().setBoolean(reObj->ignoreCase());
     return true;
 }
 
 bool
 js::regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp)
 {
-    /* Steps 1-3. */
+    // Steps 1-3.
     CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsRegExpObject, regexp_ignoreCase_impl>(cx, args);
+    return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_ignoreCase_impl>(cx, args);
 }
 
-/* ES6 draft rev32 21.2.5.7. */
+// ES 2017 draft 21.2.5.7.
 MOZ_ALWAYS_INLINE bool
 regexp_multiline_impl(JSContext* cx, const CallArgs& args)
 {
-    MOZ_ASSERT(IsRegExpObject(args.thisv()));
+    MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
+
+    // Step 3.a.
+    if (!IsRegExpObject(args.thisv())) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    // Steps 4-6.
     Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
-
-    /* Steps 4-6. */
     args.rval().setBoolean(reObj->multiline());
     return true;
 }
 
 bool
 js::regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp)
 {
-    /* Steps 1-3. */
+    // Steps 1-3.
     CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsRegExpObject, regexp_multiline_impl>(cx, args);
+    return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_multiline_impl>(cx, args);
 }
 
-/* ES6 draft rev32 21.2.5.10. */
+// ES 2017 draft rev32 21.2.5.10.
 MOZ_ALWAYS_INLINE bool
 regexp_source_impl(JSContext* cx, const CallArgs& args)
 {
-    MOZ_ASSERT(IsRegExpObject(args.thisv()));
+    MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
+
+    // Step 3.a.
+    if (!IsRegExpObject(args.thisv())) {
+        args.rval().setString(cx->names().emptyRegExp);
+        return true;
+    }
+
+    // Step 5.
     Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
-
-    /* Step 5. */
     RootedAtom src(cx, reObj->getSource());
     if (!src)
         return false;
 
-    /* Step 7. */
+    // Step 7.
     RootedString str(cx, EscapeRegExpPattern(cx, src));
     if (!str)
         return false;
 
     args.rval().setString(str);
     return true;
 }
 
 static bool
 regexp_source(JSContext* cx, unsigned argc, JS::Value* vp)
 {
-    /* Steps 1-4. */
+    // Steps 1-4.
     CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsRegExpObject, regexp_source_impl>(cx, args);
+    return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_source_impl>(cx, args);
 }
 
-/* ES6 draft rev32 21.2.5.12. */
+// ES 2017 draft 21.2.5.12.
 MOZ_ALWAYS_INLINE bool
 regexp_sticky_impl(JSContext* cx, const CallArgs& args)
 {
-    MOZ_ASSERT(IsRegExpObject(args.thisv()));
+    MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
+
+    // Step 3.a.
+    if (!IsRegExpObject(args.thisv())) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    // Steps 4-6.
     Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
-
-    /* Steps 4-6. */
     args.rval().setBoolean(reObj->sticky());
     return true;
 }
 
 bool
 js::regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp)
 {
-    /* Steps 1-3. */
+    // Steps 1-3.
     CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsRegExpObject, regexp_sticky_impl>(cx, args);
+    return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_sticky_impl>(cx, args);
 }
 
-/* ES6 21.2.5.15. */
+// ES 2017 draft 21.2.5.15.
 MOZ_ALWAYS_INLINE bool
 regexp_unicode_impl(JSContext* cx, const CallArgs& args)
 {
-    MOZ_ASSERT(IsRegExpObject(args.thisv()));
-    /* Steps 4-6. */
-    args.rval().setBoolean(args.thisv().toObject().as<RegExpObject>().unicode());
+    MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
+
+    // Step 3.a.
+    if (!IsRegExpObject(args.thisv())) {
+        args.rval().setUndefined();
+        return true;
+    }
+
+    // Steps 4-6.
+    Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
+    args.rval().setBoolean(reObj->unicode());
     return true;
 }
 
 bool
 js::regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp)
 {
-    /* Steps 1-3. */
+    // Steps 1-3.
     CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsRegExpObject, regexp_unicode_impl>(cx, args);
+    return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_unicode_impl>(cx, args);
 }
 
 const JSPropertySpec js::regexp_properties[] = {
     JS_SELF_HOSTED_GET("flags", "RegExpFlagsGetter", 0),
     JS_PSG("global", regexp_global, 0),
     JS_PSG("ignoreCase", regexp_ignoreCase, 0),
     JS_PSG("multiline", regexp_multiline, 0),
     JS_PSG("source", regexp_source, 0),
@@ -824,35 +871,16 @@ const JSPropertySpec js::regexp_static_p
     JS_PSG("$&", static_lastMatch_getter, JSPROP_PERMANENT),
     JS_PSG("$+", static_lastParen_getter, JSPROP_PERMANENT),
     JS_PSG("$`", static_leftContext_getter, JSPROP_PERMANENT),
     JS_PSG("$'", static_rightContext_getter, JSPROP_PERMANENT),
     JS_SELF_HOSTED_SYM_GET(species, "RegExpSpecies", 0),
     JS_PS_END
 };
 
-JSObject*
-js::CreateRegExpPrototype(JSContext* cx, JSProtoKey key)
-{
-    MOZ_ASSERT(key == JSProto_RegExp);
-
-    Rooted<RegExpObject*> proto(cx, cx->global()->createBlankPrototype<RegExpObject>(cx));
-    if (!proto)
-        return nullptr;
-    proto->NativeObject::setPrivate(nullptr);
-
-    if (!RegExpObject::assignInitialShape(cx, proto))
-        return nullptr;
-
-    RootedAtom source(cx, cx->names().empty);
-    proto->initAndZeroLastIndex(source, RegExpFlag(0), cx);
-
-    return proto;
-}
-
 template <typename CharT>
 static bool
 IsTrailSurrogateWithLeadSurrogateImpl(JSContext* cx, HandleLinearString input, size_t index)
 {
     JS::AutoCheckCannotGC nogc;
     MOZ_ASSERT(index > 0 && index < input->length());
     const CharT* inputChars = input->chars<CharT>(nogc);
 
--- a/js/src/jit-test/tests/basic/plain-object-prototypes-error.js
+++ b/js/src/jit-test/tests/basic/plain-object-prototypes-error.js
@@ -9,8 +9,9 @@ function assertThrowsObjectError(f) {
     }
 }
 
 assertThrowsObjectError(() => Map.prototype.has(0));
 assertThrowsObjectError(() => Set.prototype.has(0));
 assertThrowsObjectError(() => WeakMap.prototype.has({}));
 assertThrowsObjectError(() => WeakSet.prototype.has({}));
 assertThrowsObjectError(() => Date.prototype.getSeconds());
+assertThrowsObjectError(() => RegExp.prototype.compile());
--- a/js/src/jit-test/tests/basic/plain-object-prototypes.js
+++ b/js/src/jit-test/tests/basic/plain-object-prototypes.js
@@ -7,14 +7,15 @@ const prototypes = [
     Error.prototype,
     InternalError.prototype,
     EvalError.prototype,
     RangeError.prototype,
     ReferenceError.prototype,
     SyntaxError.prototype,
     TypeError.prototype,
     URIError.prototype,
+    RegExp.prototype,
 ];
 
 for (const prototype of prototypes) {
     delete prototype[Symbol.toStringTag];
     assertEq(Object.prototype.toString.call(prototype), "[object Object]");
 }
--- a/js/src/jit/BaselineCacheIR.cpp
+++ b/js/src/jit/BaselineCacheIR.cpp
@@ -222,21 +222,22 @@ class MOZ_RAII CacheRegisterAllocator
     }
 
     // Removes spilled values from the native stack. This should only be
     // called after all registers have been allocated.
     void discardStack(MacroAssembler& masm);
 
     // Returns the register for the given operand. If the operand is currently
     // not in a register, it will load it into one.
-    ValueOperand useRegister(MacroAssembler& masm, ValOperandId val);
+    ValueOperand useValueRegister(MacroAssembler& masm, ValOperandId val);
     Register useRegister(MacroAssembler& masm, ObjOperandId obj);
 
     // Allocates an output register for the given operand.
     Register defineRegister(MacroAssembler& masm, ObjOperandId obj);
+    ValueOperand defineValueRegister(MacroAssembler& masm, ValOperandId val);
 };
 
 // RAII class to allocate a scratch register and release it when we're done
 // with it.
 class MOZ_RAII AutoScratchRegister
 {
     CacheRegisterAllocator& alloc_;
     Register reg_;
@@ -483,17 +484,17 @@ class MOZ_RAII BaselineCacheIRCompiler :
     bool makesGCCalls() const { return makesGCCalls_; }
 
   private:
 #define DEFINE_OP(op) MOZ_MUST_USE bool emit##op();
     CACHE_IR_OPS(DEFINE_OP)
 #undef DEFINE_OP
 
     Address stubAddress(uint32_t offset) const {
-        return Address(ICStubReg, stubDataOffset_ + offset * sizeof(uintptr_t));
+        return Address(ICStubReg, stubDataOffset_ + offset);
     }
 
     bool addFailurePath(FailurePath** failure) {
         FailurePath newFailure;
         for (size_t i = 0; i < writer_.numInputOperands(); i++) {
             if (!newFailure.appendInput(allocator.operandLocation(i)))
                 return false;
         }
@@ -615,17 +616,17 @@ BaselineCacheIRCompiler::compile()
     // All barriers are emitted off-by-default, enable them if needed.
     if (cx_->zone()->needsIncrementalBarrier())
         newStubCode->togglePreBarriers(true, DontReprotect);
 
     return newStubCode;
 }
 
 ValueOperand
-CacheRegisterAllocator::useRegister(MacroAssembler& masm, ValOperandId op)
+CacheRegisterAllocator::useValueRegister(MacroAssembler& masm, ValOperandId op)
 {
     OperandLocation& loc = operandLocations_[op.id()];
 
     switch (loc.kind()) {
       case OperandLocation::ValueReg:
         currentOpRegs_.add(loc.valueReg());
         return loc.valueReg();
 
@@ -725,16 +726,27 @@ CacheRegisterAllocator::defineRegister(M
     OperandLocation& loc = operandLocations_[op.id()];
     MOZ_ASSERT(loc.kind() == OperandLocation::Uninitialized);
 
     Register reg = allocateRegister(masm);
     loc.setPayloadReg(reg, JSVAL_TYPE_OBJECT);
     return reg;
 }
 
+ValueOperand
+CacheRegisterAllocator::defineValueRegister(MacroAssembler& masm, ValOperandId val)
+{
+    OperandLocation& loc = operandLocations_[val.id()];
+    MOZ_ASSERT(loc.kind() == OperandLocation::Uninitialized);
+
+    ValueOperand reg = allocateValueRegister(masm);
+    loc.setValueReg(reg);
+    return reg;
+}
+
 void
 CacheRegisterAllocator::freeDeadOperandRegisters()
 {
     // See if any operands are dead so we can reuse their registers. Note that
     // we skip the input operands, as those are also used by failure paths, and
     // we currently don't track those uses.
     for (size_t i = writer_.numInputOperands(); i < operandLocations_.length(); i++) {
         if (!writer_.operandIsDead(i, currentInstruction_))
@@ -874,28 +886,28 @@ CacheRegisterAllocator::allocateValueReg
     Register reg = allocateRegister(masm);
     return ValueOperand(reg);
 #endif
 }
 
 bool
 BaselineCacheIRCompiler::emitGuardIsObject()
 {
-    ValueOperand input = allocator.useRegister(masm, reader.valOperandId());
+    ValueOperand input = allocator.useValueRegister(masm, reader.valOperandId());
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
     masm.branchTestObject(Assembler::NotEqual, input, failure->label());
     return true;
 }
 
 bool
 BaselineCacheIRCompiler::emitGuardType()
 {
-    ValueOperand input = allocator.useRegister(masm, reader.valOperandId());
+    ValueOperand input = allocator.useValueRegister(masm, reader.valOperandId());
     JSValueType type = reader.valueType();
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
     switch (type) {
       case JSVAL_TYPE_STRING:
@@ -905,16 +917,19 @@ BaselineCacheIRCompiler::emitGuardType()
         masm.branchTestSymbol(Assembler::NotEqual, input, failure->label());
         break;
       case JSVAL_TYPE_DOUBLE:
         masm.branchTestNumber(Assembler::NotEqual, input, failure->label());
         break;
       case JSVAL_TYPE_BOOLEAN:
         masm.branchTestBoolean(Assembler::NotEqual, input, failure->label());
         break;
+      case JSVAL_TYPE_UNDEFINED:
+        masm.branchTestUndefined(Assembler::NotEqual, input, failure->label());
+        break;
       default:
         MOZ_CRASH("Unexpected type");
     }
 
     return true;
 }
 
 bool
@@ -995,16 +1010,45 @@ BaselineCacheIRCompiler::emitGuardClass(
     }
 
     MOZ_ASSERT(clasp);
     masm.branchTestObjClass(Assembler::NotEqual, obj, scratch, clasp, failure->label());
     return true;
 }
 
 bool
+BaselineCacheIRCompiler::emitGuardIsProxy()
+{
+    Register obj = allocator.useRegister(masm, reader.objOperandId());
+    AutoScratchRegister scratch(allocator, masm);
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    masm.branchTestObjectIsProxy(false, obj, scratch, failure->label());
+    return true;
+}
+
+bool
+BaselineCacheIRCompiler::emitGuardNotDOMProxy()
+{
+    Register obj = allocator.useRegister(masm, reader.objOperandId());
+    AutoScratchRegister scratch(allocator, masm);
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    masm.branchTestProxyHandlerFamily(Assembler::Equal, obj, scratch,
+                                      GetDOMProxyHandlerFamily(), failure->label());
+    return true;
+}
+
+bool
 BaselineCacheIRCompiler::emitGuardSpecificObject()
 {
     Register obj = allocator.useRegister(masm, reader.objOperandId());
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
@@ -1168,16 +1212,52 @@ BaselineCacheIRCompiler::emitCallNativeG
 
     if (!callVM(masm, DoCallNativeGetterInfo))
         return false;
 
     leaveStubFrame(masm);
     return true;
 }
 
+typedef bool (*ProxyGetPropertyFn)(JSContext*, HandleObject, HandleId, MutableHandleValue);
+static const VMFunction ProxyGetPropertyInfo =
+    FunctionInfo<ProxyGetPropertyFn>(ProxyGetProperty, "ProxyGetProperty");
+
+bool
+BaselineCacheIRCompiler::emitCallProxyGetResult()
+{
+    // We use ICTailCallReg when entering the stub frame, so ensure it's not
+    // used for something else.
+    Maybe<AutoScratchRegister> tail;
+    if (allocator.isAllocatable(ICTailCallReg))
+        tail.emplace(allocator, masm, ICTailCallReg);
+
+    Register obj = allocator.useRegister(masm, reader.objOperandId());
+    Address idAddr(stubAddress(reader.stubOffset()));
+
+    AutoScratchRegister scratch(allocator, masm);
+
+    allocator.discardStack(masm);
+
+    // Push a stub frame so that we can perform a non-tail call.
+    enterStubFrame(masm, scratch);
+
+    // Load the jsid in the scratch register.
+    masm.loadPtr(idAddr, scratch);
+
+    masm.Push(scratch);
+    masm.Push(obj);
+
+    if (!callVM(masm, ProxyGetPropertyInfo))
+        return false;
+
+    leaveStubFrame(masm);
+    return true;
+}
+
 bool
 BaselineCacheIRCompiler::emitLoadUnboxedPropertyResult()
 {
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     AutoScratchRegister scratch(allocator, masm);
 
     JSValueType fieldType = reader.valueType();
     Address fieldOffset(stubAddress(reader.stubOffset()));
@@ -1341,16 +1421,85 @@ BaselineCacheIRCompiler::emitLoadProto()
 {
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     Register reg = allocator.defineRegister(masm, reader.objOperandId());
     masm.loadObjProto(obj, reg);
     return true;
 }
 
 bool
+BaselineCacheIRCompiler::emitLoadDOMExpandoValue()
+{
+    Register obj = allocator.useRegister(masm, reader.objOperandId());
+    ValueOperand val = allocator.defineValueRegister(masm, reader.valOperandId());
+
+    masm.loadPtr(Address(obj, ProxyObject::offsetOfValues()), val.scratchReg());
+    masm.loadValue(Address(val.scratchReg(),
+                           ProxyObject::offsetOfExtraSlotInValues(GetDOMProxyExpandoSlot())),
+                   val);
+    return true;
+}
+
+bool
+BaselineCacheIRCompiler::emitGuardDOMExpandoObject()
+{
+    ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
+    AutoScratchRegister shapeScratch(allocator, masm);
+    AutoScratchRegister objScratch(allocator, masm);
+    Address shapeAddr(stubAddress(reader.stubOffset()));
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    Label done;
+    masm.branchTestUndefined(Assembler::Equal, val, &done);
+
+    masm.loadPtr(shapeAddr, shapeScratch);
+    masm.unboxObject(val, objScratch);
+    masm.branchTestObjShape(Assembler::NotEqual, objScratch, shapeScratch, failure->label());
+
+    masm.bind(&done);
+    return true;
+}
+
+bool
+BaselineCacheIRCompiler::emitGuardDOMExpandoGeneration()
+{
+    Register obj = allocator.useRegister(masm, reader.objOperandId());
+    Address expandoAndGenerationAddr(stubAddress(reader.stubOffset()));
+    Address generationAddr(stubAddress(reader.stubOffset()));
+
+    AutoScratchRegister scratch(allocator, masm);
+    ValueOperand output = allocator.defineValueRegister(masm, reader.valOperandId());
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    masm.loadPtr(Address(obj, ProxyObject::offsetOfValues()), scratch);
+    Address expandoAddr(scratch, ProxyObject::offsetOfExtraSlotInValues(GetDOMProxyExpandoSlot()));
+
+    // Load the ExpandoAndGeneration* in the output scratch register and guard
+    // it matches the proxy's ExpandoAndGeneration.
+    masm.loadPtr(expandoAndGenerationAddr, output.scratchReg());
+    masm.branchPrivatePtr(Assembler::NotEqual, expandoAddr, output.scratchReg(), failure->label());
+
+    // Guard expandoAndGeneration->generation matches the expected generation.
+    masm.branch64(Assembler::NotEqual,
+                  Address(output.scratchReg(), ExpandoAndGeneration::offsetOfGeneration()),
+                  generationAddr,
+                  scratch, failure->label());
+
+    // Load expandoAndGeneration->expando into the output Value register.
+    masm.loadValue(Address(output.scratchReg(), ExpandoAndGeneration::offsetOfExpando()), output);
+    return true;
+}
+
+bool
 BaselineCacheIRCompiler::init(CacheKind kind)
 {
     size_t numInputs = writer_.numInputOperands();
     if (!allocator.init(ICStubCompiler::availableGeneralRegs(numInputs)))
         return false;
 
     MOZ_ASSERT(numInputs == 1);
     allocator.initInputLocation(0, R0);
@@ -1362,58 +1511,68 @@ template <typename T>
 static GCPtr<T>*
 AsGCPtr(uintptr_t* ptr)
 {
     return reinterpret_cast<GCPtr<T>*>(ptr);
 }
 
 template<class T>
 GCPtr<T>&
-CacheIRStubInfo::getStubField(ICStub* stub, uint32_t field) const
+CacheIRStubInfo::getStubField(ICStub* stub, uint32_t offset) const
 {
     uint8_t* stubData = (uint8_t*)stub + stubDataOffset_;
     MOZ_ASSERT(uintptr_t(stubData) % sizeof(uintptr_t) == 0);
 
-    return *AsGCPtr<T>((uintptr_t*)stubData + field);
+    return *AsGCPtr<T>((uintptr_t*)(stubData + offset));
 }
 
 template GCPtr<Shape*>& CacheIRStubInfo::getStubField(ICStub* stub, uint32_t offset) const;
 template GCPtr<ObjectGroup*>& CacheIRStubInfo::getStubField(ICStub* stub, uint32_t offset) const;
 template GCPtr<JSObject*>& CacheIRStubInfo::getStubField(ICStub* stub, uint32_t offset) const;
 
-template <typename T>
+template <typename T, typename V>
 static void
-InitGCPtr(uintptr_t* ptr, uintptr_t val)
+InitGCPtr(uintptr_t* ptr, V val)
 {
-    AsGCPtr<T*>(ptr)->init((T*)val);
+    AsGCPtr<T>(ptr)->init(mozilla::BitwiseCast<T>(val));
 }
 
 void
 CacheIRWriter::copyStubData(uint8_t* dest) const
 {
     uintptr_t* destWords = reinterpret_cast<uintptr_t*>(dest);
 
     for (size_t i = 0; i < stubFields_.length(); i++) {
-        switch (stubFields_[i].gcType) {
-          case StubField::GCType::NoGCThing:
-            destWords[i] = stubFields_[i].word;
-            continue;
-          case StubField::GCType::Shape:
-            InitGCPtr<Shape>(destWords + i, stubFields_[i].word);
-            continue;
-          case StubField::GCType::JSObject:
-            InitGCPtr<JSObject>(destWords + i, stubFields_[i].word);
-            continue;
-          case StubField::GCType::ObjectGroup:
-            InitGCPtr<ObjectGroup>(destWords + i, stubFields_[i].word);
-            continue;
-          case StubField::GCType::Limit:
+        StubField::Type type = stubFields_[i].type();
+        switch (type) {
+          case StubField::Type::RawWord:
+            *destWords = stubFields_[i].asWord();
+            break;
+          case StubField::Type::Shape:
+            InitGCPtr<Shape*>(destWords, stubFields_[i].asWord());
+            break;
+          case StubField::Type::JSObject:
+            InitGCPtr<JSObject*>(destWords, stubFields_[i].asWord());
+            break;
+          case StubField::Type::ObjectGroup:
+            InitGCPtr<ObjectGroup*>(destWords, stubFields_[i].asWord());
             break;
+          case StubField::Type::Id:
+            InitGCPtr<jsid>(destWords, stubFields_[i].asWord());
+            break;
+          case StubField::Type::RawInt64:
+            *reinterpret_cast<uint64_t*>(destWords) = stubFields_[i].asInt64();
+            break;
+          case StubField::Type::Value:
+            InitGCPtr<JS::Value>(destWords, stubFields_[i].asInt64());
+            break;
+          case StubField::Type::Limit:
+            MOZ_CRASH("Invalid type");
         }
-        MOZ_CRASH();
+        destWords += StubField::sizeInBytes(type) / sizeof(uintptr_t);
     }
 }
 
 HashNumber
 CacheIRStubKey::hash(const CacheIRStubKey::Lookup& l)
 {
     HashNumber hash = mozilla::HashBytes(l.code, l.length);
     hash = mozilla::AddToHash(hash, uint32_t(l.kind));
@@ -1454,27 +1613,27 @@ CacheIRStubInfo::New(CacheKind kind, ICS
     uint8_t* p = js_pod_malloc<uint8_t>(bytesNeeded);
     if (!p)
         return nullptr;
 
     // Copy the CacheIR code.
     uint8_t* codeStart = p + sizeof(CacheIRStubInfo);
     mozilla::PodCopy(codeStart, writer.codeStart(), writer.codeLength());
 
-    static_assert(uint32_t(StubField::GCType::Limit) <= UINT8_MAX,
-                  "All StubField::GCTypes must fit in uint8_t");
+    static_assert(sizeof(StubField::Type) == sizeof(uint8_t),
+                  "StubField::Type must fit in uint8_t");
 
-    // Copy the GC types of the stub fields.
-    uint8_t* gcTypes = codeStart + writer.codeLength();
+    // Copy the stub field types.
+    uint8_t* fieldTypes = codeStart + writer.codeLength();
     for (size_t i = 0; i < numStubFields; i++)
-        gcTypes[i] = uint8_t(writer.stubFieldGCType(i));
-    gcTypes[numStubFields] = uint8_t(StubField::GCType::Limit);
+        fieldTypes[i] = uint8_t(writer.stubFieldType(i));
+    fieldTypes[numStubFields] = uint8_t(StubField::Type::Limit);
 
     return new(p) CacheIRStubInfo(kind, engine, makesGCCalls, stubDataOffset, codeStart,
-                                  writer.codeLength(), gcTypes);
+                                  writer.codeLength(), fieldTypes);
 }
 
 static const size_t MaxOptimizedCacheIRStubs = 16;
 
 ICStub*
 jit::AttachBaselineCacheIRStub(JSContext* cx, const CacheIRWriter& writer,
                                CacheKind kind, ICStubEngine engine, JSScript* outerScript,
                                ICFallbackStub* stub)
@@ -1546,86 +1705,102 @@ jit::AttachBaselineCacheIRStub(JSContext
     stub->addNewStub((ICStub*)newStub);
     return (ICStub*)newStub;
 }
 
 void
 jit::TraceBaselineCacheIRStub(JSTracer* trc, ICStub* stub, const CacheIRStubInfo* stubInfo)
 {
     uint32_t field = 0;
+    size_t offset = 0;
     while (true) {
-        switch (stubInfo->gcType(field)) {
-          case StubField::GCType::NoGCThing:
+        StubField::Type fieldType = stubInfo->fieldType(field);
+        switch (fieldType) {
+          case StubField::Type::RawWord:
+          case StubField::Type::RawInt64:
             break;
-          case StubField::GCType::Shape:
-            TraceNullableEdge(trc, &stubInfo->getStubField<Shape*>(stub, field),
+          case StubField::Type::Shape:
+            TraceNullableEdge(trc, &stubInfo->getStubField<Shape*>(stub, offset),
                               "baseline-cacheir-shape");
             break;
-          case StubField::GCType::ObjectGroup:
-            TraceNullableEdge(trc, &stubInfo->getStubField<ObjectGroup*>(stub, field),
+          case StubField::Type::ObjectGroup:
+            TraceNullableEdge(trc, &stubInfo->getStubField<ObjectGroup*>(stub, offset),
                               "baseline-cacheir-group");
             break;
-          case StubField::GCType::JSObject:
-            TraceNullableEdge(trc, &stubInfo->getStubField<JSObject*>(stub, field),
+          case StubField::Type::JSObject:
+            TraceNullableEdge(trc, &stubInfo->getStubField<JSObject*>(stub, offset),
                               "baseline-cacheir-object");
             break;
-          case StubField::GCType::Limit:
+          case StubField::Type::Id:
+            TraceEdge(trc, &stubInfo->getStubField<jsid>(stub, offset), "baseline-cacheir-id");
+            break;
+          case StubField::Type::Value:
+            TraceEdge(trc, &stubInfo->getStubField<JS::Value>(stub, offset),
+                      "baseline-cacheir-value");
+            break;
+          case StubField::Type::Limit:
             return; // Done.
-          default:
-            MOZ_CRASH();
         }
         field++;
+        offset += StubField::sizeInBytes(fieldType);
     }
 }
 
 size_t
 CacheIRStubInfo::stubDataSize() const
 {
     size_t field = 0;
     size_t size = 0;
     while (true) {
-        switch (gcType(field++)) {
-          case StubField::GCType::NoGCThing:
-          case StubField::GCType::Shape:
-          case StubField::GCType::ObjectGroup:
-          case StubField::GCType::JSObject:
-            size += sizeof(uintptr_t);
-            continue;
-          case StubField::GCType::Limit:
+        StubField::Type type = fieldType(field++);
+        if (type == StubField::Type::Limit)
             return size;
-        }
-        MOZ_CRASH("unreachable");
+        size += StubField::sizeInBytes(type);
     }
 }
 
 void
 CacheIRStubInfo::copyStubData(ICStub* src, ICStub* dest) const
 {
-    uintptr_t* srcWords = reinterpret_cast<uintptr_t*>(src);
-    uintptr_t* destWords = reinterpret_cast<uintptr_t*>(dest);
+    uint8_t* srcBytes = reinterpret_cast<uint8_t*>(src);
+    uint8_t* destBytes = reinterpret_cast<uint8_t*>(dest);
 
     size_t field = 0;
+    size_t offset = 0;
     while (true) {
-        switch (gcType(field)) {
-          case StubField::GCType::NoGCThing:
-            destWords[field] = srcWords[field];
+        StubField::Type type = fieldType(field);
+        switch (type) {
+          case StubField::Type::RawWord:
+            *reinterpret_cast<uintptr_t*>(destBytes + offset) =
+                *reinterpret_cast<uintptr_t*>(srcBytes + offset);
             break;
-          case StubField::GCType::Shape:
-            getStubField<Shape*>(dest, field).init(getStubField<Shape*>(src, field));
+          case StubField::Type::RawInt64:
+            *reinterpret_cast<uint64_t*>(destBytes + offset) =
+                *reinterpret_cast<uint64_t*>(srcBytes + offset);
             break;
-          case StubField::GCType::JSObject:
-            getStubField<JSObject*>(dest, field).init(getStubField<JSObject*>(src, field));
+          case StubField::Type::Shape:
+            getStubField<Shape*>(dest, offset).init(getStubField<Shape*>(src, offset));
+            break;
+          case StubField::Type::JSObject:
+            getStubField<JSObject*>(dest, offset).init(getStubField<JSObject*>(src, offset));
             break;
-          case StubField::GCType::ObjectGroup:
-            getStubField<ObjectGroup*>(dest, field).init(getStubField<ObjectGroup*>(src, field));
+          case StubField::Type::ObjectGroup:
+            getStubField<ObjectGroup*>(dest, offset).init(getStubField<ObjectGroup*>(src, offset));
             break;
-          case StubField::GCType::Limit:
+          case StubField::Type::Id:
+            getStubField<jsid>(dest, offset).init(getStubField<jsid>(src, offset));
+            break;
+          case StubField::Type::Value:
+            getStubField<Value>(dest, offset).init(getStubField<Value>(src, offset));
+            break;
+          case StubField::Type::Limit:
             return; // Done.
         }
         field++;
+        offset += StubField::sizeInBytes(type);
     }
 }
 
 
 /* static */ ICCacheIR_Monitored*
 ICCacheIR_Monitored::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
                            ICCacheIR_Monitored& other)
 {
--- a/js/src/jit/BaselineCacheIR.h
+++ b/js/src/jit/BaselineCacheIR.h
@@ -24,28 +24,28 @@ class CacheIRStubInfo
     // smaller than the size of the enums.
     CacheKind kind_ : 8;
     ICStubEngine engine_ : 8;
     bool makesGCCalls_ : 1;
     uint8_t stubDataOffset_;
 
     const uint8_t* code_;
     uint32_t length_;
-    const uint8_t* gcTypes_;
+    const uint8_t* fieldTypes_;
 
     CacheIRStubInfo(CacheKind kind, ICStubEngine engine, bool makesGCCalls,
                     uint32_t stubDataOffset, const uint8_t* code, uint32_t codeLength,
-                    const uint8_t* gcTypes)
+                    const uint8_t* fieldTypes)
       : kind_(kind),
         engine_(engine),
         makesGCCalls_(makesGCCalls),
         stubDataOffset_(stubDataOffset),
         code_(code),
         length_(codeLength),
-        gcTypes_(gcTypes)
+        fieldTypes_(fieldTypes)
     {
         MOZ_ASSERT(kind_ == kind, "Kind must fit in bitfield");
         MOZ_ASSERT(engine_ == engine, "Engine must fit in bitfield");
         MOZ_ASSERT(stubDataOffset_ == stubDataOffset, "stubDataOffset must fit in uint8_t");
     }
 
     CacheIRStubInfo(const CacheIRStubInfo&) = delete;
     CacheIRStubInfo& operator=(const CacheIRStubInfo&) = delete;
@@ -56,17 +56,17 @@ class CacheIRStubInfo
     bool makesGCCalls() const { return makesGCCalls_; }
 
     const uint8_t* code() const { return code_; }
     uint32_t codeLength() const { return length_; }
     uint32_t stubDataOffset() const { return stubDataOffset_; }
 
     size_t stubDataSize() const;
 
-    StubField::GCType gcType(uint32_t i) const { return (StubField::GCType)gcTypes_[i]; }
+    StubField::Type fieldType(uint32_t i) const { return (StubField::Type)fieldTypes_[i]; }
 
     static CacheIRStubInfo* New(CacheKind kind, ICStubEngine engine, bool canMakeCalls,
                                 uint32_t stubDataOffset, const CacheIRWriter& writer);
 
     template <class T>
     js::GCPtr<T>& getStubField(ICStub* stub, uint32_t field) const;
 
     void copyStubData(ICStub* src, ICStub* dest) const;
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -698,19 +698,16 @@ RecompileBaselineScriptForDebugMode(JSCo
     _(Call_ScriptedApplyArray)                  \
     _(Call_ScriptedApplyArguments)              \
     _(Call_ScriptedFunCall)                     \
     _(GetElem_NativePrototypeCallNativeName)    \
     _(GetElem_NativePrototypeCallNativeSymbol)  \
     _(GetElem_NativePrototypeCallScriptedName)  \
     _(GetElem_NativePrototypeCallScriptedSymbol) \
     _(GetProp_CallNativeGlobal)                 \
-    _(GetProp_CallDOMProxyNative)               \
-    _(GetProp_CallDOMProxyWithGenerationNative) \
-    _(GetProp_DOMProxyShadowed)                 \
     _(GetProp_Generic)                          \
     _(SetProp_CallScripted)                     \
     _(SetProp_CallNative)
 
 static bool
 CloneOldBaselineStub(JSContext* cx, DebugModeOSREntryVector& entries, size_t entryIndex)
 {
     DebugModeOSREntry& entry = entries[entryIndex];
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -1014,19 +1014,16 @@ BaselineInspector::expectedPropertyAcces
           case ICStub::GetProp_Generic:
             return MIRType::Value;
 
           case ICStub::GetProp_ArgumentsLength:
           case ICStub::GetElem_Arguments:
             // Either an object or magic arguments.
             return MIRType::Value;
 
-          case ICStub::GetProp_CallDOMProxyNative:
-          case ICStub::GetProp_CallDOMProxyWithGenerationNative:
-          case ICStub::GetProp_DOMProxyShadowed:
           case ICStub::GetElem_NativeSlotName:
           case ICStub::GetElem_NativeSlotSymbol:
           case ICStub::GetElem_NativePrototypeSlotName:
           case ICStub::GetElem_NativePrototypeSlotSymbol:
           case ICStub::GetElem_NativePrototypeCallNativeName:
           case ICStub::GetElem_NativePrototypeCallNativeSymbol:
           case ICStub::GetElem_NativePrototypeCallScriptedName:
           case ICStub::GetElem_NativePrototypeCallScriptedSymbol:
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -17,17 +17,18 @@ using namespace js;
 using namespace js::jit;
 
 using mozilla::Maybe;
 
 GetPropIRGenerator::GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine,
                                        bool* isTemporarilyUnoptimizable,
                                        HandleValue val, HandlePropertyName name,
                                        MutableHandleValue res)
-  : cx_(cx),
+  : writer(cx),
+    cx_(cx),
     pc_(pc),
     val_(val),
     name_(name),
     res_(res),
     engine_(engine),
     isTemporarilyUnoptimizable_(isTemporarilyUnoptimizable),
     emitted_(false),
     preliminaryObjectAction_(PreliminaryObjectAction::None)
@@ -41,48 +42,48 @@ EmitLoadSlotResult(CacheIRWriter& writer
         writer.loadFixedSlotResult(holderOp, NativeObject::getFixedSlotOffset(shape->slot()));
     } else {
         size_t dynamicSlotOffset = holder->dynamicSlotIndex(shape->slot()) * sizeof(Value);
         writer.loadDynamicSlotResult(holderOp, dynamicSlotOffset);
     }
 }
 
 bool
-GetPropIRGenerator::tryAttachStub(Maybe<CacheIRWriter>& writer)
+GetPropIRGenerator::tryAttachStub()
 {
     AutoAssertNoPendingException aanpe(cx_);
-    JS::AutoCheckCannotGC nogc;
 
     MOZ_ASSERT(!emitted_);
 
-    writer.emplace();
-    ValOperandId valId(writer->setInputOperandId(0));
+    ValOperandId valId(writer.setInputOperandId(0));
 
     if (val_.isObject()) {
         RootedObject obj(cx_, &val_.toObject());
-        ObjOperandId objId = writer->guardIsObject(valId);
+        ObjOperandId objId = writer.guardIsObject(valId);
 
-        if (!emitted_ && !tryAttachObjectLength(*writer, obj, objId))
+        if (!emitted_ && !tryAttachObjectLength(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachNative(*writer, obj, objId))
+        if (!emitted_ && !tryAttachNative(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachUnboxed(*writer, obj, objId))
+        if (!emitted_ && !tryAttachUnboxed(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachUnboxedExpando(*writer, obj, objId))
+        if (!emitted_ && !tryAttachUnboxedExpando(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachTypedObject(*writer, obj, objId))
+        if (!emitted_ && !tryAttachTypedObject(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachModuleNamespace(*writer, obj, objId))
+        if (!emitted_ && !tryAttachModuleNamespace(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachWindowProxy(*writer, obj, objId))
+        if (!emitted_ && !tryAttachWindowProxy(obj, objId))
+            return false;
+        if (!emitted_ && !tryAttachProxy(obj, objId))
             return false;
         return true;
     }
 
-    if (!emitted_ && !tryAttachPrimitive(*writer, valId))
+    if (!emitted_ && !tryAttachPrimitive(valId))
         return false;
 
     return true;
 }
 
 static bool
 IsCacheableNoProperty(JSContext* cx, JSObject* obj, JSObject* holder, Shape* shape, jsid id,
                       jsbytecode* pc)
@@ -256,48 +257,55 @@ EmitReadSlotReturn(CacheIRWriter& writer
         // Normally for this op, the result would have to be monitored by TI.
         // However, since this stub ALWAYS returns UndefinedValue(), and we can be sure
         // that undefined is already registered with the type-set, this can be avoided.
         writer.returnFromIC();
     }
 }
 
 static void
-EmitCallGetterResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
-                     Shape* shape, ObjOperandId objId)
+EmitCallGetterResultNoGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
+                             Shape* shape, ObjOperandId objId)
 {
-    Maybe<ObjOperandId> expandoId;
-    TestMatchingReceiver(writer, obj, shape, objId, &expandoId);
-
-    if (obj != holder) {
-        GeneratePrototypeGuards(writer, obj, holder, objId);
-
-        // Guard on the holder's shape.
-        ObjOperandId holderId = writer.loadObject(holder);
-        writer.guardShape(holderId, holder->as<NativeObject>().lastProperty());
-    }
-
     if (IsCacheableGetPropCallNative(obj, holder, shape)) {
         JSFunction* target = &shape->getterValue().toObject().as<JSFunction>();
         MOZ_ASSERT(target->isNative());
         writer.callNativeGetterResult(objId, target);
         writer.typeMonitorResult();
         return;
     }
 
     MOZ_ASSERT(IsCacheableGetPropCallScripted(obj, holder, shape));
 
     JSFunction* target = &shape->getterValue().toObject().as<JSFunction>();
     MOZ_ASSERT(target->hasJITCode());
     writer.callScriptedGetterResult(objId, target);
     writer.typeMonitorResult();
 }
 
+static void
+EmitCallGetterResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
+                     Shape* shape, ObjOperandId objId)
+{
+    Maybe<ObjOperandId> expandoId;
+    TestMatchingReceiver(writer, obj, shape, objId, &expandoId);
+
+    if (obj != holder) {
+        GeneratePrototypeGuards(writer, obj, holder, objId);
+
+        // Guard on the holder's shape.
+        ObjOperandId holderId = writer.loadObject(holder);
+        writer.guardShape(holderId, holder->as<NativeObject>().lastProperty());
+    }
+
+    EmitCallGetterResultNoGuards(writer, obj, holder, shape, objId);
+}
+
 bool
-GetPropIRGenerator::tryAttachNative(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     RootedShape shape(cx_);
     RootedNativeObject holder(cx_);
 
     RootedId id(cx_, NameToId(name_));
     NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, obj, id, &holder, &shape, pc_,
@@ -328,18 +336,17 @@ GetPropIRGenerator::tryAttachNative(Cach
       default:
         MOZ_CRASH("Bad NativeGetPropCacheability");
     }
 
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachWindowProxy(CacheIRWriter& writer, HandleObject obj,
-                                         ObjOperandId objId)
+GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId)
 {
     // Attach a stub when the receiver is a WindowProxy and we are calling some
     // kinds of JSNative getters on the Window object (the global object).
 
     MOZ_ASSERT(!emitted_);
 
     if (!IsWindowProxy(obj))
         return true;
@@ -377,17 +384,168 @@ GetPropIRGenerator::tryAttachWindowProxy
     // on the Window object.
     writer.guardClass(objId, GuardClassKind::WindowProxy);
     ObjOperandId windowObjId = writer.loadObject(windowObj);
     EmitCallGetterResult(writer, windowObj, holder, shape, windowObjId);
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachUnboxed(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId)
+{
+    MOZ_ASSERT(!emitted_);
+    MOZ_ASSERT(obj->is<ProxyObject>());
+
+    emitted_ = true;
+
+    writer.guardIsProxy(objId);
+
+    // Ensure that the incoming object is not a DOM proxy, so that we can get to
+    // the specialized stubs
+    writer.guardNotDOMProxy(objId);
+
+    writer.callProxyGetResult(objId, NameToId(name_));
+    writer.typeMonitorResult();
+    return true;
+}
+
+bool
+GetPropIRGenerator::tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId)
+{
+    MOZ_ASSERT(!emitted_);
+    MOZ_ASSERT(IsCacheableDOMProxy(obj));
+
+    emitted_ = true;
+
+    writer.guardShape(objId, obj->maybeShape());
+
+    // No need for more guards: we know this is a DOM proxy, since the shape
+    // guard enforces a given JSClass, so just go ahead and emit the call to
+    // ProxyGet.
+    writer.callProxyGetResult(objId, NameToId(name_));
+    writer.typeMonitorResult();
+    return true;
+}
+
+// Callers are expected to have already guarded on the shape of the
+// object, which guarantees the object is a DOM proxy.
+static void
+CheckDOMProxyExpandoDoesNotShadow(CacheIRWriter& writer, JSObject* obj, jsid id,
+                                  ObjOperandId objId)
+{
+    MOZ_ASSERT(IsCacheableDOMProxy(obj));
+
+    Value expandoVal = GetProxyExtra(obj, GetDOMProxyExpandoSlot());
+
+    ValOperandId expandoId;
+    if (!expandoVal.isObject() && !expandoVal.isUndefined()) {
+        ExpandoAndGeneration* expandoAndGeneration = (ExpandoAndGeneration*)expandoVal.toPrivate();
+        expandoId = writer.guardDOMExpandoGeneration(objId, expandoAndGeneration,
+                                                     expandoAndGeneration->generation);
+        expandoVal = expandoAndGeneration->expando;
+    } else {
+        expandoId = writer.loadDOMExpandoValue(objId);
+    }
+
+    if (expandoVal.isUndefined()) {
+        // Guard there's no expando object.
+        writer.guardType(expandoId, JSVAL_TYPE_UNDEFINED);
+    } else if (expandoVal.isObject()) {
+        // Guard the proxy either has no expando object or, if it has one, that
+        // the shape matches the current expando object.
+        NativeObject& expandoObj = expandoVal.toObject().as<NativeObject>();
+        MOZ_ASSERT(!expandoObj.containsPure(id));
+        writer.guardDOMExpandoObject(expandoId, expandoObj.lastProperty());
+    } else {
+        MOZ_CRASH("Invalid expando value");
+    }
+}
+
+bool
+GetPropIRGenerator::tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId)
+{
+    MOZ_ASSERT(!emitted_);
+    MOZ_ASSERT(IsCacheableDOMProxy(obj));
+
+    RootedObject checkObj(cx_, obj->staticPrototype());
+    RootedNativeObject holder(cx_);
+    RootedShape shape(cx_);
+
+    RootedId id(cx_, NameToId(name_));
+    NativeGetPropCacheability canCache = CanAttachNativeGetProp(cx_, checkObj, id, &holder, &shape,
+                                                                pc_, engine_,
+                                                                isTemporarilyUnoptimizable_);
+    if (canCache == CanAttachNone)
+        return true;
+
+    emitted_ = true;
+
+    writer.guardShape(objId, obj->maybeShape());
+
+    // Guard that our expando object hasn't started shadowing this property.
+    CheckDOMProxyExpandoDoesNotShadow(writer, obj, id, objId);
+
+    if (holder) {
+        // Found the property on the prototype chain. Treat it like a native
+        // getprop.
+        GeneratePrototypeGuards(writer, obj, holder, objId);
+
+        // Guard on the holder of the property.
+        ObjOperandId holderId = writer.loadObject(holder);
+        writer.guardShape(holderId, holder->lastProperty());
+
+        if (canCache == CanAttachReadSlot) {
+            EmitLoadSlotResult(writer, holderId, holder, shape);
+            writer.typeMonitorResult();
+        } else {
+            // EmitCallGetterResultNoGuards expects |obj| to be the object the
+            // property is on to do some checks. Since we actually looked at
+            // checkObj, and no extra guards will be generated, we can just
+            // pass that instead.
+            MOZ_ASSERT(canCache == CanAttachCallGetter);
+            EmitCallGetterResultNoGuards(writer, checkObj, holder, shape, objId);
+        }
+    } else {
+        // Property was not found on the prototype chain. Deoptimize down to
+        // proxy get call.
+        writer.callProxyGetResult(objId, id);
+        writer.typeMonitorResult();
+    }
+
+    return true;
+}
+
+bool
+GetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId)
+{
+    MOZ_ASSERT(!emitted_);
+
+    if (!obj->is<ProxyObject>())
+        return true;
+
+    // Skim off DOM proxies.
+    if (IsCacheableDOMProxy(obj)) {
+        RootedId id(cx_, NameToId(name_));
+        DOMProxyShadowsResult shadows = GetDOMProxyShadowsCheck()(cx_, obj, id);
+        if (shadows == ShadowCheckFailed) {
+            cx_->clearPendingException();
+            return false;
+        }
+        if (DOMProxyIsShadowing(shadows))
+            return tryAttachDOMProxyShadowed(obj, objId);
+
+        MOZ_ASSERT(shadows == DoesntShadow || shadows == DoesntShadowUnique);
+        return tryAttachDOMProxyUnshadowed(obj, objId);
+    }
+
+    return tryAttachGenericProxy(obj, objId);
+}
+
+bool
+GetPropIRGenerator::tryAttachUnboxed(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (!obj->is<UnboxedPlainObject>())
         return true;
 
     const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(name_);
     if (!property)
@@ -405,17 +563,17 @@ GetPropIRGenerator::tryAttachUnboxed(Cac
         writer.returnFromIC();
 
     emitted_ = true;
     preliminaryObjectAction_ = PreliminaryObjectAction::Unlink;
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachUnboxedExpando(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (!obj->is<UnboxedPlainObject>())
         return true;
 
     UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
     if (!expando)
@@ -428,17 +586,17 @@ GetPropIRGenerator::tryAttachUnboxedExpa
     emitted_ = true;
 
     EmitReadSlotResult(writer, obj, obj, shape, objId);
     EmitReadSlotReturn(writer, obj, obj, shape);
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachTypedObject(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (!obj->is<TypedObject>() ||
         !cx_->runtime()->jitSupportsFloatingPoint ||
         cx_->compartment()->detachedTypedObjects)
     {
         return true;
@@ -482,17 +640,17 @@ GetPropIRGenerator::tryAttachTypedObject
     else
         writer.returnFromIC();
 
     emitted_ = true;
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachObjectLength(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachObjectLength(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (name_ != cx_->names().length)
         return true;
 
     if (obj->is<ArrayObject>()) {
         // Make sure int32 is added to the TypeSet before we attach a stub, so
@@ -527,18 +685,17 @@ GetPropIRGenerator::tryAttachObjectLengt
         emitted_ = true;
         return true;
     }
 
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachModuleNamespace(CacheIRWriter& writer, HandleObject obj,
-                                             ObjOperandId objId)
+GetPropIRGenerator::tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (!obj->is<ModuleNamespaceObject>())
         return true;
 
     Rooted<ModuleNamespaceObject*> ns(cx_, &obj->as<ModuleNamespaceObject>());
     RootedModuleEnvironmentObject env(cx_);
@@ -560,17 +717,17 @@ GetPropIRGenerator::tryAttachModuleNames
 
     ObjOperandId envId = writer.loadObject(env);
     EmitLoadSlotResult(writer, envId, env, shape);
     writer.typeMonitorResult();
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachPrimitive(CacheIRWriter& writer, ValOperandId valId)
+GetPropIRGenerator::tryAttachPrimitive(ValOperandId valId)
 {
     MOZ_ASSERT(!emitted_);
 
     JSValueType primitiveType;
     RootedNativeObject proto(cx_);
     if (val_.isString()) {
         if (name_ == cx_->names().length) {
             // String length is special-cased, see js::GetProperty.
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -60,16 +60,17 @@ class OperandId
   public:
     uint16_t id() const { return id_; }
     bool valid() const { return id_ != InvalidId; }
 };
 
 class ValOperandId : public OperandId
 {
   public:
+    ValOperandId() = default;
     explicit ValOperandId(uint16_t id) : OperandId(id) {}
 };
 
 class ObjOperandId : public OperandId
 {
   public:
     ObjOperandId() = default;
     explicit ObjOperandId(uint16_t id) : OperandId(id) {}
@@ -80,98 +81,142 @@ class ObjOperandId : public OperandId
 
 #define CACHE_IR_OPS(_)                   \
     _(GuardIsObject)                      \
     _(GuardType)                          \
     _(GuardShape)                         \
     _(GuardGroup)                         \
     _(GuardProto)                         \
     _(GuardClass)                         \
+    _(GuardIsProxy)                       \
+    _(GuardNotDOMProxy)                   \
     _(GuardSpecificObject)                \
     _(GuardNoDetachedTypedObjects)        \
     _(GuardNoUnboxedExpando)              \
     _(GuardAndLoadUnboxedExpando)         \
     _(LoadObject)                         \
     _(LoadProto)                          \
                                           \
+    _(LoadDOMExpandoValue)                \
+    _(GuardDOMExpandoObject)              \
+    _(GuardDOMExpandoGeneration)          \
+                                          \
     /* The *Result ops load a value into the cache's result register. */ \
     _(LoadFixedSlotResult)                \
     _(LoadDynamicSlotResult)              \
     _(LoadUnboxedPropertyResult)          \
     _(LoadTypedObjectResult)              \
     _(LoadInt32ArrayLengthResult)         \
     _(LoadUnboxedArrayLengthResult)       \
     _(LoadArgumentsObjectLengthResult)    \
     _(CallScriptedGetterResult)           \
     _(CallNativeGetterResult)             \
+    _(CallProxyGetResult)                 \
     _(LoadUndefinedResult)                \
                                           \
     _(TypeMonitorResult)                  \
     _(ReturnFromIC)
 
 enum class CacheOp {
 #define DEFINE_OP(op) op,
     CACHE_IR_OPS(DEFINE_OP)
 #undef DEFINE_OP
 };
 
-struct StubField {
-    enum class GCType {
-        NoGCThing,
+class StubField
+{
+  public:
+    enum class Type : uint8_t {
+        // These fields take up a single word.
+        RawWord,
         Shape,
         ObjectGroup,
         JSObject,
+        Id,
+
+        // These fields take up 64 bits on all platforms.
+        RawInt64,
+        First64BitType = RawInt64,
+        Value,
+
         Limit
     };
 
-    uintptr_t word;
-    GCType gcType;
+    static bool sizeIsWord(Type type) {
+        MOZ_ASSERT(type != Type::Limit);
+        return type < Type::First64BitType;
+    }
+    static bool sizeIsInt64(Type type) {
+        MOZ_ASSERT(type != Type::Limit);
+        return type >= Type::First64BitType;
+    }
+    static size_t sizeInBytes(Type type) {
+        if (sizeIsWord(type))
+            return sizeof(uintptr_t);
+        MOZ_ASSERT(sizeIsInt64(type));
+        return sizeof(int64_t);
+    }
 
-    StubField(uintptr_t word, GCType gcType)
-      : word(word), gcType(gcType)
-    {}
-};
+  private:
+    union {
+        uintptr_t dataWord_;
+        uint64_t dataInt64_;
+    };
+    Type type_;
+
+    bool sizeIsWord() const { return sizeIsWord(type_); }
+    bool sizeIsInt64() const { return sizeIsInt64(type_); }
+
+  public:
+    StubField(uint64_t data, Type type)
+      : dataInt64_(data), type_(type)
+    {
+        MOZ_ASSERT_IF(sizeIsWord(), data <= UINTPTR_MAX);
+    }
+
+    Type type() const { return type_; }
+
+    uintptr_t asWord() const { MOZ_ASSERT(sizeIsWord()); return dataWord_; }
+    uint64_t asInt64() const { MOZ_ASSERT(sizeIsInt64()); return dataInt64_; }
+} JS_HAZ_GC_POINTER;
 
 // We use this enum as GuardClass operand, instead of storing Class* pointers
 // in the IR, to keep the IR compact and the same size on all platforms.
 enum class GuardClassKind : uint8_t
 {
     Array,
     UnboxedArray,
     MappedArguments,
     UnmappedArguments,
     WindowProxy,
 };
 
 // Class to record CacheIR + some additional metadata for code generation.
-class MOZ_RAII CacheIRWriter
+class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
 {
     CompactBufferWriter buffer_;
 
     uint32_t nextOperandId_;
     uint32_t nextInstructionId_;
     uint32_t numInputOperands_;
 
     // The data (shapes, slot offsets, etc.) that will be stored in the ICStub.
     Vector<StubField, 8, SystemAllocPolicy> stubFields_;
+    size_t stubDataSize_;
 
     // For each operand id, record which instruction accessed it last. This
     // information greatly improves register allocation.
     Vector<uint32_t, 8, SystemAllocPolicy> operandLastUsed_;
 
     // OperandId and stub offsets are stored in a single byte, so make sure
     // this doesn't overflow. We use a very conservative limit for now.
     static const size_t MaxOperandIds = 20;
-    static const size_t MaxStubFields = 20;
+    static const size_t MaxStubDataSizeInBytes = 20 * sizeof(uintptr_t);
     bool tooLarge_;
 
-    // stubFields_ contains unrooted pointers, so ensure we cannot GC in
-    // our scope.
-    JS::AutoCheckCannotGC nogc;
-
     void writeOp(CacheOp op) {
         MOZ_ASSERT(uint32_t(op) <= UINT8_MAX);
         buffer_.writeByte(uint32_t(op));
         nextInstructionId_++;
     }
 
     void writeOperandId(OperandId opId) {
         if (opId.id() < MaxOperandIds) {
@@ -190,54 +235,64 @@ class MOZ_RAII CacheIRWriter
         operandLastUsed_[opId.id()] = nextInstructionId_ - 1;
     }
 
     void writeOpWithOperandId(CacheOp op, OperandId opId) {
         writeOp(op);
         writeOperandId(opId);
     }
 
-    void addStubWord(uintptr_t word, StubField::GCType gcType) {
-        uint32_t pos = stubFields_.length();
-        buffer_.propagateOOM(stubFields_.append(StubField(word, gcType)));
-        if (pos < MaxStubFields)
-            buffer_.writeByte(pos);
-        else
+    void addStubField(uint64_t value, StubField::Type fieldType) {
+        size_t newStubDataSize = stubDataSize_ + StubField::sizeInBytes(fieldType);
+        if (newStubDataSize < MaxStubDataSizeInBytes) {
+            buffer_.propagateOOM(stubFields_.append(StubField(value, fieldType)));
+            MOZ_ASSERT((stubDataSize_ % sizeof(uintptr_t)) == 0);
+            buffer_.writeByte(stubDataSize_ / sizeof(uintptr_t));
+            stubDataSize_ = newStubDataSize;
+        } else {
             tooLarge_ = true;
+        }
     }
 
     CacheIRWriter(const CacheIRWriter&) = delete;
     CacheIRWriter& operator=(const CacheIRWriter&) = delete;
 
   public:
-    CacheIRWriter()
-      : nextOperandId_(0),
+    explicit CacheIRWriter(JSContext* cx)
+      : CustomAutoRooter(cx),
+        nextOperandId_(0),
         nextInstructionId_(0),
         numInputOperands_(0),
+        stubDataSize_(0),
         tooLarge_(false)
     {}
 
     bool failed() const { return buffer_.oom() || tooLarge_; }
 
     uint32_t numInputOperands() const { return numInputOperands_; }
     uint32_t numOperandIds() const { return nextOperandId_; }
     uint32_t numInstructions() const { return nextInstructionId_; }
 
     size_t numStubFields() const { return stubFields_.length(); }
-    StubField::GCType stubFieldGCType(uint32_t i) const { return stubFields_[i].gcType; }
+    StubField::Type stubFieldType(uint32_t i) const { return stubFields_[i].type(); }
 
     uint32_t setInputOperandId(uint32_t op) {
         MOZ_ASSERT(op == nextOperandId_);
         nextOperandId_++;
         numInputOperands_++;
         return op;
     }
 
+    void trace(JSTracer* trc) override {
+        // For now, assert we only GC before we append stub fields.
+        MOZ_RELEASE_ASSERT(stubFields_.empty());
+    }
+
     size_t stubDataSize() const {
-        return stubFields_.length() * sizeof(uintptr_t);
+        return stubDataSize_;
     }
     void copyStubData(uint8_t* dest) const;
 
     bool operandIsDead(uint32_t operandId, uint32_t currentInstruction) const {
         if (operandId >= operandLastUsed_.length())
             return false;
         return currentInstruction > operandLastUsed_[operandId];
     }
@@ -257,35 +312,41 @@ class MOZ_RAII CacheIRWriter
     }
     void guardType(ValOperandId val, JSValueType type) {
         writeOpWithOperandId(CacheOp::GuardType, val);
         static_assert(sizeof(type) == sizeof(uint8_t), "JSValueType should fit in a byte");
         buffer_.writeByte(uint32_t(type));
     }
     void guardShape(ObjOperandId obj, Shape* shape) {
         writeOpWithOperandId(CacheOp::GuardShape, obj);
-        addStubWord(uintptr_t(shape), StubField::GCType::Shape);
+        addStubField(uintptr_t(shape), StubField::Type::Shape);
     }
     void guardGroup(ObjOperandId obj, ObjectGroup* group) {
         writeOpWithOperandId(CacheOp::GuardGroup, obj);
-        addStubWord(uintptr_t(group), StubField::GCType::ObjectGroup);
+        addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
     }
     void guardProto(ObjOperandId obj, JSObject* proto) {
         writeOpWithOperandId(CacheOp::GuardProto, obj);
-        addStubWord(uintptr_t(proto), StubField::GCType::JSObject);
+        addStubField(uintptr_t(proto), StubField::Type::JSObject);
     }
     void guardClass(ObjOperandId obj, GuardClassKind kind) {
         static_assert(sizeof(GuardClassKind) == sizeof(uint8_t),
                       "GuardClassKind must fit in a byte");
         writeOpWithOperandId(CacheOp::GuardClass, obj);
         buffer_.writeByte(uint32_t(kind));
     }
+    void guardIsProxy(ObjOperandId obj) {
+        writeOpWithOperandId(CacheOp::GuardIsProxy, obj);
+    }
+    void guardNotDOMProxy(ObjOperandId obj) {
+        writeOpWithOperandId(CacheOp::GuardNotDOMProxy, obj);
+    }
     void guardSpecificObject(ObjOperandId obj, JSObject* expected) {
         writeOpWithOperandId(CacheOp::GuardSpecificObject, obj);
-        addStubWord(uintptr_t(expected), StubField::GCType::JSObject);
+        addStubField(uintptr_t(expected), StubField::Type::JSObject);
     }
     void guardNoDetachedTypedObjects() {
         writeOp(CacheOp::GuardNoDetachedTypedObjects);
     }
     void guardNoUnboxedExpando(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::GuardNoUnboxedExpando, obj);
     }
     ObjOperandId guardAndLoadUnboxedExpando(ObjOperandId obj) {
@@ -293,67 +354,93 @@ class MOZ_RAII CacheIRWriter
         writeOpWithOperandId(CacheOp::GuardAndLoadUnboxedExpando, obj);
         writeOperandId(res);
         return res;
     }
 
     ObjOperandId loadObject(JSObject* obj) {
         ObjOperandId res(nextOperandId_++);
         writeOpWithOperandId(CacheOp::LoadObject, res);
-        addStubWord(uintptr_t(obj), StubField::GCType::JSObject);
+        addStubField(uintptr_t(obj), StubField::Type::JSObject);
         return res;
     }
     ObjOperandId loadProto(ObjOperandId obj) {
         ObjOperandId res(nextOperandId_++);
         writeOpWithOperandId(CacheOp::LoadProto, obj);
         writeOperandId(res);
         return res;
     }
 
+    ValOperandId loadDOMExpandoValue(ObjOperandId obj) {
+        ValOperandId res(nextOperandId_++);
+        writeOpWithOperandId(CacheOp::LoadDOMExpandoValue, obj);
+        writeOperandId(res);
+        return res;
+    }
+    void guardDOMExpandoObject(ValOperandId expando, Shape* shape) {
+        writeOpWithOperandId(CacheOp::GuardDOMExpandoObject, expando);
+        addStubField(uintptr_t(shape), StubField::Type::Shape);
+    }
+    ValOperandId guardDOMExpandoGeneration(ObjOperandId obj,
+                                           ExpandoAndGeneration* expandoAndGeneration,
+                                           uint64_t generation)
+    {
+        ValOperandId res(nextOperandId_++);
+        writeOpWithOperandId(CacheOp::GuardDOMExpandoGeneration, obj);
+        addStubField(uintptr_t(expandoAndGeneration), StubField::Type::RawWord);
+        addStubField(generation, StubField::Type::RawInt64);
+        writeOperandId(res);
+        return res;
+    }
+
     void loadUndefinedResult() {
         writeOp(CacheOp::LoadUndefinedResult);
     }
     void loadFixedSlotResult(ObjOperandId obj, size_t offset) {
         writeOpWithOperandId(CacheOp::LoadFixedSlotResult, obj);
-        addStubWord(offset, StubField::GCType::NoGCThing);
+        addStubField(offset, StubField::Type::RawWord);
     }
     void loadDynamicSlotResult(ObjOperandId obj, size_t offset) {
         writeOpWithOperandId(CacheOp::LoadDynamicSlotResult, obj);
-        addStubWord(offset, StubField::GCType::NoGCThing);
+        addStubField(offset, StubField::Type::RawWord);
     }
     void loadUnboxedPropertyResult(ObjOperandId obj, JSValueType type, size_t offset) {
         writeOpWithOperandId(CacheOp::LoadUnboxedPropertyResult, obj);
         buffer_.writeByte(uint32_t(type));
-        addStubWord(offset, StubField::GCType::NoGCThing);
+        addStubField(offset, StubField::Type::RawWord);
     }
     void loadTypedObjectResult(ObjOperandId obj, uint32_t offset, TypedThingLayout layout,
                                uint32_t typeDescr) {
         MOZ_ASSERT(uint32_t(layout) <= UINT8_MAX);
         MOZ_ASSERT(typeDescr <= UINT8_MAX);
         writeOpWithOperandId(CacheOp::LoadTypedObjectResult, obj);
         buffer_.writeByte(uint32_t(layout));
         buffer_.writeByte(typeDescr);
-        addStubWord(offset, StubField::GCType::NoGCThing);
+        addStubField(offset, StubField::Type::RawWord);
     }
     void loadInt32ArrayLengthResult(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::LoadInt32ArrayLengthResult, obj);
     }
     void loadUnboxedArrayLengthResult(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::LoadUnboxedArrayLengthResult, obj);
     }
     void loadArgumentsObjectLengthResult(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::LoadArgumentsObjectLengthResult, obj);
     }
     void callScriptedGetterResult(ObjOperandId obj, JSFunction* getter) {
         writeOpWithOperandId(CacheOp::CallScriptedGetterResult, obj);
-        addStubWord(uintptr_t(getter), StubField::GCType::JSObject);
+        addStubField(uintptr_t(getter), StubField::Type::JSObject);
     }
     void callNativeGetterResult(ObjOperandId obj, JSFunction* getter) {
         writeOpWithOperandId(CacheOp::CallNativeGetterResult, obj);
-        addStubWord(uintptr_t(getter), StubField::GCType::JSObject);
+        addStubField(uintptr_t(getter), StubField::Type::JSObject);
+    }
+    void callProxyGetResult(ObjOperandId obj, jsid id) {
+        writeOpWithOperandId(CacheOp::CallProxyGetResult, obj);
+        addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id);
     }
 
     void typeMonitorResult() {
         writeOp(CacheOp::TypeMonitorResult);
     }
     void returnFromIC() {
         writeOp(CacheOp::ReturnFromIC);
     }
@@ -386,17 +473,17 @@ class MOZ_RAII CacheIRReader
 
     ValOperandId valOperandId() {
         return ValOperandId(buffer_.readByte());
     }
     ObjOperandId objOperandId() {
         return ObjOperandId(buffer_.readByte());
     }
 
-    uint32_t stubOffset() { return buffer_.readByte(); }
+    uint32_t stubOffset() { return buffer_.readByte() * sizeof(uintptr_t); }
     GuardClassKind guardClassKind() { return GuardClassKind(buffer_.readByte()); }
     JSValueType valueType() { return JSValueType(buffer_.readByte()); }
     TypedThingLayout typedThingLayout() { return TypedThingLayout(buffer_.readByte()); }
     uint32_t typeDescrKey() { return buffer_.readByte(); }
 
     bool matchOp(CacheOp op) {
         const uint8_t* pos = buffer_.currentPosition();
         if (readOp() == op)
@@ -419,61 +506,65 @@ class MOZ_RAII CacheIRReader
         buffer_.seek(pos, 0);
         return false;
     }
 };
 
 // GetPropIRGenerator generates CacheIR for a GetProp IC.
 class MOZ_RAII GetPropIRGenerator
 {
+    CacheIRWriter writer;
     JSContext* cx_;
     jsbytecode* pc_;
     HandleValue val_;
     HandlePropertyName name_;
     MutableHandleValue res_;
     ICStubEngine engine_;
     bool* isTemporarilyUnoptimizable_;
     bool emitted_;
 
     enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
     PreliminaryObjectAction preliminaryObjectAction_;
 
-    MOZ_MUST_USE bool tryAttachNative(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachUnboxed(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachUnboxedExpando(CacheIRWriter& writer, HandleObject obj,
-                                              ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj,
-                                           ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachObjectLength(CacheIRWriter& writer, HandleObject obj,
-                                            ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachModuleNamespace(CacheIRWriter& writer, HandleObject obj,
-                                               ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachWindowProxy(CacheIRWriter& writer, HandleObject obj,
-                                           ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachNative(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachUnboxed(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachTypedObject(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachObjectLength(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId);
 
-    MOZ_MUST_USE bool tryAttachPrimitive(CacheIRWriter& writer, ValOperandId valId);
+    MOZ_MUST_USE bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachProxy(HandleObject obj, ObjOperandId objId);
+
+    MOZ_MUST_USE bool tryAttachPrimitive(ValOperandId valId);
 
     GetPropIRGenerator(const GetPropIRGenerator&) = delete;
     GetPropIRGenerator& operator=(const GetPropIRGenerator&) = delete;
 
   public:
     GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine,
                        bool* isTemporarilyUnoptimizable,
                        HandleValue val, HandlePropertyName name, MutableHandleValue res);
 
     bool emitted() const { return emitted_; }
 
-    MOZ_MUST_USE bool tryAttachStub(mozilla::Maybe<CacheIRWriter>& writer);
+    MOZ_MUST_USE bool tryAttachStub();
 
     bool shouldUnlinkPreliminaryObjectStubs() const {
         return preliminaryObjectAction_ == PreliminaryObjectAction::Unlink;
     }
     bool shouldNotePreliminaryObjectStub() const {
         return preliminaryObjectAction_ == PreliminaryObjectAction::NotePreliminary;
     }
+    const CacheIRWriter& writerRef() const {
+        return writer;
+    }
 };
 
 enum class CacheKind : uint8_t
 {
     GetProp
 };
 
 } // namespace jit
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1681,23 +1681,16 @@ static void
 PushObjectOpResult(MacroAssembler& masm)
 {
     static_assert(sizeof(ObjectOpResult) == sizeof(uintptr_t),
                   "ObjectOpResult size must match size reserved by masm.Push() here");
     masm.Push(ImmWord(ObjectOpResult::Uninitialized));
 }
 
 static bool
-ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
-{
-    RootedValue receiver(cx, ObjectValue(*proxy));
-    return Proxy::get(cx, proxy, receiver, id, vp);
-}
-
-static bool
 EmitCallProxyGet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher,
                  jsid id, LiveRegisterSet liveRegs, Register object, TypedOrValueRegister output,
                  jsbytecode* pc, void* returnAddr)
 {
     MOZ_ASSERT(output.hasValue());
     MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs);
 
     // Remaining registers should be free, but we need to use |object| still
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1333,25 +1333,27 @@ TraceJitExitFrame(JSTracer* trc, const J
           case VMFunction::RootObject: {
             // Sometimes we can bake in HandleObjects to nullptr.
             JSObject** pobj = reinterpret_cast<JSObject**>(argBase);
             if (*pobj)
                 TraceRoot(trc, pobj, "ion-vm-args");
             break;
           }
           case VMFunction::RootString:
-          case VMFunction::RootPropertyName:
             TraceRoot(trc, reinterpret_cast<JSString**>(argBase), "ion-vm-args");
             break;
           case VMFunction::RootFunction:
             TraceRoot(trc, reinterpret_cast<JSFunction**>(argBase), "ion-vm-args");
             break;
           case VMFunction::RootValue:
             TraceRoot(trc, reinterpret_cast<Value*>(argBase), "ion-vm-args");
             break;
+          case VMFunction::RootId:
+            TraceRoot(trc, reinterpret_cast<jsid*>(argBase), "ion-vm-args");
+            break;
           case VMFunction::RootCell:
             TraceGenericPointerRoot(trc, reinterpret_cast<gc::Cell**>(argBase), "ion-vm-args");
             break;
         }
 
         switch (f->argProperties(explicitArg)) {
           case VMFunction::WordByValue:
           case VMFunction::WordByRef:
@@ -1367,25 +1369,27 @@ TraceJitExitFrame(JSTracer* trc, const J
     if (f->outParam == Type_Handle) {
         switch (f->outParamRootType) {
           case VMFunction::RootNone:
             MOZ_CRASH("Handle outparam must have root type");
           case VMFunction::RootObject:
             TraceRoot(trc, footer->outParam<JSObject*>(), "ion-vm-out");
             break;
           case VMFunction::RootString:
-          case VMFunction::RootPropertyName:
             TraceRoot(trc, footer->outParam<JSString*>(), "ion-vm-out");
             break;
           case VMFunction::RootFunction:
             TraceRoot(trc, footer->outParam<JSFunction*>(), "ion-vm-out");
             break;
           case VMFunction::RootValue:
             TraceRoot(trc, footer->outParam<Value>(), "ion-vm-outvp");
             break;
+          case VMFunction::RootId:
+            TraceRoot(trc, footer->outParam<jsid>(), "ion-vm-outvp");
+            break;
           case VMFunction::RootCell:
             TraceGenericPointerRoot(trc, footer->outParam<gc::Cell*>(), "ion-vm-out");
             break;
         }
     }
 
     TraceJitExitFrameCopiedArguments(trc, f, footer);
 }
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2501,39 +2501,41 @@ MacroAssembler::PushValue(const Address&
 void
 MacroAssembler::PushEmptyRooted(VMFunction::RootType rootType)
 {
     switch (rootType) {
       case VMFunction::RootNone:
         MOZ_CRASH("Handle must have root type");
       case VMFunction::RootObject:
       case VMFunction::RootString:
-      case VMFunction::RootPropertyName:
       case VMFunction::RootFunction:
       case VMFunction::RootCell:
         Push(ImmPtr(nullptr));
         break;
       case VMFunction::RootValue:
         Push(UndefinedValue());
         break;
+      case VMFunction::RootId:
+        Push(ImmWord(JSID_BITS(JSID_VOID)));
+        break;
     }
 }
 
 void
 MacroAssembler::popRooted(VMFunction::RootType rootType, Register cellReg,
                           const ValueOperand& valueReg)
 {
     switch (rootType) {
       case VMFunction::RootNone:
         MOZ_CRASH("Handle must have root type");
       case VMFunction::RootObject:
       case VMFunction::RootString:
-      case VMFunction::RootPropertyName:
       case VMFunction::RootFunction:
       case VMFunction::RootCell:
+      case VMFunction::RootId:
         Pop(cellReg);
         break;
       case VMFunction::RootValue:
         Pop(valueReg);
         break;
     }
 }
 
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -180,19 +180,16 @@ ICStub::NonCacheIRStubMakesGCCalls(Kind 
       case GetElem_NativePrototypeSlotName:
       case GetElem_NativePrototypeSlotSymbol:
       case GetElem_NativePrototypeCallNativeName:
       case GetElem_NativePrototypeCallNativeSymbol:
       case GetElem_NativePrototypeCallScriptedName:
       case GetElem_NativePrototypeCallScriptedSymbol:
       case GetElem_UnboxedPropertyName:
       case GetProp_CallNativeGlobal:
-      case GetProp_CallDOMProxyNative:
-      case GetProp_CallDOMProxyWithGenerationNative:
-      case GetProp_DOMProxyShadowed:
       case GetProp_Generic:
       case SetProp_CallScripted:
       case SetProp_CallNative:
       case RetSub_Fallback:
       // These two fallback stubs don't actually make non-tail calls,
       // but the fallback code for the bailout path needs to pop the stub frame
       // pushed during the bailout.
       case GetProp_Fallback:
@@ -460,37 +457,16 @@ ICStub::trace(JSTracer* trc)
       case ICStub::GetName_Env6:
         static_cast<ICGetName_Env<6>*>(this)->traceEnvironments(trc);
         break;
       case ICStub::GetIntrinsic_Constant: {
         ICGetIntrinsic_Constant* constantStub = toGetIntrinsic_Constant();
         TraceEdge(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
         break;
       }
-      case ICStub::GetProp_CallDOMProxyNative:
-      case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
-        ICGetPropCallDOMProxyNativeStub* propStub;
-        if (kind() == ICStub::GetProp_CallDOMProxyNative)
-            propStub = toGetProp_CallDOMProxyNative();
-        else
-            propStub = toGetProp_CallDOMProxyWithGenerationNative();
-        propStub->receiverGuard().trace(trc);
-        TraceNullableEdge(trc, &propStub->expandoShape(),
-                          "baseline-getproplistbasenative-stub-expandoshape");
-        TraceEdge(trc, &propStub->holder(), "baseline-getproplistbasenative-stub-holder");
-        TraceEdge(trc, &propStub->holderShape(), "baseline-getproplistbasenative-stub-holdershape");
-        TraceEdge(trc, &propStub->getter(), "baseline-getproplistbasenative-stub-getter");
-        break;
-      }
-      case ICStub::GetProp_DOMProxyShadowed: {
-        ICGetProp_DOMProxyShadowed* propStub = toGetProp_DOMProxyShadowed();
-        TraceEdge(trc, &propStub->shape(), "baseline-getproplistbaseshadowed-stub-shape");
-        TraceEdge(trc, &propStub->name(), "baseline-getproplistbaseshadowed-stub-name");
-        break;
-      }
       case ICStub::GetProp_CallNativeGlobal: {
         ICGetProp_CallNativeGlobal* callStub = toGetProp_CallNativeGlobal();
         callStub->receiverGuard().trace(trc);
         TraceEdge(trc, &callStub->holder(), "baseline-getpropcallnativeglobal-stub-holder");
         TraceEdge(trc, &callStub->holderShape(), "baseline-getpropcallnativeglobal-stub-holdershape");
         TraceEdge(trc, &callStub->globalShape(), "baseline-getpropcallnativeglobal-stub-globalshape");
         TraceEdge(trc, &callStub->getter(), "baseline-getpropcallnativeglobal-stub-getter");
         break;
@@ -2148,42 +2124,16 @@ TryAttachLengthStub(JSContext* cx, Share
         *attached = true;
         stub->addNewStub(newStub);
         return true;
     }
 
     return true;
 }
 
-static bool
-UpdateExistingGenerationalDOMProxyStub(ICGetProp_Fallback* stub,
-                                       HandleObject obj)
-{
-    Value expandoSlot = GetProxyExtra(obj, GetDOMProxyExpandoSlot());
-    MOZ_ASSERT(!expandoSlot.isObject() && !expandoSlot.isUndefined());
-    ExpandoAndGeneration* expandoAndGeneration = (ExpandoAndGeneration*)expandoSlot.toPrivate();
-    for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
-        if (iter->isGetProp_CallDOMProxyWithGenerationNative()) {
-            ICGetProp_CallDOMProxyWithGenerationNative* updateStub =
-                iter->toGetProp_CallDOMProxyWithGenerationNative();
-            if (updateStub->expandoAndGeneration() == expandoAndGeneration) {
-                // Update generation
-                uint64_t generation = expandoAndGeneration->generation;
-                JitSpew(JitSpew_BaselineIC,
-                        "  Updating existing stub with generation, old value: %" PRIu64 ", "
-                        "new value: %" PRIu64 "", updateStub->generation(),
-                        generation);
-                updateStub->setGeneration(generation);
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
 // Return whether obj is in some PreliminaryObjectArray and has a structure
 // that might change in the future.
 bool
 IsPreliminaryObject(JSObject* obj)
 {
     if (obj->isSingleton())
         return false;
 
@@ -2224,56 +2174,22 @@ GetDOMProxyProto(JSObject* obj)
     return obj->staticPrototype();
 }
 
 // Look up a property's shape on an object, being careful never to do any effectful
 // operations.  This procedure not yielding a shape should not be taken as a lack of
 // existence of the property on the object.
 bool
 EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId id,
-                           MutableHandleObject holder, MutableHandleShape shape,
-                           bool* checkDOMProxy,
-                           DOMProxyShadowsResult* shadowsResult,
-                           bool* domProxyHasGeneration)
+                           MutableHandleObject holder, MutableHandleShape shape)
 {
     shape.set(nullptr);
     holder.set(nullptr);
 
-    if (checkDOMProxy) {
-        *checkDOMProxy = false;
-        *shadowsResult = ShadowCheckFailed;
-    }
-
-    // Check for list base if asked to.
-    RootedObject checkObj(cx, obj);
-    if (checkDOMProxy && IsCacheableDOMProxy(obj)) {
-        MOZ_ASSERT(domProxyHasGeneration);
-        MOZ_ASSERT(shadowsResult);
-
-        *checkDOMProxy = true;
-        if (obj->hasUncacheableProto())
-            return true;
-
-        *shadowsResult = GetDOMProxyShadowsCheck()(cx, obj, id);
-        if (*shadowsResult == ShadowCheckFailed)
-            return false;
-
-        if (DOMProxyIsShadowing(*shadowsResult)) {
-            holder.set(obj);
-            return true;
-        }
-
-        *domProxyHasGeneration = (*shadowsResult == DoesntShadowUnique);
-
-        checkObj = GetDOMProxyProto(obj);
-        if (!checkObj)
-            return true;
-    }
-
-    if (LookupPropertyPure(cx, checkObj, id, holder.address(), shape.address()))
+    if (LookupPropertyPure(cx, obj, id, holder.address(), shape.address()))
         return true;
 
     holder.set(nullptr);
     shape.set(nullptr);
     return true;
 }
 
 bool
@@ -2426,110 +2342,16 @@ UpdateExistingGetPropCallStubs(ICFallbac
                     foundMatchingStub = true;
             }
         }
     }
 
     return foundMatchingStub;
 }
 
-static bool
-TryAttachNativeGetAccessorPropStub(JSContext* cx, SharedStubInfo* info,
-                                   ICGetProp_Fallback* stub, HandlePropertyName name,
-                                   HandleValue val, HandleValue res, bool* attached,
-                                   bool* isTemporarilyUnoptimizable)
-{
-    MOZ_ASSERT(!*attached);
-    MOZ_ASSERT(!*isTemporarilyUnoptimizable);
-
-    if (!val.isObject())
-        return true;
-
-    RootedObject obj(cx, &val.toObject());
-
-    bool isDOMProxy;
-    bool domProxyHasGeneration;
-    DOMProxyShadowsResult domProxyShadowsResult;
-    RootedShape shape(cx);
-    RootedObject holder(cx);
-    RootedId id(cx, NameToId(name));
-    if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape, &isDOMProxy,
-                                    &domProxyShadowsResult, &domProxyHasGeneration))
-    {
-        return false;
-    }
-
-    ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
-
-    bool isScripted = false;
-    bool cacheableCall = IsCacheableGetPropCall(cx, obj, holder, shape, &isScripted,
-                                                isTemporarilyUnoptimizable,
-                                                isDOMProxy);
-
-    // If it's a shadowed listbase proxy property, attach stub to call Proxy::get instead.
-    if (isDOMProxy && DOMProxyIsShadowing(domProxyShadowsResult)) {
-        MOZ_ASSERT(obj == holder);
-
-        JitSpew(JitSpew_BaselineIC, "  Generating GetProp(DOMProxyProxy) stub");
-        Rooted<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
-        ICGetProp_DOMProxyShadowed::Compiler compiler(cx, info->engine(), monitorStub, proxy, name,
-                                                      info->pcOffset());
-        ICStub* newStub = compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));
-        if (!newStub)
-            return false;
-        stub->addNewStub(newStub);
-        *attached = true;
-        return true;
-    }
-
-    // Try handling JSNative getters.
-    if (!cacheableCall || isScripted)
-        return true;
-
-    if (!shape || !shape->hasGetterValue() || !shape->getterValue().isObject() ||
-        !shape->getterObject()->is<JSFunction>())
-    {
-        return true;
-    }
-
-    RootedFunction callee(cx, &shape->getterObject()->as<JSFunction>());
-    MOZ_ASSERT(callee->isNative());
-
-    JitSpew(JitSpew_BaselineIC, "  Generating GetProp(%s%s/NativeGetter %p) stub",
-            isDOMProxy ? "DOMProxyObj" : "NativeObj",
-            isDOMProxy && domProxyHasGeneration ? "WithGeneration" : "",
-            callee->native());
-
-    ICStub* newStub = nullptr;
-    if (isDOMProxy) {
-        MOZ_ASSERT(obj != holder);
-        ICStub::Kind kind;
-        if (domProxyHasGeneration) {
-            if (UpdateExistingGenerationalDOMProxyStub(stub, obj)) {
-                *attached = true;
-                return true;
-            }
-            kind = ICStub::GetProp_CallDOMProxyWithGenerationNative;
-        } else {
-            kind = ICStub::GetProp_CallDOMProxyNative;
-        }
-        Rooted<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
-        ICGetPropCallDOMProxyNativeCompiler compiler(cx, kind, info->engine(), monitorStub, proxy, holder,
-                                                     callee, info->pcOffset());
-        newStub = compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));
-    } else {
-        return true;
-    }
-    if (!newStub)
-        return false;
-    stub->addNewStub(newStub);
-    *attached = true;
-    return true;
-}
-
 bool
 CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name,
                        JSObject** lastProto, size_t* protoChainDepthOut)
 {
     size_t depth = 0;
     JSObject* curObj = obj;
     while (curObj) {
         if (curObj->isNative()) {
@@ -2644,41 +2466,33 @@ DoGetPropFallback(JSContext* cx, void* p
         ICStub* newStub = compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));
         if (!newStub)
             return false;
         stub->addNewStub(newStub);
         attached = true;
     }
 
     if (!attached && !JitOptions.disableCacheIR) {
-        mozilla::Maybe<CacheIRWriter> writer;
         GetPropIRGenerator gen(cx, pc, engine, &isTemporarilyUnoptimizable, val, name, res);
-        if (!gen.tryAttachStub(writer))
+        if (!gen.tryAttachStub())
             return false;
         if (gen.emitted()) {
-            ICStub* newStub = AttachBaselineCacheIRStub(cx, writer.ref(), CacheKind::GetProp,
+            ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), CacheKind::GetProp,
                                                         engine, info.outerScript(cx), stub);
             if (newStub) {
                 JitSpew(JitSpew_BaselineIC, "  Attached CacheIR stub");
                 attached = true;
                 if (gen.shouldNotePreliminaryObjectStub())
                     newStub->toCacheIR_Monitored()->notePreliminaryObject();
                 else if (gen.shouldUnlinkPreliminaryObjectStubs())
                     StripPreliminaryObjectStubs(cx, stub);
             }
         }
     }
 
-    if (!attached && !stub.invalid() && !isTemporarilyUnoptimizable &&
-        !TryAttachNativeGetAccessorPropStub(cx, &info, stub, name, val, res, &attached,
-                                            &isTemporarilyUnoptimizable))
-    {
-        return false;
-    }
-
     if (!ComputeGetPropResult(cx, info.maybeFrame(), op, name, val, res))
         return false;
 
     TypeScript::Monitor(cx, script, pc, res);
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
@@ -3060,277 +2874,16 @@ ICGetPropCallNativeCompiler::getStub(ICS
                                                    getter_, pcOffset_);
       }
 
       default:
         MOZ_CRASH("Bad stub kind");
     }
 }
 
-// Callers are expected to have already guarded on the shape of the
-// object, which guarantees the object is a DOM proxy.
-void
-CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, Register object,
-                                  const Address& checkExpandoShapeAddr,
-                                  Address* expandoAndGenerationAddr,
-                                  Address* generationAddr,
-                                  Register scratch,
-                                  AllocatableGeneralRegisterSet& domProxyRegSet,
-                                  Label* checkFailed)
-{
-    // Guard that the object does not have expando properties, or has an expando
-    // which is known to not have the desired property.
-
-    // For the remaining code, we need to reserve some registers to load a value.
-    // This is ugly, but unavoidable.
-    ValueOperand tempVal = domProxyRegSet.takeAnyValue();
-    masm.pushValue(tempVal);
-
-    Label failDOMProxyCheck;
-    Label domProxyOk;
-
-    masm.loadPtr(Address(object, ProxyObject::offsetOfValues()), scratch);
-    Address expandoAddr(scratch, ProxyObject::offsetOfExtraSlotInValues(GetDOMProxyExpandoSlot()));
-
-    if (expandoAndGenerationAddr) {
-        MOZ_ASSERT(generationAddr);
-
-        masm.loadPtr(*expandoAndGenerationAddr, tempVal.scratchReg());
-        masm.branchPrivatePtr(Assembler::NotEqual, expandoAddr, tempVal.scratchReg(),
-                              &failDOMProxyCheck);
-
-        masm.branch64(Assembler::NotEqual,
-                      Address(tempVal.scratchReg(), ExpandoAndGeneration::offsetOfGeneration()),
-                      *generationAddr,
-                      scratch, &failDOMProxyCheck);
-
-        masm.loadValue(Address(tempVal.scratchReg(), 0), tempVal);
-    } else {
-        masm.loadValue(expandoAddr, tempVal);
-    }
-
-    // If the incoming object does not have an expando object then we're sure we're not
-    // shadowing.
-    masm.branchTestUndefined(Assembler::Equal, tempVal, &domProxyOk);
-
-    // The reference object used to generate this check may not have had an
-    // expando object at all, in which case the presence of a non-undefined
-    // expando value in the incoming object is automatically a failure.
-    masm.loadPtr(checkExpandoShapeAddr, scratch);
-    masm.branchPtr(Assembler::Equal, scratch, ImmPtr(nullptr), &failDOMProxyCheck);
-
-    // Otherwise, ensure that the incoming object has an object for its expando value and that
-    // the shape matches.
-    masm.branchTestObject(Assembler::NotEqual, tempVal, &failDOMProxyCheck);
-    Register objReg = masm.extractObject(tempVal, tempVal.scratchReg());
-    masm.branchTestObjShape(Assembler::Equal, objReg, scratch, &domProxyOk);
-
-    // Failure case: restore the tempVal registers and jump to failures.
-    masm.bind(&failDOMProxyCheck);
-    masm.popValue(tempVal);
-    masm.jump(checkFailed);
-
-    // Success case: restore the tempval and proceed.
-    masm.bind(&domProxyOk);
-    masm.popValue(tempVal);
-}
-
-bool
-ICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler& masm,
-                                                      Address* expandoAndGenerationAddr,
-                                                      Address* generationAddr)
-{
-    Label failure;
-    AllocatableGeneralRegisterSet regs(availableGeneralRegs(1));
-    Register scratch = regs.takeAnyExcluding(ICTailCallReg);
-
-    // Guard input is an object.
-    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
-
-    // Unbox.
-    Register objReg = masm.extractObject(R0, ExtractTemp0);
-
-    // Shape guard.
-    static const size_t receiverShapeOffset =
-        ICGetProp_CallDOMProxyNative::offsetOfReceiverGuard() +
-        HeapReceiverGuard::offsetOfShape();
-    masm.loadPtr(Address(ICStubReg, receiverShapeOffset), scratch);
-    masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
-
-    // Guard that our expando object hasn't started shadowing this property.
-    {
-        AllocatableGeneralRegisterSet domProxyRegSet(GeneralRegisterSet::All());
-        domProxyRegSet.take(ICStubReg);
-        domProxyRegSet.take(objReg);
-        domProxyRegSet.take(scratch);
-        Address expandoShapeAddr(ICStubReg, ICGetProp_CallDOMProxyNative::offsetOfExpandoShape());
-        CheckDOMProxyExpandoDoesNotShadow(
-                cx, masm, objReg,
-                expandoShapeAddr, expandoAndGenerationAddr, generationAddr,
-                scratch,
-                domProxyRegSet,
-                &failure);
-    }
-
-    Register holderReg = regs.takeAny();
-    masm.loadPtr(Address(ICStubReg, ICGetProp_CallDOMProxyNative::offsetOfHolder()),
-                 holderReg);
-    masm.loadPtr(Address(ICStubReg, ICGetProp_CallDOMProxyNative::offsetOfHolderShape()),
-                 scratch);
-    masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure);
-    regs.add(holderReg);
-
-    // Push a stub frame so that we can perform a non-tail call.
-    enterStubFrame(masm, scratch);
-
-    // Load callee function.
-    Register callee = regs.takeAny();
-    masm.loadPtr(Address(ICStubReg, ICGetProp_CallDOMProxyNative::offsetOfGetter()), callee);
-
-    // Push args for vm call.
-    masm.Push(objReg);
-    masm.Push(callee);
-
-    // Don't have to preserve R0 anymore.
-    regs.add(R0);
-
-    if (!callVM(DoCallNativeGetterInfo, masm))
-        return false;
-    leaveStubFrame(masm);
-
-    // Enter type monitor IC to type-check result.
-    EmitEnterTypeMonitorIC(masm);
-
-    // Failure case - jump to next stub
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-    return true;
-}
-
-bool
-ICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler& masm)
-{
-    if (kind == ICStub::GetProp_CallDOMProxyNative)
-        return generateStubCode(masm, nullptr, nullptr);
-
-    Address internalStructAddress(ICStubReg,
-        ICGetProp_CallDOMProxyWithGenerationNative::offsetOfInternalStruct());
-    Address generationAddress(ICStubReg,
-        ICGetProp_CallDOMProxyWithGenerationNative::offsetOfGeneration());
-    return generateStubCode(masm, &internalStructAddress, &generationAddress);
-}
-
-ICStub*
-ICGetPropCallDOMProxyNativeCompiler::getStub(ICStubSpace* space)
-{
-    RootedShape shape(cx, proxy_->maybeShape());
-    RootedShape holderShape(cx, holder_->as<NativeObject>().lastProperty());
-
-    Value expandoSlot = GetProxyExtra(proxy_, GetDOMProxyExpandoSlot());
-    RootedShape expandoShape(cx, nullptr);
-    ExpandoAndGeneration* expandoAndGeneration;
-    uint64_t generation;
-    Value expandoVal;
-    if (kind == ICStub::GetProp_CallDOMProxyNative) {
-        expandoVal = expandoSlot;
-        expandoAndGeneration = nullptr;  // initialize to silence GCC warning
-        generation = 0;  // initialize to silence GCC warning
-    } else {
-        MOZ_ASSERT(kind == ICStub::GetProp_CallDOMProxyWithGenerationNative);
-        MOZ_ASSERT(!expandoSlot.isObject() && !expandoSlot.isUndefined());
-        expandoAndGeneration = (ExpandoAndGeneration*)expandoSlot.toPrivate();
-        expandoVal = expandoAndGeneration->expando;
-        generation = expandoAndGeneration->generation;
-    }
-
-    if (expandoVal.isObject())
-        expandoShape = expandoVal.toObject().as<NativeObject>().lastProperty();
-
-    if (kind == ICStub::GetProp_CallDOMProxyNative) {
-        return newStub<ICGetProp_CallDOMProxyNative>(
-            space, getStubCode(), firstMonitorStub_, shape,
-            expandoShape, holder_, holderShape, getter_, pcOffset_);
-    }
-
-    return newStub<ICGetProp_CallDOMProxyWithGenerationNative>(
-        space, getStubCode(), firstMonitorStub_, shape,
-        expandoAndGeneration, generation, expandoShape, holder_, holderShape, getter_,
-        pcOffset_);
-}
-
-ICStub*
-ICGetProp_DOMProxyShadowed::Compiler::getStub(ICStubSpace* space)
-{
-    RootedShape shape(cx, proxy_->maybeShape());
-    return New<ICGetProp_DOMProxyShadowed>(cx, space, getStubCode(), firstMonitorStub_, shape,
-                                           proxy_->handler(), name_, pcOffset_);
-}
-
-static bool
-ProxyGet(JSContext* cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp)
-{
-    RootedValue receiver(cx, ObjectValue(*proxy));
-    RootedId id(cx, NameToId(name));
-    return Proxy::get(cx, proxy, receiver, id, vp);
-}
-
-typedef bool (*ProxyGetFn)(JSContext* cx, HandleObject proxy, HandlePropertyName name,
-                           MutableHandleValue vp);
-static const VMFunction ProxyGetInfo = FunctionInfo<ProxyGetFn>(ProxyGet, "ProxyGet");
-
-bool
-ICGetProp_DOMProxyShadowed::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    Label failure;
-
-    AllocatableGeneralRegisterSet regs(availableGeneralRegs(1));
-    // Need to reserve a scratch register, but the scratch register should not be
-    // ICTailCallReg, because it's used for |enterStubFrame| which needs a
-    // non-ICTailCallReg scratch reg.
-    Register scratch = regs.takeAnyExcluding(ICTailCallReg);
-
-    // Guard input is an object.
-    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
-
-    // Unbox.
-    Register objReg = masm.extractObject(R0, ExtractTemp0);
-
-    // Shape guard.
-    masm.loadPtr(Address(ICStubReg, ICGetProp_DOMProxyShadowed::offsetOfShape()), scratch);
-    masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
-
-    // No need to do any more guards; it's safe to call ProxyGet even
-    // if we've since stopped shadowing.
-
-    // Call ProxyGet(JSContext* cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp);
-
-    // Push a stub frame so that we can perform a non-tail call.
-    enterStubFrame(masm, scratch);
-
-    // Push property name and proxy object.
-    masm.loadPtr(Address(ICStubReg, ICGetProp_DOMProxyShadowed::offsetOfName()), scratch);
-    masm.Push(scratch);
-    masm.Push(objReg);
-
-    // Don't have to preserve R0 anymore.
-    regs.add(R0);
-
-    if (!callVM(ProxyGetInfo, masm))
-        return false;
-    leaveStubFrame(masm);
-
-    // Enter type monitor IC to type-check result.
-    EmitEnterTypeMonitorIC(masm);
-
-    // Failure case - jump to next stub
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-    return true;
-}
-
 bool
 ICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler& masm)
 {
     MOZ_ASSERT(which_ == ICGetProp_ArgumentsLength::Magic);
 
     Label failure;
 
     // Ensure that this is lazy arguments.
@@ -3496,112 +3049,29 @@ ICGetPropCallGetter::ICGetPropCallGetter
                                          uint32_t pcOffset)
   : ICMonitoredStub(kind, stubCode, firstMonitorStub),
     receiverGuard_(receiverGuard),
     holder_(holder),
     holderShape_(holderShape),
     getter_(getter),
     pcOffset_(pcOffset)
 {
-    MOZ_ASSERT(kind == ICStub::GetProp_CallNativeGlobal ||
-               kind == ICStub::GetProp_CallDOMProxyNative ||
-               kind == ICStub::GetProp_CallDOMProxyWithGenerationNative);
+    MOZ_ASSERT(kind == ICStub::GetProp_CallNativeGlobal);
 }
 
 /* static */ ICGetProp_CallNativeGlobal*
 ICGetProp_CallNativeGlobal::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
                             ICGetProp_CallNativeGlobal& other)
 {
     return New<ICGetProp_CallNativeGlobal>(cx, space, other.jitCode(), firstMonitorStub,
                                            other.receiverGuard(), other.holder_,
                                            other.holderShape_, other.globalShape_,
                                            other.getter_, other.pcOffset_);
 }
 
-ICGetPropCallDOMProxyNativeStub::ICGetPropCallDOMProxyNativeStub(Kind kind, JitCode* stubCode,
-                                                                 ICStub* firstMonitorStub,
-                                                                 Shape* shape,
-                                                                 Shape* expandoShape,
-                                                                 JSObject* holder,
-                                                                 Shape* holderShape,
-                                                                 JSFunction* getter,
-                                                                 uint32_t pcOffset)
-  : ICGetPropCallGetter(kind, stubCode, firstMonitorStub, ReceiverGuard(nullptr, shape),
-                        holder, holderShape, getter, pcOffset),
-    expandoShape_(expandoShape)
-{ }
-
-ICGetPropCallDOMProxyNativeCompiler::ICGetPropCallDOMProxyNativeCompiler(JSContext* cx,
-                                                                         ICStub::Kind kind,
-                                                                         ICStubCompiler::Engine engine,
-                                                                         ICStub* firstMonitorStub,
-                                                                         Handle<ProxyObject*> proxy,
-                                                                         HandleObject holder,
-                                                                         HandleFunction getter,
-                                                                         uint32_t pcOffset)
-  : ICStubCompiler(cx, kind, engine),
-    firstMonitorStub_(firstMonitorStub),
-    proxy_(cx, proxy),
-    holder_(cx, holder),
-    getter_(cx, getter),
-    pcOffset_(pcOffset)
-{
-    MOZ_ASSERT(kind == ICStub::GetProp_CallDOMProxyNative ||
-               kind == ICStub::GetProp_CallDOMProxyWithGenerationNative);
-    MOZ_ASSERT(proxy_->handler()->family() == GetDOMProxyHandlerFamily());
-}
-
-/* static */ ICGetProp_CallDOMProxyNative*
-ICGetProp_CallDOMProxyNative::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
-                                    ICGetProp_CallDOMProxyNative& other)
-{
-    return New<ICGetProp_CallDOMProxyNative>(cx, space, other.jitCode(), firstMonitorStub,
-                                             other.receiverGuard_.shape(), other.expandoShape_,
-                                             other.holder_, other.holderShape_, other.getter_,
-                                             other.pcOffset_);
-}
-
-/* static */ ICGetProp_CallDOMProxyWithGenerationNative*
-ICGetProp_CallDOMProxyWithGenerationNative::Clone(JSContext* cx,
-                                                  ICStubSpace* space,
-                                                  ICStub* firstMonitorStub,
-                                                  ICGetProp_CallDOMProxyWithGenerationNative& other)
-{
-    return New<ICGetProp_CallDOMProxyWithGenerationNative>(cx, space, other.jitCode(),
-                                                           firstMonitorStub,
-                                                           other.receiverGuard_.shape(),
-                                                           other.expandoAndGeneration_,
-                                                           other.generation_,
-                                                           other.expandoShape_, other.holder_,
-                                                           other.holderShape_, other.getter_,
-                                                           other.pcOffset_);
-}
-
-ICGetProp_DOMProxyShadowed::ICGetProp_DOMProxyShadowed(JitCode* stubCode,
-                                                       ICStub* firstMonitorStub,
-                                                       Shape* shape,
-                                                       const BaseProxyHandler* proxyHandler,
-                                                       PropertyName* name,
-                                                       uint32_t pcOffset)
-  : ICMonitoredStub(ICStub::GetProp_DOMProxyShadowed, stubCode, firstMonitorStub),
-    shape_(shape),
-    proxyHandler_(proxyHandler),
-    name_(name),
-    pcOffset_(pcOffset)
-{ }
-
-/* static */ ICGetProp_DOMProxyShadowed*
-ICGetProp_DOMProxyShadowed::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
-                                  ICGetProp_DOMProxyShadowed& other)
-{
-    return New<ICGetProp_DOMProxyShadowed>(cx, space, other.jitCode(), firstMonitorStub,
-                                           other.shape_, other.proxyHandler_, other.name_,
-                                           other.pcOffset_);
-}
-
 //
 // TypeMonitor_Fallback
 //
 
 bool
 ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, SharedStubInfo* info, HandleValue val)
 {
     bool wasDetachedMonitorChain = lastMonitorStubPtrAddr_ == nullptr;
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -2208,20 +2208,17 @@ GetTypedThingLayout(const Class* clasp)
 bool
 IsPreliminaryObject(JSObject* obj);
 
 void
 StripPreliminaryObjectStubs(JSContext* cx, ICFallbackStub* stub);
 
 MOZ_MUST_USE bool
 EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId name,
-                           MutableHandleObject holder, MutableHandleShape shape,
-                           bool* checkDOMProxy=nullptr,
-                           DOMProxyShadowsResult* shadowsResult=nullptr,
-                           bool* domProxyHasGeneration=nullptr);
+                           MutableHandleObject holder, MutableHandleShape shape);
 
 JSObject*
 GetDOMProxyProto(JSObject* obj);
 
 bool
 IsCacheableProtoChain(JSObject* obj, JSObject* holder, bool isDOMProxy=false);
 
 bool
@@ -2248,25 +2245,16 @@ void
 GuardReceiverObject(MacroAssembler& masm, ReceiverGuard guard,
                     Register object, Register scratch,
                     size_t receiverGuardOffset, Label* failure);
 
 MOZ_MUST_USE bool
 GetProtoShapes(JSObject* obj, size_t protoChainDepth, MutableHandle<ShapeVector> shapes);
 
 void
-CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, Register object,
-                                  const Address& checkExpandoShapeAddr,
-                                  Address* expandoAndGenerationAddr,
-                                  Address* generationAddr,
-                                  Register scratch,
-                                  AllocatableGeneralRegisterSet& domProxyRegSet,
-                                  Label* checkFailed);
-
-void
 CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Label* failure);
 
 MOZ_MUST_USE bool
 DoCallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
                    MutableHandleValue result);
 
 void
 LoadTypedThingData(MacroAssembler& masm, TypedThingLayout layout, Register obj, Register result);
@@ -2681,182 +2669,16 @@ class ICGetPropCallNativeCompiler : publ
       : ICGetPropCallGetter::Compiler(cx, kind, engine, firstMonitorStub, receiver, holder,
                                       getter, pcOffset),
         inputDefinitelyObject_(inputDefinitelyObject)
     {}
 
     ICStub* getStub(ICStubSpace* space);
 };
 
-class ICGetPropCallDOMProxyNativeStub : public ICGetPropCallGetter
-{
-  friend class ICStubSpace;
-  protected:
-    // Object shape of expected expando object. (nullptr if no expando object should be there)
-    GCPtrShape expandoShape_;
-
-    ICGetPropCallDOMProxyNativeStub(ICStub::Kind kind, JitCode* stubCode,
-                                    ICStub* firstMonitorStub, Shape* shape,
-                                    Shape* expandoShape,
-                                    JSObject* holder, Shape* holderShape,
-                                    JSFunction* getter, uint32_t pcOffset);
-
-  public:
-    GCPtrShape& expandoShape() {
-        return expandoShape_;
-    }
-    static size_t offsetOfExpandoShape() {
-        return offsetof(ICGetPropCallDOMProxyNativeStub, expandoShape_);
-    }
-};
-
-class ICGetProp_CallDOMProxyNative : public ICGetPropCallDOMProxyNativeStub
-{
-    friend class ICStubSpace;
-    ICGetProp_CallDOMProxyNative(JitCode* stubCode, ICStub* firstMonitorStub, Shape* shape,
-                                 Shape* expandoShape,
-                                 JSObject* holder, Shape* holderShape,
-                                 JSFunction* getter, uint32_t pcOffset)
-      : ICGetPropCallDOMProxyNativeStub(ICStub::GetProp_CallDOMProxyNative, stubCode,
-                                        firstMonitorStub, shape, expandoShape,
-                                        holder, holderShape, getter, pcOffset)
-    {}
-
-  public:
-    static ICGetProp_CallDOMProxyNative* Clone(JSContext* cx,
-                                               ICStubSpace* space,
-                                               ICStub* firstMonitorStub,
-                                               ICGetProp_CallDOMProxyNative& other);
-};
-
-class ICGetProp_CallDOMProxyWithGenerationNative : public ICGetPropCallDOMProxyNativeStub
-{
-  protected:
-    ExpandoAndGeneration* expandoAndGeneration_;
-    uint64_t generation_;
-
-  public:
-    ICGetProp_CallDOMProxyWithGenerationNative(JitCode* stubCode, ICStub* firstMonitorStub,
-                                               Shape* shape,
-                                               ExpandoAndGeneration* expandoAndGeneration,
-                                               uint64_t generation, Shape* expandoShape,
-                                               JSObject* holder, Shape* holderShape,
-                                               JSFunction* getter, uint32_t pcOffset)
-      : ICGetPropCallDOMProxyNativeStub(ICStub::GetProp_CallDOMProxyWithGenerationNative,
-                                        stubCode, firstMonitorStub, shape,
-                                        expandoShape, holder, holderShape, getter, pcOffset),
-        expandoAndGeneration_(expandoAndGeneration),
-        generation_(generation)
-    {
-    }
-
-    static ICGetProp_CallDOMProxyWithGenerationNative*
-    Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
-          ICGetProp_CallDOMProxyWithGenerationNative& other);
-
-    void* expandoAndGeneration() const {
-        return expandoAndGeneration_;
-    }
-    uint64_t generation() const {
-        return generation_;
-    }
-
-    void setGeneration(uint64_t value) {
-        generation_ = value;
-    }
-
-    static size_t offsetOfInternalStruct() {
-        return offsetof(ICGetProp_CallDOMProxyWithGenerationNative, expandoAndGeneration_);
-    }
-    static size_t offsetOfGeneration() {
-        return offsetof(ICGetProp_CallDOMProxyWithGenerationNative, generation_);
-    }
-};
-
-class ICGetPropCallDOMProxyNativeCompiler : public ICStubCompiler {
-    ICStub* firstMonitorStub_;
-    Rooted<ProxyObject*> proxy_;
-    RootedObject holder_;
-    RootedFunction getter_;
-    uint32_t pcOffset_;
-
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm, Address* internalStructAddr,
-                                       Address* generationAddr);
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
-
-  public:
-    ICGetPropCallDOMProxyNativeCompiler(JSContext* cx, ICStub::Kind kind,
-                                        ICStubCompiler::Engine engine,
-                                        ICStub* firstMonitorStub, Handle<ProxyObject*> proxy,
-                                        HandleObject holder, HandleFunction getter,
-                                        uint32_t pcOffset);
-
-    ICStub* getStub(ICStubSpace* space);
-};
-
-class ICGetProp_DOMProxyShadowed : public ICMonitoredStub
-{
-  friend class ICStubSpace;
-  protected:
-    GCPtrShape shape_;
-    const BaseProxyHandler* proxyHandler_;
-    GCPtrPropertyName name_;
-    uint32_t pcOffset_;
-
-    ICGetProp_DOMProxyShadowed(JitCode* stubCode, ICStub* firstMonitorStub, Shape* shape,
-                               const BaseProxyHandler* proxyHandler, PropertyName* name,
-                               uint32_t pcOffset);
-
-  public:
-    static ICGetProp_DOMProxyShadowed* Clone(JSContext* cx, ICStubSpace* space,
-                                             ICStub* firstMonitorStub,
-                                             ICGetProp_DOMProxyShadowed& other);
-
-    GCPtrShape& shape() {
-        return shape_;
-    }
-    GCPtrPropertyName& name() {
-        return name_;
-    }
-
-    static size_t offsetOfShape() {
-        return offsetof(ICGetProp_DOMProxyShadowed, shape_);
-    }
-    static size_t offsetOfProxyHandler() {
-        return offsetof(ICGetProp_DOMProxyShadowed, proxyHandler_);
-    }
-    static size_t offsetOfName() {
-        return offsetof(ICGetProp_DOMProxyShadowed, name_);
-    }
-    static size_t offsetOfPCOffset() {
-        return offsetof(ICGetProp_DOMProxyShadowed, pcOffset_);
-    }
-
-    class Compiler : public ICStubCompiler {
-        ICStub* firstMonitorStub_;
-        Rooted<ProxyObject*> proxy_;
-        RootedPropertyName name_;
-        uint32_t pcOffset_;
-
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
-
-      public:
-        Compiler(JSContext* cx, Engine engine, ICStub* firstMonitorStub, Handle<ProxyObject*> proxy,
-                 HandlePropertyName name, uint32_t pcOffset)
-          : ICStubCompiler(cx, ICStub::GetProp_DOMProxyShadowed, engine),
-            firstMonitorStub_(firstMonitorStub),
-            proxy_(cx, proxy),
-            name_(cx, name),
-            pcOffset_(pcOffset)
-        {}
-
-        ICStub* getStub(ICStubSpace* space);
-    };
-};
-
 class ICGetProp_ArgumentsLength : public ICStub
 {
   friend class ICStubSpace;
   public:
     enum Which { Magic };
 
   protected:
     explicit ICGetProp_ArgumentsLength(JitCode* stubCode)
--- a/js/src/jit/SharedICList.h
+++ b/js/src/jit/SharedICList.h
@@ -32,19 +32,16 @@ namespace jit {
     _(Compare_Boolean)                           \
     _(Compare_Object)                            \
     _(Compare_ObjectWithUndefined)               \
     _(Compare_Int32WithBoolean)                  \
                                                  \
     _(GetProp_Fallback)                          \
     _(GetProp_StringLength)                      \
     _(GetProp_CallNativeGlobal)                  \
-    _(GetProp_CallDOMProxyNative)                \
-    _(GetProp_CallDOMProxyWithGenerationNative)  \
-    _(GetProp_DOMProxyShadowed)                  \
     _(GetProp_ArgumentsLength)                   \
     _(GetProp_ArgumentsCallee)                   \
     _(GetProp_Generic)                           \
                                                  \
     _(CacheIR_Monitored)                         \
                                                  \
 
 } // namespace jit
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1350,10 +1350,17 @@ ThrowObjectCoercible(JSContext* cx, Hand
 }
 
 bool
 BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res)
 {
     return GetFunctionThis(cx, frame, res);
 }
 
+bool
+ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
+{
+    RootedValue receiver(cx, ObjectValue(*proxy));
+    return Proxy::get(cx, proxy, receiver, id, vp);
+}
+
 } // namespace jit
 } // namespace js
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -107,17 +107,17 @@ struct VMFunction
     // nullptr before discarding its value.
     DataType returnType;
 
     // Note: a maximum of seven root types is supported.
     enum RootType {
         RootNone = 0,
         RootObject,
         RootString,
-        RootPropertyName,
+        RootId,
         RootFunction,
         RootValue,
         RootCell
     };
 
     // Contains an combination of enumerated types used by the gc for marking
     // arguments of the VM wrapper.
     uint64_t argumentRootTypes;
@@ -279,16 +279,17 @@ template <> struct TypeToDataType<Handle
 template <> struct TypeToDataType<Handle<GeneratorObject*> > { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<Handle<PlainObject*> > { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<Handle<WithScope*> > { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<Handle<LexicalScope*> > { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<Handle<Scope*> > { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleScript> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleValue> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<MutableHandleValue> { static const DataType result = Type_Handle; };
+template <> struct TypeToDataType<HandleId> { static const DataType result = Type_Handle; };
 
 // Convert argument types to properties of the argument known by the jit.
 template <class T> struct TypeToArgProperties {
     static const uint32_t result =
         (sizeof(T) <= sizeof(void*) ? VMFunction::Word : VMFunction::Double);
 };
 template <> struct TypeToArgProperties<const Value&> {
     static const uint32_t result = TypeToArgProperties<Value>::result | VMFunction::ByRef;
@@ -333,16 +334,19 @@ template <> struct TypeToArgProperties<H
     static const uint32_t result = TypeToArgProperties<JSScript*>::result | VMFunction::ByRef;
 };
 template <> struct TypeToArgProperties<HandleValue> {
     static const uint32_t result = TypeToArgProperties<Value>::result | VMFunction::ByRef;
 };
 template <> struct TypeToArgProperties<MutableHandleValue> {
     static const uint32_t result = TypeToArgProperties<Value>::result | VMFunction::ByRef;
 };
+template <> struct TypeToArgProperties<HandleId> {
+    static const uint32_t result = TypeToArgProperties<jsid>::result | VMFunction::ByRef;
+};
 template <> struct TypeToArgProperties<HandleShape> {
     static const uint32_t result = TypeToArgProperties<Shape*>::result | VMFunction::ByRef;
 };
 template <> struct TypeToArgProperties<HandleObjectGroup> {
     static const uint32_t result = TypeToArgProperties<ObjectGroup*>::result | VMFunction::ByRef;
 };
 
 // Convert argument type to whether or not it should be passed in a float
@@ -360,27 +364,30 @@ template <class T> struct TypeToRootType
 };
 template <> struct TypeToRootType<HandleObject> {
     static const uint32_t result = VMFunction::RootObject;
 };
 template <> struct TypeToRootType<HandleString> {
     static const uint32_t result = VMFunction::RootString;
 };
 template <> struct TypeToRootType<HandlePropertyName> {
-    static const uint32_t result = VMFunction::RootPropertyName;
+    static const uint32_t result = VMFunction::RootString;
 };
 template <> struct TypeToRootType<HandleFunction> {
     static const uint32_t result = VMFunction::RootFunction;
 };
 template <> struct TypeToRootType<HandleValue> {
     static const uint32_t result = VMFunction::RootValue;
 };
 template <> struct TypeToRootType<MutableHandleValue> {
     static const uint32_t result = VMFunction::RootValue;
 };
+template <> struct TypeToRootType<HandleId> {
+    static const uint32_t result = VMFunction::RootId;
+};
 template <> struct TypeToRootType<HandleShape> {
     static const uint32_t result = VMFunction::RootCell;
 };
 template <> struct TypeToRootType<HandleObjectGroup> {
     static const uint32_t result = VMFunction::RootCell;
 };
 template <> struct TypeToRootType<HandleScript> {
     static const uint32_t result = VMFunction::RootCell;
@@ -797,12 +804,15 @@ MOZ_MUST_USE bool
 ThrowBadDerivedReturn(JSContext* cx, HandleValue v);
 
 MOZ_MUST_USE bool
 ThrowObjectCoercible(JSContext* cx, HandleValue v);
 
 MOZ_MUST_USE bool
 BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res);
 
+MOZ_MUST_USE bool
+ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp);
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_VMFunctions_h */
--- a/js/src/tests/ecma_5/RegExp/instance-property-storage-introspection.js
+++ b/js/src/tests/ecma_5/RegExp/instance-property-storage-introspection.js
@@ -35,32 +35,29 @@ function checkDataProperty(obj, p, expec
   assertEq(d.writable, d2.writable, msg + ": writable changed on redefinition of " + p + "?");
   assertEq(d.enumerable, d2.enumerable, msg + ": enumerable changed on redefinition of " + p + "?");
   assertEq(d.configurable, d2.configurable, msg + ": configurable changed on redefinition of " + p + "?");
 }
 
 
 // Check a bunch of "empty" regular expressions first.
 
-var choices = [{ msg: "RegExp.prototype",
-                 get: function() { return RegExp.prototype; } },
-               { msg: "new RegExp()",
+var choices = [{ msg: "new RegExp()",
                  get: function() { return new RegExp(); } },
                { msg: "/(?:)/",
                  get: Function("return /(?:)/;") }];
 
 function checkRegExp(r, msg, lastIndex)
 {
   var expect;
 
   expect = { value: lastIndex, enumerable: false, configurable: false, writable: true };
   checkDataProperty(r, "lastIndex", expect, msg);
 }
 
-checkRegExp(RegExp.prototype, "RegExp.prototype", 0);
 checkRegExp(new RegExp(), "new RegExp()", 0);
 checkRegExp(/(?:)/, "/(?:)/", 0);
 checkRegExp(Function("return /(?:)/;")(), 'Function("return /(?:)/;")()', 0);
 
 for (var i = 0; i < choices.length; i++)
 {
   var choice = choices[i];
   var msg = choice.msg;
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/prototype.js
@@ -0,0 +1,31 @@
+const t = RegExp.prototype;
+
+const properties = "toSource,toString,compile,exec,test," +
+                   "flags,global,ignoreCase,multiline,source,sticky,unicode," +
+                   "constructor," +
+                   "Symbol(Symbol.match),Symbol(Symbol.replace),Symbol(Symbol.search),Symbol(Symbol.split)";
+assertEq(Reflect.ownKeys(t).map(String).toString(), properties);
+
+
+// Invoking getters on the prototype should not throw
+function getter(name) {
+    return Object.getOwnPropertyDescriptor(t, name).get.call(t);
+}
+
+assertEq(getter("flags"), "");
+assertEq(getter("global"), undefined);
+assertEq(getter("ignoreCase"), undefined);
+assertEq(getter("multiline"), undefined);
+assertEq(getter("source"), "(?:)");
+assertEq(getter("sticky"), undefined);
+assertEq(getter("unicode"), undefined);
+
+assertEq(t.toString(), "/(?:)/");
+
+// The methods don't work with the prototype
+assertThrowsInstanceOf(() => t.compile("b", "i"), TypeError);
+assertThrowsInstanceOf(() => t.test("x"), TypeError);
+assertThrowsInstanceOf(() => t.exec("x"), TypeError);
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
--- a/js/src/tests/js1_8_5/extensions/clone-regexp.js
+++ b/js/src/tests/js1_8_5/extensions/clone-regexp.js
@@ -17,17 +17,16 @@ function testRegExp(b, c=b) {
     assertEq(a.multiline, c.multiline);
     assertEq(a.sticky, c.sticky);
     assertEq("expando" in a, false);
 }
 
 testRegExp(RegExp(""));
 testRegExp(/(?:)/);
 testRegExp(/^(.*)$/gimy);
-testRegExp(RegExp.prototype);
 
 var re = /\bx\b/gi;
 re.expando = true;
 testRegExp(re);
 // `source` and the flag accessors are defined on RegExp.prototype, so they're
 // not available after re.__proto__ has been changed. We solve that by passing
 // in an additional copy of the same RegExp to compare the
 // serialized-then-deserialized clone with."
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -572,17 +572,17 @@ ObjectGroup::defaultNewGroup(ExclusiveCo
          * Some builtin objects have slotful native properties baked in at
          * creation via the Shape::{insert,get}initialShape mechanism. Since
          * these properties are never explicitly defined on new objects, update
          * the type information for them here.
          */
 
         const JSAtomState& names = cx->names();
 
-        if (obj->is<RegExpObject>())
+        if (StandardProtoKeyOrNull(obj) == JSProto_RegExp)
             AddTypePropertyId(cx, group, nullptr, NameToId(names.lastIndex), TypeSet::Int32Type());
 
         if (obj->is<StringObject>())
             AddTypePropertyId(cx, group, nullptr, NameToId(names.length), TypeSet::Int32Type());
 
         if (IsErrorProtoKey(StandardProtoKeyOrNull(obj))) {
             AddTypePropertyId(cx, group, nullptr, NameToId(names.fileName), TypeSet::StringType());
             AddTypePropertyId(cx, group, nullptr, NameToId(names.lineNumber), TypeSet::Int32Type());
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -189,16 +189,22 @@ RegExpObject::trace(JSTracer* trc, JSObj
         !obj->asTenured().zone()->isPreservingCode())
     {
         obj->as<RegExpObject>().NativeObject::setPrivate(nullptr);
     } else {
         shared->trace(trc);
     }
 }
 
+static JSObject*
+CreateRegExpPrototype(JSContext* cx, JSProtoKey key)
+{
+    return cx->global()->createBlankPrototype(cx, &RegExpObject::protoClass_);
+}
+
 static const ClassOps RegExpObjectClassOps = {
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* getProperty */
     nullptr, /* setProperty */
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
@@ -222,16 +228,23 @@ const Class RegExpObject::class_ = {
     js_RegExp_str,
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(RegExpObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
     &RegExpObjectClassOps,
     &RegExpObjectClassSpec
 };
 
+const Class RegExpObject::protoClass_ = {
+    js_Object_str,
+    JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
+    JS_NULL_CLASS_OPS,
+    &RegExpObjectClassSpec
+};
+
 RegExpObject*
 RegExpObject::create(ExclusiveContext* cx, const char16_t* chars, size_t length, RegExpFlag flags,
                      TokenStream* tokenStream, LifoAlloc& alloc)
 {
     RootedAtom source(cx, AtomizeChars(cx, chars, length));
     if (!source)
         return nullptr;
 
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -74,19 +74,16 @@ enum RegExpRunStatus
 
 extern RegExpObject*
 RegExpAlloc(ExclusiveContext* cx, HandleObject proto = nullptr);
 
 // |regexp| is under-typed because this function's used in the JIT.
 extern JSObject*
 CloneRegExpObject(JSContext* cx, JSObject* regexp);
 
-extern JSObject*
-CreateRegExpPrototype(JSContext* cx, JSProtoKey key);
-
 /*
  * A RegExpShared is the compiled representation of a regexp. A RegExpShared is
  * potentially pointed to by multiple RegExpObjects. Additionally, C++ code may
  * have pointers to RegExpShareds on the stack. The RegExpShareds are kept in a
  * table so that they can be reused when compiling the same regex string.
  *
  * During a GC, RegExpShared instances are marked and swept like GC things.
  * Usually, RegExpObjects clear their pointers to their RegExpShareds rather
@@ -402,16 +399,17 @@ class RegExpObject : public NativeObject
     static_assert(RegExpObject::FLAGS_SLOT == REGEXP_FLAGS_SLOT,
                   "FLAGS_SLOT values should be in sync with self-hosted JS");
 
   public:
     static const unsigned RESERVED_SLOTS = 3;
     static const unsigned PRIVATE_SLOT = 3;
 
     static const Class class_;
+    static const Class protoClass_;
 
     // The maximum number of pairs a MatchResult can have, without having to
     // allocate a bigger MatchResult.
     static const size_t MaxPairCount = 14;
 
     static RegExpObject*
     create(ExclusiveContext* cx, const char16_t* chars, size_t length, RegExpFlag flags,
            frontend::TokenStream* ts, LifoAlloc& alloc);
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -234,18 +234,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   gPrototypeProperties['Function'] =
     ["constructor", "toSource", "toString", "apply", "call", "bind",
      "isGenerator", "length", "name", "arguments", "caller", Symbol.hasInstance];
   gConstructorProperties['Function'] = constructorProps([])
 
   gPrototypeProperties['RegExp'] =
     ["constructor", "toSource", "toString", "compile", "exec", "test",
      Symbol.match, Symbol.replace, Symbol.search, Symbol.split,
-     "flags", "global", "ignoreCase", "multiline", "source", "sticky", "unicode",
-     "lastIndex"];
+     "flags", "global", "ignoreCase", "multiline", "source", "sticky", "unicode"];
   gConstructorProperties['RegExp'] =
     constructorProps(["input", "lastMatch", "lastParen",
                       "leftContext", "rightContext", "$1", "$2", "$3", "$4",
                       "$5", "$6", "$7", "$8", "$9", "$_", "$&", "$+",
                       "$`", "$'", Symbol.species])
 
   gPrototypeProperties['Promise'] =
     ["constructor", "catch", "then", Symbol.toStringTag];
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_xray_regexp.js
@@ -0,0 +1,9 @@
+const Cu = Components.utils;
+
+function run_test() {
+    var sandbox = Cu.Sandbox('http://www.example.com');
+    var regexp = Cu.evalInSandbox("/test/i", sandbox);
+    equal(RegExp.prototype.toString.call(regexp), "/test/i");
+    var prototype = Cu.evalInSandbox("RegExp.prototype", sandbox);
+    equal(typeof prototype.lastIndex, "undefined");
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -122,9 +122,10 @@ head = head_watchdog.js
 [test_watchdog_hibernate.js]
 head = head_watchdog.js
 [test_weak_keys.js]
 [test_writeToGlobalPrototype.js]
 [test_xpcwn_tamperproof.js]
 [test_xrayed_iterator.js]
 [test_xray_SavedFrame.js]
 [test_xray_SavedFrame-02.js]
+[test_xray_regexp.js]
 [test_resolve_dead_promise.js]
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -633,20 +633,16 @@ JSXrayTraits::resolveOwnProperty(JSConte
         desc.object().set(wrapper);
         desc.setAttributes(0);
         desc.setGetter(nullptr);
         desc.setSetter(nullptr);
         desc.value().setObject(*constructor);
         return true;
     }
 
-    // Handle the 'lastIndex' property for RegExp prototypes.
-    if (key == JSProto_RegExp && id == GetJSIDByIndex(cx, XPCJSContext::IDX_LASTINDEX))
-        return getOwnPropertyFromWrapperIfSafe(cx, wrapper, id, desc);
-
     // Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
     const js::Class* clasp = js::GetObjectClass(target);
     MOZ_ASSERT(clasp->specDefined());
 
     // Indexed array properties are handled above, so we can just work with the
     // class spec here.
     if (!TryResolvePropertyFromSpecs(cx, id, holder,
                                      clasp->specPrototypeFunctions(),
@@ -878,20 +874,16 @@ JSXrayTraits::enumerateNames(JSContext* 
         // The rest of this function applies only to prototypes.
         return true;
     }
 
     // Add the 'constructor' property.
     if (!props.append(GetJSIDByIndex(cx, XPCJSContext::IDX_CONSTRUCTOR)))
         return false;
 
-    // For RegExp protoypes, add the 'lastIndex' property.
-    if (key == JSProto_RegExp && !props.append(GetJSIDByIndex(cx, XPCJSContext::IDX_LASTINDEX)))
-        return false;
-
     // Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
     const js::Class* clasp = js::GetObjectClass(target);
     MOZ_ASSERT(clasp->specDefined());
 
     return AppendNamesFromFunctionAndPropertySpecs(
         cx, clasp->specPrototypeFunctions(),
         clasp->specPrototypeProperties(), flags, props);
 }
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2280,17 +2280,17 @@ nsStyleImage::ComputeActualCropRect(nsIn
 nsresult
 nsStyleImage::StartDecoding() const
 {
   if (mType == eStyleImageType_Image) {
     imgRequestProxy* req = GetImageData();
     if (!req) {
       return NS_ERROR_FAILURE;
     }
-    return req->StartDecoding();
+    return req->StartDecoding(imgIContainer::FLAG_NONE);
   }
   return NS_OK;
 }
 
 bool
 nsStyleImage::IsOpaque() const
 {
   if (!IsComplete()) {
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -284,17 +284,17 @@ nsImageBoxFrame::UpdateImage()
     }
   }
 
   if (!mImageRequest) {
     // We have no image, so size to 0
     mIntrinsicSize.SizeTo(0, 0);
   } else {
     // We don't want discarding or decode-on-draw for xul images.
-    mImageRequest->StartDecoding();
+    mImageRequest->StartDecoding(imgIContainer::FLAG_NONE);
     mImageRequest->LockImage();
   }
 
   // Do this _after_ locking the new image in case they are the same image.
   if (oldImageRequest) {
     oldImageRequest->UnlockImage();
   }
 }
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -2200,17 +2200,17 @@ nsTreeBodyFrame::GetImage(int32_t aRowIn
       NS_ENSURE_SUCCESS(rv, rv);
     }
     listener->UnsuppressInvalidation();
 
     if (!imageRequest)
       return NS_ERROR_FAILURE;
 
     // We don't want discarding/decode-on-draw for xul images
-    imageRequest->StartDecoding();
+    imageRequest->StartDecoding(imgIContainer::FLAG_ASYNC_NOTIFY);
     imageRequest->LockImage();
 
     // In a case it was already cached.
     imageRequest->GetImage(aResult);
     nsTreeImageCacheEntry cacheEntry(imageRequest, imgNotificationObserver);
     mImageCache.Put(imageSrc, cacheEntry);
   }
   return NS_OK;