commit 5b4768d1dd6709c9e7e08b67fc94664396902d1c
parent 62273e72609efc2f03a1a562befb22e93b3c329f
Author: André Bargull <andre.bargull@gmail.com>
Date: Mon, 20 Oct 2025 12:27:44 +0000
Bug 1991402 - Part 19: Make (Specialized)BindFunctionResult shared CacheIR instructions. r=jandem
Inlined GetProp ICs don't have additional arguments we need to load from the stack,
so we don't have to load anything from the stub frame.
Differential Revision: https://phabricator.services.mozilla.com/D266775
Diffstat:
5 files changed, 93 insertions(+), 93 deletions(-)
diff --git a/js/src/jit-test/tests/cacheir/inlinable-native-accessor-6.js b/js/src/jit-test/tests/cacheir/inlinable-native-accessor-6.js
@@ -66,3 +66,17 @@ function testArrayJoin() {
}
}
testArrayJoin();
+
+function testFunctionBind() {
+ Object.defineProperty(Function.prototype, "bound", {get: Function.prototype.bind});
+
+ for (var i = 0; i < 100; ++i) {
+ // |SpecializedBindFunctionResult| CacheIROp.
+ assertEq(function(){ return i; }.bound(), i);
+
+ // |BindFunctionResult| CacheIROp.
+ var r = Math.random.bound();
+ assertEq(0 <= r && r < 1, true);
+ }
+}
+testFunctionBind();
diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -4093,86 +4093,6 @@ bool BaselineCacheIRCompiler::emitNewFunctionCloneResult(
return true;
}
-bool BaselineCacheIRCompiler::emitBindFunctionResult(
- ObjOperandId targetId, uint32_t argc, uint32_t templateObjectOffset) {
- JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-
- AutoOutputRegister output(*this);
- AutoScratchRegister scratch(allocator, masm);
-
- Register target = allocator.useRegister(masm, targetId);
-
- allocator.discardStack(masm);
-
- AutoStubFrame stubFrame(*this);
- stubFrame.enter(masm, scratch);
-
- // Push the arguments in reverse order.
- for (uint32_t i = 0; i < argc; i++) {
- Address argAddress(FramePointer,
- BaselineStubFrameLayout::Size() + i * sizeof(Value));
- masm.pushValue(argAddress);
- }
- masm.moveStackPtrTo(scratch.get());
-
- masm.Push(ImmWord(0)); // nullptr for maybeBound
- masm.Push(Imm32(argc));
- masm.Push(scratch);
- masm.Push(target);
-
- using Fn = BoundFunctionObject* (*)(JSContext*, Handle<JSObject*>, Value*,
- uint32_t, Handle<BoundFunctionObject*>);
- callVM<Fn, BoundFunctionObject::functionBindImpl>(masm);
-
- stubFrame.leave(masm);
- masm.storeCallPointerResult(scratch);
-
- masm.tagValue(JSVAL_TYPE_OBJECT, scratch, output.valueReg());
- return true;
-}
-
-bool BaselineCacheIRCompiler::emitSpecializedBindFunctionResult(
- ObjOperandId targetId, uint32_t argc, uint32_t templateObjectOffset) {
- JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
-
- AutoOutputRegister output(*this);
- AutoScratchRegisterMaybeOutput scratch1(allocator, masm);
- AutoScratchRegister scratch2(allocator, masm);
-
- Register target = allocator.useRegister(masm, targetId);
-
- StubFieldOffset objectField(templateObjectOffset, StubField::Type::JSObject);
- emitLoadStubField(objectField, scratch2);
-
- allocator.discardStack(masm);
-
- AutoStubFrame stubFrame(*this);
- stubFrame.enter(masm, scratch1);
-
- // Push the arguments in reverse order.
- for (uint32_t i = 0; i < argc; i++) {
- Address argAddress(FramePointer,
- BaselineStubFrameLayout::Size() + i * sizeof(Value));
- masm.pushValue(argAddress);
- }
- masm.moveStackPtrTo(scratch1.get());
-
- masm.Push(scratch2);
- masm.Push(Imm32(argc));
- masm.Push(scratch1);
- masm.Push(target);
-
- using Fn = BoundFunctionObject* (*)(JSContext*, Handle<JSObject*>, Value*,
- uint32_t, Handle<BoundFunctionObject*>);
- callVM<Fn, BoundFunctionObject::functionBindSpecializedBaseline>(masm);
-
- stubFrame.leave(masm);
- masm.storeCallPointerResult(scratch1);
-
- masm.tagValue(JSVAL_TYPE_OBJECT, scratch1, output.valueReg());
- return true;
-}
-
bool BaselineCacheIRCompiler::emitCloseIterScriptedResult(
ObjOperandId iterId, ObjOperandId calleeId, CompletionKind kind,
uint32_t calleeNargs) {
diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp
@@ -4548,6 +4548,79 @@ bool CacheIRCompiler::emitLoadFunctionNameResult(ObjOperandId objId) {
return true;
}
+bool CacheIRCompiler::emitBindFunctionResult(ObjOperandId targetId,
+ uint32_t argc,
+ uint32_t templateObjectOffset) {
+ JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
+
+ AutoCallVM callvm(masm, this, allocator);
+ AutoScratchRegisterMaybeOutput scratch(allocator, masm, callvm.output());
+
+ Register target = allocator.useRegister(masm, targetId);
+
+ callvm.prepare();
+
+ if (isBaseline()) {
+ // Push the arguments in reverse order.
+ for (uint32_t i = 0; i < argc; i++) {
+ Address argAddress(FramePointer,
+ BaselineStubFrameLayout::Size() + i * sizeof(Value));
+ masm.pushValue(argAddress);
+ }
+ } else {
+ MOZ_ASSERT(argc == 0, "Call ICs not used in ion");
+ }
+ masm.moveStackPtrTo(scratch.get());
+
+ masm.Push(ImmWord(0)); // nullptr for maybeBound
+ masm.Push(Imm32(argc));
+ masm.Push(scratch);
+ masm.Push(target);
+
+ using Fn = BoundFunctionObject* (*)(JSContext*, Handle<JSObject*>, Value*,
+ uint32_t, Handle<BoundFunctionObject*>);
+ callvm.call<Fn, BoundFunctionObject::functionBindImpl>();
+ return true;
+}
+
+bool CacheIRCompiler::emitSpecializedBindFunctionResult(
+ ObjOperandId targetId, uint32_t argc, uint32_t templateObjectOffset) {
+ JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
+
+ AutoCallVM callvm(masm, this, allocator);
+ AutoScratchRegisterMaybeOutput scratch1(allocator, masm, callvm.output());
+ AutoScratchRegister scratch2(allocator, masm);
+
+ Register target = allocator.useRegister(masm, targetId);
+
+ StubFieldOffset objectField(templateObjectOffset, StubField::Type::JSObject);
+ emitLoadStubField(objectField, scratch2);
+
+ callvm.prepare();
+
+ if (isBaseline()) {
+ // Push the arguments in reverse order.
+ for (uint32_t i = 0; i < argc; i++) {
+ Address argAddress(FramePointer,
+ BaselineStubFrameLayout::Size() + i * sizeof(Value));
+ masm.pushValue(argAddress);
+ }
+ } else {
+ MOZ_ASSERT(argc == 0, "Call ICs not used in ion");
+ }
+ masm.moveStackPtrTo(scratch1.get());
+
+ masm.Push(scratch2);
+ masm.Push(Imm32(argc));
+ masm.Push(scratch1);
+ masm.Push(target);
+
+ using Fn = BoundFunctionObject* (*)(JSContext*, Handle<JSObject*>, Value*,
+ uint32_t, Handle<BoundFunctionObject*>);
+ callvm.call<Fn, BoundFunctionObject::functionBindSpecializedBaseline>();
+ return true;
+}
+
bool CacheIRCompiler::emitLinearizeForCharAccess(StringOperandId strId,
Int32OperandId indexId,
StringOperandId resultId) {
@@ -12027,6 +12100,10 @@ template <>
struct ReturnTypeToJSValueType<SetObject*> {
static constexpr JSValueType result = JSVAL_TYPE_OBJECT;
};
+template <>
+struct ReturnTypeToJSValueType<BoundFunctionObject*> {
+ static constexpr JSValueType result = JSVAL_TYPE_OBJECT;
+};
template <typename Fn>
void AutoCallVM::storeResult() {
diff --git a/js/src/jit/CacheIROps.yaml b/js/src/jit/CacheIROps.yaml
@@ -2254,7 +2254,7 @@
thisShape: ShapeField
- name: BindFunctionResult
- shared: false
+ shared: true
transpile: true
cost_estimate: 5
args:
@@ -2263,7 +2263,7 @@
templateObject: ObjectField
- name: SpecializedBindFunctionResult
- shared: false
+ shared: true
transpile: true
cost_estimate: 4
args:
diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp
@@ -2308,17 +2308,6 @@ bool IonCacheIRCompiler::emitCallInlinedFunction(ObjOperandId calleeId,
MOZ_CRASH("Call ICs not used in ion");
}
-bool IonCacheIRCompiler::emitBindFunctionResult(ObjOperandId targetId,
- uint32_t argc,
- uint32_t templateObjectOffset) {
- MOZ_CRASH("Call ICs not used in ion");
-}
-
-bool IonCacheIRCompiler::emitSpecializedBindFunctionResult(
- ObjOperandId targetId, uint32_t argc, uint32_t templateObjectOffset) {
- MOZ_CRASH("Call ICs not used in ion");
-}
-
bool IonCacheIRCompiler::emitLoadArgumentFixedSlot(ValOperandId resultId,
uint8_t slotIndex) {
MOZ_CRASH("Call ICs not used in ion");