Bug 1661211 part 1 - Clean up CacheIR ops for getter calls. r=iain
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 26 Aug 2020 20:00:45 +0000
changeset 546400 fc681a8e552e530a2d8af0870ca3d91550e6a1e2
parent 546399 44ee384376ce8b20ef64db6e4fef50af983c2088
child 546401 d01415c7707edaaf119e5e4c76f6b4e3c6a30e13
push id37735
push userabutkovits@mozilla.com
push dateThu, 27 Aug 2020 21:29:40 +0000
treeherdermozilla-central@109f3a4de567 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersiain
bugs1661211
milestone82.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1661211 part 1 - Clean up CacheIR ops for getter calls. r=iain We had different CacheIR ops for receiver-is-object and receiver-is-Value. This patch unifies them by always using the receiver-is-Value version. This makes it easier to transpile in Warp. When generating CacheIR, pass and use the receiverId (Value) in a few places instead of objId. This also lets us support non-object receivers for super.prop There are two places where this doesn't work and boxObject is used to convert from object-id to value-id. In the future this could be a dedicated CacheIR op instead of a cast, but that would require BaselineInspector changes. Differential Revision: https://phabricator.services.mozilla.com/D88264
js/src/jit/BaselineCacheIRCompiler.cpp
js/src/jit/BaselineCacheIRCompiler.h
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
js/src/jit/CacheIROps.yaml
js/src/jit/IonCacheIRCompiler.cpp
js/src/jit/IonCacheIRCompiler.h
js/src/jit/VMFunctionList-inl.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -491,18 +491,21 @@ bool BaselineCacheIRCompiler::emitGuardH
   masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectHasGetterSetterPure));
   masm.mov(ReturnReg, scratch1);
   masm.PopRegsInMask(volatileRegs);
 
   masm.branchIfFalseBool(scratch1, failure->label());
   return true;
 }
 
-bool BaselineCacheIRCompiler::emitCallScriptedGetterResultShared(
-    TypedOrValueRegister receiver, uint32_t getterOffset, bool sameRealm) {
+bool BaselineCacheIRCompiler::emitCallScriptedGetterResult(
+    ValOperandId receiverId, uint32_t getterOffset, bool sameRealm) {
+  JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
+
+  ValueOperand receiver = allocator.useValueRegister(masm, receiverId);
   Address getterAddr(stubAddress(getterOffset));
 
   AutoScratchRegister code(allocator, masm);
   AutoScratchRegister callee(allocator, masm);
   AutoScratchRegister scratch(allocator, masm);
 
   // First, retrieve jitCodeRaw for getter.
   masm.loadPtr(getterAddr, callee);
@@ -549,82 +552,44 @@ bool BaselineCacheIRCompiler::emitCallSc
 
   if (!sameRealm) {
     masm.switchToBaselineFrameRealm(R1.scratchReg());
   }
 
   return true;
 }
 
-bool BaselineCacheIRCompiler::emitCallScriptedGetterResult(
-    ObjOperandId objId, uint32_t getterOffset, bool sameRealm) {
+bool BaselineCacheIRCompiler::emitCallNativeGetterResult(
+    ValOperandId receiverId, uint32_t getterOffset) {
   JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-  Register obj = allocator.useRegister(masm, objId);
-
-  return emitCallScriptedGetterResultShared(
-      TypedOrValueRegister(MIRType::Object, AnyRegister(obj)), getterOffset,
-      sameRealm);
-}
-
-bool BaselineCacheIRCompiler::emitCallScriptedGetterByValueResult(
-    ValOperandId valId, uint32_t getterOffset, bool sameRealm) {
-  JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-  ValueOperand val = allocator.useValueRegister(masm, valId);
-
-  return emitCallScriptedGetterResultShared(val, getterOffset, sameRealm);
-}
-
-template <typename T, typename CallVM>
-bool BaselineCacheIRCompiler::emitCallNativeGetterResultShared(
-    T receiver, uint32_t getterOffset, const CallVM& emitCallVM) {
+
+  ValueOperand receiver = allocator.useValueRegister(masm, receiverId);
   Address getterAddr(stubAddress(getterOffset));
 
   AutoScratchRegister scratch(allocator, masm);
 
   allocator.discardStack(masm);
 
   AutoStubFrame stubFrame(*this);
   stubFrame.enter(masm, scratch);
 
   // Load the callee in the scratch register.
   masm.loadPtr(getterAddr, scratch);
 
   masm.Push(receiver);
   masm.Push(scratch);
 
-  emitCallVM();
+  using Fn =
+      bool (*)(JSContext*, HandleFunction, HandleValue, MutableHandleValue);
+  callVM<Fn, CallNativeGetter>(masm);
 
   stubFrame.leave(masm);
   return true;
 }
 
-bool BaselineCacheIRCompiler::emitCallNativeGetterResult(
-    ObjOperandId objId, uint32_t getterOffset) {
-  JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-  Register obj = allocator.useRegister(masm, objId);
-
-  return emitCallNativeGetterResultShared(obj, getterOffset, [this]() {
-    using Fn =
-        bool (*)(JSContext*, HandleFunction, HandleObject, MutableHandleValue);
-    callVM<Fn, CallNativeGetter>(masm);
-  });
-}
-
-bool BaselineCacheIRCompiler::emitCallNativeGetterByValueResult(
-    ValOperandId valId, uint32_t getterOffset) {
-  JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-  ValueOperand val = allocator.useValueRegister(masm, valId);
-
-  return emitCallNativeGetterResultShared(val, getterOffset, [this]() {
-    using Fn =
-        bool (*)(JSContext*, HandleFunction, HandleValue, MutableHandleValue);
-    callVM<Fn, CallNativeGetterByValue>(masm);
-  });
-}
-
 bool BaselineCacheIRCompiler::emitProxyGetResult(ObjOperandId objId,
                                                  uint32_t idOffset) {
   JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
   Register obj = allocator.useRegister(masm, objId);
   Address idAddr(stubAddress(idOffset));
 
   AutoScratchRegister scratch(allocator, masm);
 
--- a/js/src/jit/BaselineCacheIRCompiler.h
+++ b/js/src/jit/BaselineCacheIRCompiler.h
@@ -69,24 +69,16 @@ class MOZ_RAII BaselineCacheIRCompiler :
   void updateReturnValue();
 
   enum class NativeCallType { Native, ClassHook };
   bool emitCallNativeShared(NativeCallType callType, ObjOperandId calleeId,
                             Int32OperandId argcId, CallFlags flags,
                             mozilla::Maybe<bool> ignoresReturnValue,
                             mozilla::Maybe<uint32_t> targetOffset);
 
-  MOZ_MUST_USE bool emitCallScriptedGetterResultShared(
-      TypedOrValueRegister receiver, uint32_t getterOffset, bool sameRealm);
-
-  template <typename T, typename CallVM>
-  MOZ_MUST_USE bool emitCallNativeGetterResultShared(T receiver,
-                                                     uint32_t getterOffset,
-                                                     const CallVM& emitCallVM);
-
   enum class StringCode { CodeUnit, CodePoint };
   bool emitStringFromCodeResult(Int32OperandId codeId, StringCode stringCode);
 
  public:
   friend class AutoStubFrame;
 
   BaselineCacheIRCompiler(JSContext* cx, const CacheIRWriter& writer,
                           uint32_t stubDataOffset,
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -314,23 +314,16 @@ static bool ValueToNameOrSymbolId(JSCont
 }
 
 AttachDecision GetPropIRGenerator::tryAttachStub() {
   // Idempotent ICs should call tryAttachIdempotentStub instead.
   MOZ_ASSERT(!idempotent());
 
   AutoAssertNoPendingException aanpe(cx_);
 
-  // Non-object receivers are a degenerate case, so don't try to attach
-  // stubs. The stubs we do emit will still perform runtime checks and
-  // fallback as needed.
-  if (isSuper() && !receiver_.isObject()) {
-    return AttachDecision::NoAction;
-  }
-
   ValOperandId valId(writer.setInputOperandId(0));
   if (cacheKind_ != CacheKind::GetProp) {
     MOZ_ASSERT_IF(cacheKind_ == CacheKind::GetPropSuper,
                   getSuperReceiverValueId().id() == 1);
     MOZ_ASSERT_IF(cacheKind_ != CacheKind::GetPropSuper,
                   getElemKeyValueId().id() == 1);
     writer.setInputOperandId(1);
   }
@@ -341,30 +334,35 @@ AttachDecision GetPropIRGenerator::tryAt
 
   RootedId id(cx_);
   bool nameOrSymbol;
   if (!ValueToNameOrSymbolId(cx_, idVal_, &id, &nameOrSymbol)) {
     cx_->clearPendingException();
     return AttachDecision::NoAction;
   }
 
+  // |super.prop| getter calls use a |this| value that differs from lookup
+  // object.
+  ValOperandId receiverId = isSuper() ? getSuperReceiverValueId() : valId;
+
   if (val_.isObject()) {
     RootedObject obj(cx_, &val_.toObject());
     ObjOperandId objId = writer.guardToObject(valId);
     if (nameOrSymbol) {
       TRY_ATTACH(tryAttachObjectLength(obj, objId, id));
       TRY_ATTACH(tryAttachTypedArrayLength(obj, objId, id));
-      TRY_ATTACH(tryAttachNative(obj, objId, id));
+      TRY_ATTACH(tryAttachNative(obj, objId, id, receiverId));
       TRY_ATTACH(tryAttachTypedObject(obj, objId, id));
       TRY_ATTACH(tryAttachModuleNamespace(obj, objId, id));
       TRY_ATTACH(tryAttachWindowProxy(obj, objId, id));
       TRY_ATTACH(tryAttachCrossCompartmentWrapper(obj, objId, id));
-      TRY_ATTACH(tryAttachXrayCrossCompartmentWrapper(obj, objId, id));
+      TRY_ATTACH(
+          tryAttachXrayCrossCompartmentWrapper(obj, objId, id, receiverId));
       TRY_ATTACH(tryAttachFunction(obj, objId, id));
-      TRY_ATTACH(tryAttachProxy(obj, objId, id));
+      TRY_ATTACH(tryAttachProxy(obj, objId, id, receiverId));
 
       trackAttached(IRGenerator::NotAttached);
       return AttachDecision::NoAction;
     }
 
     MOZ_ASSERT(cacheKind_ == CacheKind::GetElem ||
                cacheKind_ == CacheKind::GetElemSuper);
 
@@ -420,24 +418,25 @@ AttachDecision GetPropIRGenerator::tryAt
   MOZ_ASSERT(idempotent());
 
   RootedObject obj(cx_, &val_.toObject());
   RootedId id(cx_, NameToId(idVal_.toString()->asAtom().asPropertyName()));
 
   ValOperandId valId(writer.setInputOperandId(0));
   ObjOperandId objId = writer.guardToObject(valId);
 
-  TRY_ATTACH(tryAttachNative(obj, objId, id));
+  ValOperandId receiverId = valId;
+  TRY_ATTACH(tryAttachNative(obj, objId, id, receiverId));
 
   // Object lengths are supported only if int32 results are allowed.
   TRY_ATTACH(tryAttachObjectLength(obj, objId, id));
 
   // Also support native data properties on DOMProxy prototypes.
   if (GetProxyStubType(cx_, obj, id) == ProxyStubType::DOMUnshadowed) {
-    return tryAttachDOMProxyUnshadowed(obj, objId, id);
+    return tryAttachDOMProxyUnshadowed(obj, objId, id, receiverId);
   }
 
   return AttachDecision::NoAction;
 }
 
 static bool IsCacheableProtoChain(JSObject* obj, JSObject* holder) {
   while (obj != holder) {
     /*
@@ -997,17 +996,17 @@ static void EmitReadSlotReturn(CacheIRWr
     // avoided.
     writer.returnFromIC();
   }
 }
 
 static void EmitCallGetterResultNoGuards(JSContext* cx, CacheIRWriter& writer,
                                          JSObject* obj, JSObject* holder,
                                          Shape* shape,
-                                         ObjOperandId receiverId) {
+                                         ValOperandId receiverId) {
   switch (IsCacheableGetPropCall(obj, holder, shape)) {
     case CanAttachNativeGetter: {
       JSFunction* target = &shape->getterValue().toObject().as<JSFunction>();
       MOZ_ASSERT(target->isNativeWithoutJitEntry());
       writer.callNativeGetterResult(receiverId, target);
       writer.typeMonitorResult();
       break;
     }
@@ -1045,59 +1044,22 @@ static void EmitCallGetterResultGuards(C
     }
   } else {
     writer.guardHasGetterSetter(objId, shape);
   }
 }
 
 static void EmitCallGetterResult(JSContext* cx, CacheIRWriter& writer,
                                  JSObject* obj, JSObject* holder, Shape* shape,
-                                 ObjOperandId objId, ObjOperandId receiverId,
+                                 ObjOperandId objId, ValOperandId receiverId,
                                  ICState::Mode mode) {
   EmitCallGetterResultGuards(writer, obj, holder, shape, objId, mode);
   EmitCallGetterResultNoGuards(cx, writer, obj, holder, shape, receiverId);
 }
 
-static void EmitCallGetterResult(JSContext* cx, CacheIRWriter& writer,
-                                 JSObject* obj, JSObject* holder, Shape* shape,
-                                 ObjOperandId objId, ICState::Mode mode) {
-  EmitCallGetterResult(cx, writer, obj, holder, shape, objId, objId, mode);
-}
-
-static void EmitCallGetterByValueResult(JSContext* cx, CacheIRWriter& writer,
-                                        JSObject* obj, JSObject* holder,
-                                        Shape* shape, ObjOperandId objId,
-                                        ValOperandId receiverId,
-                                        ICState::Mode mode) {
-  EmitCallGetterResultGuards(writer, obj, holder, shape, objId, mode);
-
-  switch (IsCacheableGetPropCall(obj, holder, shape)) {
-    case CanAttachNativeGetter: {
-      JSFunction* target = &shape->getterValue().toObject().as<JSFunction>();
-      MOZ_ASSERT(target->isNativeWithoutJitEntry());
-      writer.callNativeGetterByValueResult(receiverId, target);
-      writer.typeMonitorResult();
-      break;
-    }
-    case CanAttachScriptedGetter: {
-      JSFunction* target = &shape->getterValue().toObject().as<JSFunction>();
-      MOZ_ASSERT(target->hasJitEntry());
-      bool sameRealm = cx->realm() == target->realm();
-      writer.callScriptedGetterByValueResult(receiverId, target, sameRealm);
-      writer.typeMonitorResult();
-      break;
-    }
-    default:
-      // CanAttachNativeGetProp guarantees that the getter is either a native or
-      // a scripted function.
-      MOZ_ASSERT_UNREACHABLE("Can't attach getter");
-      break;
-  }
-}
-
 void GetPropIRGenerator::attachMegamorphicNativeSlot(ObjOperandId objId,
                                                      jsid id,
                                                      bool handleMissing) {
   MOZ_ASSERT(mode_ == ICState::Mode::Megamorphic);
 
   // The stub handles the missing-properties case only if we're seeing one
   // now, to make sure Ion ICs correctly monitor the undefined type. Without
   // TI we don't use type monitoring so always allow |undefined|.
@@ -1118,17 +1080,18 @@ void GetPropIRGenerator::attachMegamorph
   writer.typeMonitorResult();
 
   trackAttached(handleMissing ? "MegamorphicMissingNativeSlot"
                               : "MegamorphicNativeSlot");
 }
 
 AttachDecision GetPropIRGenerator::tryAttachNative(HandleObject obj,
                                                    ObjOperandId objId,
-                                                   HandleId id) {
+                                                   HandleId id,
+                                                   ValOperandId receiverId) {
   RootedShape shape(cx_);
   RootedNativeObject holder(cx_);
 
   NativeGetPropCacheability type =
       CanAttachNativeGetProp(cx_, obj, id, &holder, &shape, pc_, resultFlags_);
   switch (type) {
     case CanAttachNone:
       return AttachDecision::NoAction;
@@ -1150,21 +1113,17 @@ AttachDecision GetPropIRGenerator::tryAt
       }
       EmitReadSlotResult(writer, obj, holder, shape, objId);
       EmitReadSlotReturn(writer, obj, holder, shape);
 
       trackAttached("NativeSlot");
       return AttachDecision::Attach;
     case CanAttachScriptedGetter:
     case CanAttachNativeGetter: {
-      // |super.prop| accesses use a |this| value that differs from lookup
-      // object
       MOZ_ASSERT(!idempotent());
-      ObjOperandId receiverId =
-          isSuper() ? writer.guardToObject(getSuperReceiverValueId()) : objId;
       maybeEmitIdGuard(id);
       EmitCallGetterResult(cx_, writer, obj, holder, shape, objId, receiverId,
                            mode_);
 
       trackAttached("NativeGetter");
       return AttachDecision::Attach;
     }
   }
@@ -1263,18 +1222,19 @@ AttachDecision GetPropIRGenerator::tryAt
         return AttachDecision::NoAction;
       }
 
       // Guard the incoming object is a WindowProxy and inline a getter call
       // based on the Window object.
       maybeEmitIdGuard(id);
       ObjOperandId windowObjId =
           GuardAndLoadWindowProxyWindow(writer, objId, windowObj);
+      ValOperandId receiverId = writer.boxObject(windowObjId);
       EmitCallGetterResult(cx_, writer, windowObj, holder, shape, windowObjId,
-                           mode_);
+                           receiverId, mode_);
 
       trackAttached("WindowProxyGetter");
       return AttachDecision::Attach;
     }
 
     case CanAttachScriptedGetter:
       MOZ_ASSERT_UNREACHABLE("Not possible for window proxies");
   }
@@ -1385,17 +1345,18 @@ static bool GetXrayExpandoShapeWrapper(J
       return wrapper != nullptr;
     }
   }
   wrapper.set(nullptr);
   return true;
 }
 
 AttachDecision GetPropIRGenerator::tryAttachXrayCrossCompartmentWrapper(
-    HandleObject obj, ObjOperandId objId, HandleId id) {
+    HandleObject obj, ObjOperandId objId, HandleId id,
+    ValOperandId receiverId) {
   if (!IsProxy(obj)) {
     return AttachDecision::NoAction;
   }
 
   XrayJitInfo* info = GetXrayJitInfo();
   if (!info || !info->isCrossCompartmentXray(GetProxyHandler(obj))) {
     return AttachDecision::NoAction;
   }
@@ -1483,17 +1444,17 @@ AttachDecision GetPropIRGenerator::tryAt
     ObjOperandId protoId = writer.loadObject(proto);
     if (JSObject* protoShapeWrapper = prototypeExpandoShapeWrappers[i]) {
       writer.guardXrayExpandoShapeAndDefaultProto(protoId, protoShapeWrapper);
     } else {
       writer.guardXrayNoExpando(protoId);
     }
   }
 
-  writer.callNativeGetterResult(objId, &getter->as<JSFunction>());
+  writer.callNativeGetterResult(receiverId, &getter->as<JSFunction>());
   writer.typeMonitorResult();
 
   trackAttached("XrayGetter");
   return AttachDecision::Attach;
 }
 
 AttachDecision GetPropIRGenerator::tryAttachGenericProxy(
     HandleObject obj, ObjOperandId objId, HandleId id, bool handleDOMProxies) {
@@ -1541,19 +1502,19 @@ ObjOperandId IRGenerator::guardDOMProxyE
   }
 
   // Guard the expando is an object and shape guard.
   ObjOperandId expandoObjId = writer.guardToObject(expandoValId);
   TestMatchingHolder(writer, expandoObj, expandoObjId);
   return expandoObjId;
 }
 
-AttachDecision GetPropIRGenerator::tryAttachDOMProxyExpando(HandleObject obj,
-                                                            ObjOperandId objId,
-                                                            HandleId id) {
+AttachDecision GetPropIRGenerator::tryAttachDOMProxyExpando(
+    HandleObject obj, ObjOperandId objId, HandleId id,
+    ValOperandId receiverId) {
   MOZ_ASSERT(IsCacheableDOMProxy(obj));
 
   RootedValue expandoVal(cx_, GetProxyPrivate(obj));
   RootedObject expandoObj(cx_);
   if (expandoVal.isObject()) {
     expandoObj = &expandoVal.toObject();
   } else {
     MOZ_ASSERT(!expandoVal.isUndefined(),
@@ -1588,17 +1549,17 @@ AttachDecision GetPropIRGenerator::tryAt
                        propShape);
     writer.typeMonitorResult();
   } else {
     // Call the getter. Note that we pass objId, the DOM proxy, as |this|
     // and not the expando object.
     MOZ_ASSERT(canCache == CanAttachNativeGetter ||
                canCache == CanAttachScriptedGetter);
     EmitCallGetterResultNoGuards(cx_, writer, expandoObj, expandoObj, propShape,
-                                 objId);
+                                 receiverId);
   }
 
   trackAttached("DOMProxyExpando");
   return AttachDecision::Attach;
 }
 
 AttachDecision GetPropIRGenerator::tryAttachDOMProxyShadowed(HandleObject obj,
                                                              ObjOperandId objId,
@@ -1647,17 +1608,18 @@ static void CheckDOMProxyExpandoDoesNotS
     writer.guardDOMExpandoMissingOrGuardShape(expandoId,
                                               expandoObj.lastProperty());
   } else {
     MOZ_CRASH("Invalid expando value");
   }
 }
 
 AttachDecision GetPropIRGenerator::tryAttachDOMProxyUnshadowed(
-    HandleObject obj, ObjOperandId objId, HandleId id) {
+    HandleObject obj, ObjOperandId objId, HandleId id,
+    ValOperandId receiverId) {
   MOZ_ASSERT(IsCacheableDOMProxy(obj));
 
   RootedObject checkObj(cx_, obj->staticPrototype());
   if (!checkObj) {
     return AttachDecision::NoAction;
   }
 
   RootedNativeObject holder(cx_);
@@ -1689,33 +1651,35 @@ AttachDecision GetPropIRGenerator::tryAt
     } 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 == CanAttachNativeGetter ||
                  canCache == CanAttachScriptedGetter);
       MOZ_ASSERT(!isSuper());
-      EmitCallGetterResultNoGuards(cx_, writer, checkObj, holder, shape, objId);
+      EmitCallGetterResultNoGuards(cx_, writer, checkObj, holder, shape,
+                                   receiverId);
     }
   } else {
     // Property was not found on the prototype chain. Deoptimize down to
     // proxy get call.
     MOZ_ASSERT(!isSuper());
     writer.proxyGetResult(objId, id);
     writer.typeMonitorResult();
   }
 
   trackAttached("DOMProxyUnshadowed");
   return AttachDecision::Attach;
 }
 
 AttachDecision GetPropIRGenerator::tryAttachProxy(HandleObject obj,
                                                   ObjOperandId objId,
-                                                  HandleId id) {
+                                                  HandleId id,
+                                                  ValOperandId receiverId) {
   ProxyStubType type = GetProxyStubType(cx_, obj, id);
   if (type == ProxyStubType::None) {
     return AttachDecision::NoAction;
   }
 
   // The proxy stubs don't currently support |super| access.
   if (isSuper()) {
     return AttachDecision::NoAction;
@@ -1724,22 +1688,22 @@ AttachDecision GetPropIRGenerator::tryAt
   if (mode_ == ICState::Mode::Megamorphic) {
     return tryAttachGenericProxy(obj, objId, id, /* handleDOMProxies = */ true);
   }
 
   switch (type) {
     case ProxyStubType::None:
       break;
     case ProxyStubType::DOMExpando:
-      TRY_ATTACH(tryAttachDOMProxyExpando(obj, objId, id));
+      TRY_ATTACH(tryAttachDOMProxyExpando(obj, objId, id, receiverId));
       [[fallthrough]];  // Fall through to the generic shadowed case.
     case ProxyStubType::DOMShadowed:
       return tryAttachDOMProxyShadowed(obj, objId, id);
     case ProxyStubType::DOMUnshadowed:
-      TRY_ATTACH(tryAttachDOMProxyUnshadowed(obj, objId, id));
+      TRY_ATTACH(tryAttachDOMProxyUnshadowed(obj, objId, id, receiverId));
       return tryAttachGenericProxy(obj, objId, id,
                                    /* handleDOMProxies = */ true);
     case ProxyStubType::Generic:
       return tryAttachGenericProxy(obj, objId, id,
                                    /* handleDOMProxies = */ false);
   }
 
   MOZ_CRASH("Unexpected ProxyStubType");
@@ -2055,18 +2019,18 @@ AttachDecision GetPropIRGenerator::tryAt
       if (val_.isNumber()) {
         writer.guardIsNumber(valId);
       } else {
         writer.guardNonDoubleType(valId, val_.type());
       }
       maybeEmitIdGuard(id);
 
       ObjOperandId protoId = writer.loadObject(proto);
-      EmitCallGetterByValueResult(cx_, writer, proto, holder, shape, protoId,
-                                  valId, mode_);
+      EmitCallGetterResult(cx_, writer, proto, holder, shape, protoId, valId,
+                           mode_);
 
       trackAttached("PrimitiveGetter");
       return AttachDecision::Attach;
     }
   }
 
   MOZ_CRASH("Bad NativeGetPropCacheability");
 }
@@ -2745,18 +2709,19 @@ AttachDecision GetNameIRGenerator::tryAt
   writer.guardShape(globalId, globalLexical->global().lastProperty());
 
   if (holder != &globalLexical->global()) {
     // Shape guard holder.
     ObjOperandId holderId = writer.loadObject(holder);
     writer.guardShape(holderId, holder->lastProperty());
   }
 
+  ValOperandId receiverId = writer.boxObject(globalId);
   EmitCallGetterResultNoGuards(cx_, writer, &globalLexical->global(), holder,
-                               shape, globalId);
+                               shape, receiverId);
 
   trackAttached("GlobalNameGetter");
   return AttachDecision::Attach;
 }
 
 static bool NeedEnvironmentShapeGuard(JSObject* envObj) {
   if (!envObj->is<CallObject>()) {
     return true;
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -761,16 +761,20 @@ class MOZ_RAII CacheIRWriter : public JS
     return Int32OperandId(input.id());
   }
 
   NumberOperandId guardIsNumber(ValOperandId input) {
     guardIsNumber_(input);
     return NumberOperandId(input.id());
   }
 
+  ValOperandId boxObject(ObjOperandId input) {
+    return ValOperandId(input.id());
+  }
+
   void guardShapeForClass(ObjOperandId obj, Shape* shape) {
     // Guard shape to ensure that object class is unchanged. This is true
     // for all shapes.
     guardShape(obj, shape);
   }
 
   void guardShapeForOwnProperties(ObjOperandId obj, Shape* shape) {
     // Guard shape to detect changes to (non-dense) own properties. This
@@ -1174,17 +1178,17 @@ class MOZ_RAII GetPropIRGenerator : publ
   HandleValue idVal_;
   HandleValue receiver_;
   GetPropertyResultFlags resultFlags_;
 
   enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
   PreliminaryObjectAction preliminaryObjectAction_;
 
   AttachDecision tryAttachNative(HandleObject obj, ObjOperandId objId,
-                                 HandleId id);
+                                 HandleId id, ValOperandId receiverId);
   AttachDecision tryAttachUnboxed(HandleObject obj, ObjOperandId objId,
                                   HandleId id);
   AttachDecision tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId,
                                          HandleId id);
   AttachDecision tryAttachTypedObject(HandleObject obj, ObjOperandId objId,
                                       HandleId id);
   AttachDecision tryAttachObjectLength(HandleObject obj, ObjOperandId objId,
                                        HandleId id);
@@ -1194,30 +1198,32 @@ class MOZ_RAII GetPropIRGenerator : publ
                                           HandleId id);
   AttachDecision tryAttachWindowProxy(HandleObject obj, ObjOperandId objId,
                                       HandleId id);
   AttachDecision tryAttachCrossCompartmentWrapper(HandleObject obj,
                                                   ObjOperandId objId,
                                                   HandleId id);
   AttachDecision tryAttachXrayCrossCompartmentWrapper(HandleObject obj,
                                                       ObjOperandId objId,
-                                                      HandleId id);
+                                                      HandleId id,
+                                                      ValOperandId receiverId);
   AttachDecision tryAttachFunction(HandleObject obj, ObjOperandId objId,
                                    HandleId id);
 
   AttachDecision tryAttachGenericProxy(HandleObject obj, ObjOperandId objId,
                                        HandleId id, bool handleDOMProxies);
   AttachDecision tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objId,
-                                          HandleId id);
+                                          HandleId id, ValOperandId receiverId);
   AttachDecision tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId,
                                            HandleId id);
   AttachDecision tryAttachDOMProxyUnshadowed(HandleObject obj,
-                                             ObjOperandId objId, HandleId id);
+                                             ObjOperandId objId, HandleId id,
+                                             ValOperandId receiverId);
   AttachDecision tryAttachProxy(HandleObject obj, ObjOperandId objId,
-                                HandleId id);
+                                HandleId id, ValOperandId receiverId);
 
   AttachDecision tryAttachPrimitive(ValOperandId valId, HandleId id);
   AttachDecision tryAttachStringChar(ValOperandId valId, ValOperandId indexId);
   AttachDecision tryAttachStringLength(ValOperandId valId, HandleId id);
   AttachDecision tryAttachMagicArgumentsName(ValOperandId valId, HandleId id);
 
   AttachDecision tryAttachMagicArgument(ValOperandId valId,
                                         ValOperandId indexId);
--- a/js/src/jit/CacheIROps.yaml
+++ b/js/src/jit/CacheIROps.yaml
@@ -1813,43 +1813,26 @@
   args:
     val: BigIntId
 
 - name: CallScriptedGetterResult
   shared: false
   transpile: false
   cost_estimate: 5
   args:
-    obj: ObjId
-    getter: ObjectField
-    sameRealm: BoolImm
-
-- name: CallScriptedGetterByValueResult
-  shared: false
-  transpile: false
-  cost_estimate: 5
-  args:
-    val: ValId
+    receiver: ValId
     getter: ObjectField
     sameRealm: BoolImm
 
 - name: CallNativeGetterResult
   shared: false
   transpile: false
   cost_estimate: 5
   args:
-    obj: ObjId
-    getter: ObjectField
-
-- name: CallNativeGetterByValueResult
-  shared: false
-  transpile: false
-  cost_estimate: 5
-  args:
-    val: ValId
+    receiver: ValId
     getter: ObjectField
 
 - name: ProxyGetResult
   shared: false
   transpile: true
   cost_estimate: 5
   args:
     obj: ObjId
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -897,19 +897,25 @@ bool IonCacheIRCompiler::emitGuardHasGet
   masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectHasGetterSetterPure));
   masm.mov(ReturnReg, scratch1);
   masm.PopRegsInMask(volatileRegs);
 
   masm.branchIfFalseBool(scratch1, failure->label());
   return true;
 }
 
-bool IonCacheIRCompiler::emitCallScriptedGetterResultShared(
-    TypedOrValueRegister receiver, uint32_t getterOffset, bool sameRealm,
-    TypedOrValueRegister output) {
+bool IonCacheIRCompiler::emitCallScriptedGetterResult(ValOperandId receiverId,
+                                                      uint32_t getterOffset,
+                                                      bool sameRealm) {
+  JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
+  AutoSaveLiveRegisters save(*this);
+  AutoOutputRegister output(*this);
+
+  ValueOperand receiver = allocator.useValueRegister(masm, receiverId);
+
   JSFunction* target = &objectStubField(getterOffset)->as<JSFunction>();
   AutoScratchRegister scratch(allocator, masm);
 
   MOZ_ASSERT(sameRealm == (cx_->realm() == target->realm()));
 
   allocator.discardStack(masm);
 
   uint32_t framePushedBefore = masm.framePushed();
@@ -962,45 +968,24 @@ bool IonCacheIRCompiler::emitCallScripte
     masm.switchToRealm(cx_->realm(), ReturnReg);
   }
 
   masm.storeCallResultValue(output);
   masm.freeStack(masm.framePushed() - framePushedBefore);
   return true;
 }
 
-bool IonCacheIRCompiler::emitCallScriptedGetterResult(ObjOperandId objId,
-                                                      uint32_t getterOffset,
-                                                      bool sameRealm) {
+bool IonCacheIRCompiler::emitCallNativeGetterResult(ValOperandId receiverId,
+                                                    uint32_t getterOffset) {
   JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
   AutoSaveLiveRegisters save(*this);
   AutoOutputRegister output(*this);
 
-  Register obj = allocator.useRegister(masm, objId);
-
-  return emitCallScriptedGetterResultShared(
-      TypedOrValueRegister(MIRType::Object, AnyRegister(obj)), getterOffset,
-      sameRealm, output);
-}
-
-bool IonCacheIRCompiler::emitCallScriptedGetterByValueResult(
-    ValOperandId valId, uint32_t getterOffset, bool sameRealm) {
-  JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-  AutoSaveLiveRegisters save(*this);
-  AutoOutputRegister output(*this);
-
-  ValueOperand val = allocator.useValueRegister(masm, valId);
-
-  return emitCallScriptedGetterResultShared(val, getterOffset, sameRealm,
-                                            output);
-}
-
-bool IonCacheIRCompiler::emitCallNativeGetterResultShared(
-    TypedOrValueRegister receiver, uint32_t getterOffset,
-    const AutoOutputRegister& output, AutoSaveLiveRegisters& save) {
+  ValueOperand receiver = allocator.useValueRegister(masm, receiverId);
+
   JSFunction* target = &objectStubField(getterOffset)->as<JSFunction>();
   MOZ_ASSERT(target->isNative());
 
   AutoScratchRegisterMaybeOutput argJSContext(allocator, masm, output);
   AutoScratchRegister argUintN(allocator, masm);
   AutoScratchRegister argVp(allocator, masm);
   AutoScratchRegister scratch(allocator, masm);
 
@@ -1059,40 +1044,16 @@ bool IonCacheIRCompiler::emitCallNativeG
   if (JitOptions.spectreJitToCxxCalls) {
     masm.speculationBarrier();
   }
 
   masm.adjustStack(IonOOLNativeExitFrameLayout::Size(0));
   return true;
 }
 
-bool IonCacheIRCompiler::emitCallNativeGetterResult(ObjOperandId objId,
-                                                    uint32_t getterOffset) {
-  JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-  AutoSaveLiveRegisters save(*this);
-  AutoOutputRegister output(*this);
-
-  Register obj = allocator.useRegister(masm, objId);
-
-  return emitCallNativeGetterResultShared(
-      TypedOrValueRegister(MIRType::Object, AnyRegister(obj)), getterOffset,
-      output, save);
-}
-
-bool IonCacheIRCompiler::emitCallNativeGetterByValueResult(
-    ValOperandId valId, uint32_t getterOffset) {
-  JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-  AutoSaveLiveRegisters save(*this);
-  AutoOutputRegister output(*this);
-
-  ValueOperand val = allocator.useValueRegister(masm, valId);
-
-  return emitCallNativeGetterResultShared(val, getterOffset, output, save);
-}
-
 bool IonCacheIRCompiler::emitProxyGetResult(ObjOperandId objId,
                                             uint32_t idOffset) {
   JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
   AutoSaveLiveRegisters save(*this);
   AutoOutputRegister output(*this);
 
   Register obj = allocator.useRegister(masm, objId);
   jsid id = idStubField(idOffset);
--- a/js/src/jit/IonCacheIRCompiler.h
+++ b/js/src/jit/IonCacheIRCompiler.h
@@ -64,22 +64,16 @@ class MOZ_RAII IonCacheIRCompiler : publ
 
   template <typename Fn, Fn fn>
   void callVM(MacroAssembler& masm);
 
   MOZ_MUST_USE bool emitAddAndStoreSlotShared(
       CacheOp op, ObjOperandId objId, uint32_t offsetOffset, ValOperandId rhsId,
       bool changeGroup, uint32_t newGroupOffset, uint32_t newShapeOffset,
       mozilla::Maybe<uint32_t> numNewSlotsOffset);
-  MOZ_MUST_USE bool emitCallScriptedGetterResultShared(
-      TypedOrValueRegister receiver, uint32_t getterOffset, bool sameRealm,
-      TypedOrValueRegister output);
-  MOZ_MUST_USE bool emitCallNativeGetterResultShared(
-      TypedOrValueRegister receiver, uint32_t getterOffset,
-      const AutoOutputRegister& output, AutoSaveLiveRegisters& save);
 
   bool needsPostBarrier() const;
 
   void pushStubCodePointer();
 
   CACHE_IR_COMPILER_UNSHARED_GENERATED
 };
 
--- a/js/src/jit/VMFunctionList-inl.h
+++ b/js/src/jit/VMFunctionList-inl.h
@@ -71,17 +71,16 @@ namespace jit {
   _(BigIntStringNotEqual,                                                      \
     js::jit::BigIntStringEqual<js::jit::EqualityKind::NotEqual>)               \
   _(BigIntSub, JS::BigInt::sub)                                                \
   _(BindVarOperation, js::BindVarOperation)                                    \
   _(BoxBoxableValue, js::wasm::BoxBoxableValue)                                \
   _(BoxNonStrictThis, js::BoxNonStrictThis)                                    \
   _(BuiltinObjectOperation, js::BuiltinObjectOperation)                        \
   _(CallNativeGetter, js::jit::CallNativeGetter)                               \
-  _(CallNativeGetterByValue, js::jit::CallNativeGetterByValue)                 \
   _(CallNativeSetter, js::jit::CallNativeSetter)                               \
   _(CharCodeAt, js::jit::CharCodeAt)                                           \
   _(CheckClassHeritageOperation, js::CheckClassHeritageOperation)              \
   _(CheckGlobalOrEvalDeclarationConflicts,                                     \
     js::CheckGlobalOrEvalDeclarationConflicts)                                 \
   _(CheckOverRecursed, js::jit::CheckOverRecursed)                             \
   _(CheckOverRecursedBaseline, js::jit::CheckOverRecursedBaseline)             \
   _(CheckPrivateFieldOperation, js::CheckPrivateFieldOperation)                \
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1474,37 +1474,18 @@ bool ThrowBadDerivedReturnOrUninitialize
   return ThrowBadDerivedReturn(cx, v);
 }
 
 bool BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame,
                              MutableHandleValue res) {
   return GetFunctionThis(cx, frame, res);
 }
 
-bool CallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
-                      MutableHandleValue result) {
-  AutoRealm ar(cx, callee);
-
-  MOZ_ASSERT(callee->isNative());
-  JSNative natfun = callee->native();
-
-  JS::RootedValueArray<2> vp(cx);
-  vp[0].setObject(*callee.get());
-  vp[1].setObject(*obj.get());
-
-  if (!natfun(cx, 0, vp.begin())) {
-    return false;
-  }
-
-  result.set(vp[0]);
-  return true;
-}
-
-bool CallNativeGetterByValue(JSContext* cx, HandleFunction callee,
-                             HandleValue receiver, MutableHandleValue result) {
+bool CallNativeGetter(JSContext* cx, HandleFunction callee,
+                      HandleValue receiver, MutableHandleValue result) {
   AutoRealm ar(cx, callee);
 
   MOZ_ASSERT(callee->isNative());
   JSNative natfun = callee->native();
 
   JS::RootedValueArray<2> vp(cx);
   vp[0].setObject(*callee.get());
   vp[1].set(receiver);
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -1070,21 +1070,18 @@ MOZ_MUST_USE bool ThrowBadDerivedReturn(
 
 MOZ_MUST_USE bool ThrowBadDerivedReturnOrUninitializedThis(JSContext* cx,
                                                            HandleValue v);
 
 MOZ_MUST_USE bool BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame,
                                           MutableHandleValue res);
 
 MOZ_MUST_USE bool CallNativeGetter(JSContext* cx, HandleFunction callee,
-                                   HandleObject obj, MutableHandleValue result);
-
-MOZ_MUST_USE bool CallNativeGetterByValue(JSContext* cx, HandleFunction callee,
-                                          HandleValue receiver,
-                                          MutableHandleValue result);
+                                   HandleValue receiver,
+                                   MutableHandleValue result);
 
 MOZ_MUST_USE bool CallNativeSetter(JSContext* cx, HandleFunction callee,
                                    HandleObject obj, HandleValue rhs);
 
 MOZ_MUST_USE bool EqualStringsHelperPure(JSString* str1, JSString* str2);
 
 void HandleCodeCoverageAtPC(BaselineFrame* frame, jsbytecode* pc);
 void HandleCodeCoverageAtPrologue(BaselineFrame* frame);