[nojit] Refactor CallApiCallback calling convention
This is the first (and major) step towards converting CallApiCallback and CallApiGetter stubs into builtins. The CallApiCallbackStub was parameterized with the number of arguments passed on the stack. This CL converts the compile-time parameter into an explicit runtime parameter, and removes all uses of the stub parameter. Drive-by: The implementation is now mostly consistent across platforms. Drive-by: Refactor the calling convention to free up two registers (kCallData and kHolder are now passed on the stack). Bug: v8:7777 Change-Id: I212dccc2930de89c264a13755918c9fae7842f1f Reviewed-on: https://chromium-review.googlesource.com/c/1354887 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#58005}
This commit is contained in:
parent
f40638d148
commit
c6b0e12e4e
@ -351,20 +351,32 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
|
||||
void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r4 : call_data
|
||||
// -- r2 : holder
|
||||
// -- r1 : api_function_address
|
||||
// -- cp : context
|
||||
// -- cp : kTargetContext
|
||||
// -- r1 : kApiFunctionAddress
|
||||
// -- r2 : kArgc
|
||||
// --
|
||||
// -- sp[0] : last argument
|
||||
// -- ...
|
||||
// -- sp[(argc - 1) * 4] : first argument
|
||||
// -- sp[argc * 4] : receiver
|
||||
// -- sp[(argc + 0) * 4] : receiver
|
||||
// -- sp[(argc + 1) * 4] : kHolder
|
||||
// -- sp[(argc + 2) * 4] : kCallData
|
||||
// -----------------------------------
|
||||
|
||||
Register call_data = r4;
|
||||
Register holder = r2;
|
||||
Register api_function_address = r1;
|
||||
Register argc = r2;
|
||||
Register scratch = r4;
|
||||
Register index = r5; // For indexing MemOperands.
|
||||
|
||||
DCHECK(!AreAliased(api_function_address, argc, scratch, index));
|
||||
|
||||
// Stack offsets (without argc).
|
||||
static constexpr int kReceiverOffset = 0;
|
||||
static constexpr int kHolderOffset = kReceiverOffset + 1;
|
||||
static constexpr int kCallDataOffset = kHolderOffset + 1;
|
||||
|
||||
// Extra stack arguments are: the receiver, kHolder, kCallData.
|
||||
static constexpr int kExtraStackArgumentCount = 3;
|
||||
|
||||
typedef FunctionCallbackArguments FCA;
|
||||
|
||||
@ -376,60 +388,88 @@ void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
STATIC_ASSERT(FCA::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(FCA::kHolderIndex == 0);
|
||||
|
||||
// new target
|
||||
__ PushRoot(RootIndex::kUndefinedValue);
|
||||
// Set up FunctionCallbackInfo's implicit_args on the stack as follows:
|
||||
//
|
||||
// Target state:
|
||||
// sp[0 * kPointerSize]: kHolder
|
||||
// sp[1 * kPointerSize]: kIsolate
|
||||
// sp[2 * kPointerSize]: undefined (kReturnValueDefaultValue)
|
||||
// sp[3 * kPointerSize]: undefined (kReturnValue)
|
||||
// sp[4 * kPointerSize]: kData
|
||||
// sp[5 * kPointerSize]: undefined (kNewTarget)
|
||||
|
||||
// call data
|
||||
__ push(call_data);
|
||||
// Reserve space on the stack.
|
||||
__ sub(sp, sp, Operand(FCA::kArgsLength * kPointerSize));
|
||||
|
||||
Register scratch0 = call_data;
|
||||
Register scratch1 = r5;
|
||||
__ LoadRoot(scratch0, RootIndex::kUndefinedValue);
|
||||
// return value
|
||||
__ push(scratch0);
|
||||
// return value default
|
||||
__ push(scratch0);
|
||||
// isolate
|
||||
__ Move(scratch1, ExternalReference::isolate_address(masm->isolate()));
|
||||
__ push(scratch1);
|
||||
// holder
|
||||
__ push(holder);
|
||||
// kHolder.
|
||||
__ add(index, argc, Operand(FCA::kArgsLength + kHolderOffset));
|
||||
__ ldr(scratch, MemOperand(sp, index, LSL, kPointerSizeLog2));
|
||||
__ str(scratch, MemOperand(sp, 0 * kPointerSize));
|
||||
|
||||
// Prepare arguments.
|
||||
__ mov(scratch0, sp);
|
||||
// kIsolate.
|
||||
__ Move(scratch, ExternalReference::isolate_address(masm->isolate()));
|
||||
__ str(scratch, MemOperand(sp, 1 * kPointerSize));
|
||||
|
||||
// kReturnValueDefaultValue, kReturnValue, and kNewTarget.
|
||||
__ LoadRoot(scratch, RootIndex::kUndefinedValue);
|
||||
__ str(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||
__ str(scratch, MemOperand(sp, 3 * kPointerSize));
|
||||
__ str(scratch, MemOperand(sp, 5 * kPointerSize));
|
||||
|
||||
// kData.
|
||||
__ add(index, argc, Operand(FCA::kArgsLength + kCallDataOffset));
|
||||
__ ldr(scratch, MemOperand(sp, index, LSL, kPointerSizeLog2));
|
||||
__ str(scratch, MemOperand(sp, 4 * kPointerSize));
|
||||
|
||||
// Keep a pointer to kHolder (= implicit_args) in a scratch register.
|
||||
// We use it below to set up the FunctionCallbackInfo object.
|
||||
__ mov(scratch, sp);
|
||||
|
||||
// Allocate the v8::Arguments structure in the arguments' space since
|
||||
// it's not controlled by GC.
|
||||
const int kApiStackSpace = 3;
|
||||
|
||||
static constexpr int kApiStackSpace = 4;
|
||||
static constexpr bool kDontSaveDoubles = false;
|
||||
FrameScope frame_scope(masm, StackFrame::MANUAL);
|
||||
__ EnterExitFrame(false, kApiStackSpace);
|
||||
__ EnterExitFrame(kDontSaveDoubles, kApiStackSpace);
|
||||
|
||||
DCHECK(api_function_address != r0 && scratch0 != r0);
|
||||
// r0 = FunctionCallbackInfo&
|
||||
// Arguments is after the return address.
|
||||
// FunctionCallbackInfo::implicit_args_ (points at kHolder as set up above).
|
||||
// Arguments are after the return address (pushed by EnterExitFrame()).
|
||||
__ str(scratch, MemOperand(sp, 1 * kPointerSize));
|
||||
|
||||
// FunctionCallbackInfo::values_ (points at the first varargs argument passed
|
||||
// on the stack).
|
||||
__ add(scratch, scratch, Operand((FCA::kArgsLength - 1) * kPointerSize));
|
||||
__ add(scratch, scratch, Operand(argc, LSL, kPointerSizeLog2));
|
||||
__ str(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||
|
||||
// FunctionCallbackInfo::length_.
|
||||
__ str(argc, MemOperand(sp, 3 * kPointerSize));
|
||||
|
||||
// We also store the number of bytes to drop from the stack after returning
|
||||
// from the API function here.
|
||||
__ mov(scratch,
|
||||
Operand((FCA::kArgsLength + kExtraStackArgumentCount) * kPointerSize));
|
||||
__ add(scratch, scratch, Operand(argc, LSL, kPointerSizeLog2));
|
||||
__ str(scratch, MemOperand(sp, 4 * kPointerSize));
|
||||
|
||||
// v8::InvocationCallback's argument.
|
||||
__ add(r0, sp, Operand(1 * kPointerSize));
|
||||
// FunctionCallbackInfo::implicit_args_
|
||||
__ str(scratch0, MemOperand(r0, 0 * kPointerSize));
|
||||
// FunctionCallbackInfo::values_
|
||||
__ add(scratch1, scratch0,
|
||||
Operand((FCA::kArgsLength - 1 + argc()) * kPointerSize));
|
||||
__ str(scratch1, MemOperand(r0, 1 * kPointerSize));
|
||||
// FunctionCallbackInfo::length_ = argc
|
||||
__ mov(scratch0, Operand(argc()));
|
||||
__ str(scratch0, MemOperand(r0, 2 * kPointerSize));
|
||||
|
||||
ExternalReference thunk_ref = ExternalReference::invoke_function_callback();
|
||||
|
||||
AllowExternalCallThatCantCauseGC scope(masm);
|
||||
// Stores return the first js argument
|
||||
int return_value_offset = 2 + FCA::kReturnValueOffset;
|
||||
MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
|
||||
const int stack_space = argc() + FCA::kArgsLength + 1;
|
||||
MemOperand* stack_space_operand = nullptr;
|
||||
// There are two stack slots above the arguments we constructed on the stack.
|
||||
// TODO(jgruber): Document what these arguments are.
|
||||
static constexpr int kStackSlotsAboveFCA = 2;
|
||||
MemOperand return_value_operand(
|
||||
fp, (kStackSlotsAboveFCA + FCA::kReturnValueOffset) * kPointerSize);
|
||||
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, stack_space,
|
||||
stack_space_operand, return_value_operand);
|
||||
static constexpr int kUseStackSpaceOperand = 0;
|
||||
MemOperand stack_space_operand(sp, 4 * kPointerSize);
|
||||
|
||||
AllowExternalCallThatCantCauseGC scope(masm);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kUseStackSpaceOperand, &stack_space_operand,
|
||||
return_value_operand);
|
||||
}
|
||||
|
||||
|
||||
@ -490,8 +530,10 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
MemOperand return_value_operand(
|
||||
fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
MemOperand* const kUseStackSpaceConstant = nullptr;
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kStackUnwindSpace, nullptr, return_value_operand);
|
||||
kStackUnwindSpace, kUseStackSpaceConstant,
|
||||
return_value_operand);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
@ -202,10 +202,9 @@ void ArgumentsAdaptorDescriptor::InitializePlatformSpecific(
|
||||
void ApiCallbackDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {
|
||||
JavaScriptFrame::context_register(), // callee context
|
||||
r4, // call_data
|
||||
r2, // holder
|
||||
r1, // api_function_address
|
||||
JavaScriptFrame::context_register(), // kTargetContext
|
||||
r1, // kApiFunctionAddress
|
||||
r2, // kArgc
|
||||
};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
@ -232,8 +232,7 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
|
||||
// The number of register that CallApiFunctionAndReturn will need to save on
|
||||
// the stack. The space for these registers need to be allocated in the
|
||||
// ExitFrame before calling CallApiFunctionAndReturn.
|
||||
static const int kCallApiFunctionSpillSpace = 4;
|
||||
|
||||
static constexpr int kCallApiFunctionSpillSpace = 4;
|
||||
|
||||
static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
|
||||
return static_cast<int>(ref0.address() - ref1.address());
|
||||
@ -248,7 +247,9 @@ static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
|
||||
static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
Register function_address,
|
||||
ExternalReference thunk_ref,
|
||||
int stack_space, int spill_offset,
|
||||
int stack_space,
|
||||
MemOperand* stack_space_operand,
|
||||
int spill_offset,
|
||||
MemOperand return_value_operand) {
|
||||
ASM_LOCATION("CallApiFunctionAndReturn");
|
||||
Isolate* isolate = masm->isolate();
|
||||
@ -349,6 +350,12 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
__ Peek(x21, (spill_offset + 2) * kXRegSize);
|
||||
__ Peek(x22, (spill_offset + 3) * kXRegSize);
|
||||
|
||||
if (stack_space_operand != nullptr) {
|
||||
CHECK_EQ(stack_space, 0);
|
||||
// Load the number of stack slots to drop before LeaveExitFrame modifies sp.
|
||||
__ Ldr(x19, *stack_space_operand);
|
||||
}
|
||||
|
||||
__ LeaveExitFrame(false, x1, x5);
|
||||
|
||||
// Check if the function scheduled an exception.
|
||||
@ -356,7 +363,14 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
__ Ldr(x5, MemOperand(x5));
|
||||
__ JumpIfNotRoot(x5, RootIndex::kTheHoleValue, &promote_scheduled_exception);
|
||||
|
||||
__ DropSlots(stack_space);
|
||||
if (stack_space_operand == nullptr) {
|
||||
CHECK_NE(stack_space, 0);
|
||||
__ DropSlots(stack_space);
|
||||
} else {
|
||||
CHECK_EQ(stack_space, 0);
|
||||
__ DropArguments(x19);
|
||||
}
|
||||
|
||||
__ Ret();
|
||||
|
||||
// Re-throw by promoting a scheduled exception.
|
||||
@ -377,20 +391,32 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
|
||||
void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- x4 : call_data
|
||||
// -- x2 : holder
|
||||
// -- x1 : api_function_address
|
||||
// -- cp : context
|
||||
// -- cp : kTargetContext
|
||||
// -- r1 : kApiFunctionAddress
|
||||
// -- r2 : kArgc
|
||||
// --
|
||||
// -- sp[0] : last argument
|
||||
// -- ...
|
||||
// -- sp[(argc - 1) * 8] : first argument
|
||||
// -- sp[argc * 8] : receiver
|
||||
// -- sp[(argc + 0) * 8] : receiver
|
||||
// -- sp[(argc + 1) * 8] : kHolder
|
||||
// -- sp[(argc + 2) * 8] : kCallData
|
||||
// -----------------------------------
|
||||
|
||||
Register call_data = x4;
|
||||
Register holder = x2;
|
||||
Register api_function_address = x1;
|
||||
Register argc = x2;
|
||||
Register scratch = x4;
|
||||
Register index = x5; // For indexing MemOperands.
|
||||
|
||||
DCHECK(!AreAliased(api_function_address, argc, scratch, index));
|
||||
|
||||
// Stack offsets (without argc).
|
||||
static constexpr int kReceiverOffset = 0;
|
||||
static constexpr int kHolderOffset = kReceiverOffset + 1;
|
||||
static constexpr int kCallDataOffset = kHolderOffset + 1;
|
||||
|
||||
// Extra stack arguments are: the receiver, kHolder, kCallData.
|
||||
static constexpr int kExtraStackArgumentCount = 3;
|
||||
|
||||
typedef FunctionCallbackArguments FCA;
|
||||
|
||||
@ -402,61 +428,97 @@ void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
STATIC_ASSERT(FCA::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(FCA::kHolderIndex == 0);
|
||||
|
||||
Register undef = x7;
|
||||
__ LoadRoot(undef, RootIndex::kUndefinedValue);
|
||||
// Set up FunctionCallbackInfo's implicit_args on the stack as follows:
|
||||
//
|
||||
// Target state:
|
||||
// sp[0 * kPointerSize]: kHolder
|
||||
// sp[1 * kPointerSize]: kIsolate
|
||||
// sp[2 * kPointerSize]: undefined (kReturnValueDefaultValue)
|
||||
// sp[3 * kPointerSize]: undefined (kReturnValue)
|
||||
// sp[4 * kPointerSize]: kData
|
||||
// sp[5 * kPointerSize]: undefined (kNewTarget)
|
||||
|
||||
// Push new target, call data.
|
||||
__ Push(undef, call_data);
|
||||
// Reserve space on the stack.
|
||||
__ Sub(sp, sp, Operand(FCA::kArgsLength * kPointerSize));
|
||||
|
||||
Register isolate_reg = x5;
|
||||
__ Mov(isolate_reg, ExternalReference::isolate_address(masm->isolate()));
|
||||
// kHolder.
|
||||
__ Add(index, argc, Operand(FCA::kArgsLength + kHolderOffset));
|
||||
__ Ldr(scratch, MemOperand(sp, index, LSL, kPointerSizeLog2));
|
||||
__ Str(scratch, MemOperand(sp, 0 * kPointerSize));
|
||||
|
||||
// FunctionCallbackArguments:
|
||||
// return value, return value default, isolate, holder.
|
||||
__ Push(undef, undef, isolate_reg, holder);
|
||||
// kIsolate.
|
||||
__ Mov(scratch, ExternalReference::isolate_address(masm->isolate()));
|
||||
__ Str(scratch, MemOperand(sp, 1 * kPointerSize));
|
||||
|
||||
// Prepare arguments.
|
||||
Register args = x6;
|
||||
__ Mov(args, sp);
|
||||
// kReturnValueDefaultValue, kReturnValue, and kNewTarget.
|
||||
__ LoadRoot(scratch, RootIndex::kUndefinedValue);
|
||||
__ Str(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||
__ Str(scratch, MemOperand(sp, 3 * kPointerSize));
|
||||
__ Str(scratch, MemOperand(sp, 5 * kPointerSize));
|
||||
|
||||
// kData.
|
||||
__ Add(index, argc, Operand(FCA::kArgsLength + kCallDataOffset));
|
||||
__ Ldr(scratch, MemOperand(sp, index, LSL, kPointerSizeLog2));
|
||||
__ Str(scratch, MemOperand(sp, 4 * kPointerSize));
|
||||
|
||||
// Keep a pointer to kHolder (= implicit_args) in a scratch register.
|
||||
// We use it below to set up the FunctionCallbackInfo object.
|
||||
__ Mov(scratch, sp);
|
||||
|
||||
// Allocate the v8::Arguments structure in the arguments' space, since it's
|
||||
// not controlled by GC.
|
||||
const int kApiStackSpace = 3;
|
||||
|
||||
// Allocate space so that CallApiFunctionAndReturn can store some scratch
|
||||
// registers on the stack.
|
||||
const int kCallApiFunctionSpillSpace = 4;
|
||||
static constexpr int kApiStackSpace = 4;
|
||||
static constexpr bool kDontSaveDoubles = false;
|
||||
|
||||
FrameScope frame_scope(masm, StackFrame::MANUAL);
|
||||
__ EnterExitFrame(false, x10, kApiStackSpace + kCallApiFunctionSpillSpace);
|
||||
__ EnterExitFrame(kDontSaveDoubles, x10,
|
||||
kApiStackSpace + kCallApiFunctionSpillSpace);
|
||||
|
||||
// FunctionCallbackInfo::implicit_args_ (points at kHolder as set up above).
|
||||
// Arguments are after the return address (pushed by EnterExitFrame()).
|
||||
__ Str(scratch, MemOperand(sp, 1 * kPointerSize));
|
||||
|
||||
// FunctionCallbackInfo::values_ (points at the first varargs argument passed
|
||||
// on the stack).
|
||||
__ Add(scratch, scratch, Operand((FCA::kArgsLength - 1) * kPointerSize));
|
||||
__ Add(scratch, scratch, Operand(argc, LSL, kPointerSizeLog2));
|
||||
__ Str(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||
|
||||
// FunctionCallbackInfo::length_.
|
||||
__ Str(argc, MemOperand(sp, 3 * kPointerSize));
|
||||
|
||||
// We also store the number of slots to drop from the stack after returning
|
||||
// from the API function here.
|
||||
// Note: Unlike on other architectures, this stores the number of slots to
|
||||
// drop, not the number of bytes. arm64 must always drop a slot count that is
|
||||
// a multiple of two, and related helper functions (DropArguments) expect a
|
||||
// register containing the slot count.
|
||||
__ Add(scratch, argc, Operand(FCA::kArgsLength + kExtraStackArgumentCount));
|
||||
__ Str(scratch, MemOperand(sp, 4 * kPointerSize));
|
||||
|
||||
// v8::InvocationCallback's argument.
|
||||
DCHECK(!AreAliased(x0, api_function_address));
|
||||
// x0 = FunctionCallbackInfo&
|
||||
// Arguments is after the return address.
|
||||
__ SlotAddress(x0, 1);
|
||||
// FunctionCallbackInfo::implicit_args_ and FunctionCallbackInfo::values_
|
||||
__ Add(x10, args, Operand((FCA::kArgsLength - 1 + argc()) * kPointerSize));
|
||||
__ Stp(args, x10, MemOperand(x0, 0 * kPointerSize));
|
||||
// FunctionCallbackInfo::length_ = argc
|
||||
__ Mov(x10, argc());
|
||||
__ Str(x10, MemOperand(x0, 2 * kPointerSize));
|
||||
__ add(x0, sp, Operand(1 * kPointerSize));
|
||||
|
||||
ExternalReference thunk_ref = ExternalReference::invoke_function_callback();
|
||||
|
||||
AllowExternalCallThatCantCauseGC scope(masm);
|
||||
// Stores return the first js argument
|
||||
int return_value_offset = 2 + FCA::kReturnValueOffset;
|
||||
MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
|
||||
// The number of arguments might be odd, but will be padded when calling the
|
||||
// stub. We do not round up stack_space to account for odd argc here, this
|
||||
// will be done in CallApiFunctionAndReturn.
|
||||
const int stack_space = (argc() + 1) + FCA::kArgsLength;
|
||||
|
||||
// The current frame needs to be aligned.
|
||||
DCHECK_EQ((stack_space - (argc() + 1)) % 2, 0);
|
||||
const int spill_offset = 1 + kApiStackSpace;
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, stack_space,
|
||||
spill_offset, return_value_operand);
|
||||
DCHECK_EQ(FCA::kArgsLength % 2, 0);
|
||||
|
||||
// There are two stack slots above the arguments we constructed on the stack.
|
||||
// TODO(jgruber): Document what these arguments are.
|
||||
static constexpr int kStackSlotsAboveFCA = 2;
|
||||
MemOperand return_value_operand(
|
||||
fp, (kStackSlotsAboveFCA + FCA::kReturnValueOffset) * kPointerSize);
|
||||
|
||||
static constexpr int kSpillOffset = 1 + kApiStackSpace;
|
||||
static constexpr int kUseStackSpaceOperand = 0;
|
||||
MemOperand stack_space_operand(sp, 4 * kPointerSize);
|
||||
|
||||
AllowExternalCallThatCantCauseGC scope(masm);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kUseStackSpaceOperand, &stack_space_operand,
|
||||
kSpillOffset, return_value_operand);
|
||||
}
|
||||
|
||||
|
||||
@ -504,10 +566,6 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
const int kApiStackSpace = 1;
|
||||
|
||||
// Allocate space so that CallApiFunctionAndReturn can store some scratch
|
||||
// registers on the stack.
|
||||
const int kCallApiFunctionSpillSpace = 4;
|
||||
|
||||
FrameScope frame_scope(masm, StackFrame::MANUAL);
|
||||
__ EnterExitFrame(false, x10, kApiStackSpace + kCallApiFunctionSpillSpace);
|
||||
|
||||
@ -530,9 +588,10 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
MemOperand return_value_operand(
|
||||
fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
MemOperand* const kUseStackSpaceConstant = nullptr;
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kStackUnwindSpace, spill_offset,
|
||||
return_value_operand);
|
||||
kStackUnwindSpace, kUseStackSpaceConstant,
|
||||
spill_offset, return_value_operand);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
@ -206,10 +206,9 @@ void ArgumentsAdaptorDescriptor::InitializePlatformSpecific(
|
||||
void ApiCallbackDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {
|
||||
JavaScriptFrame::context_register(), // callee context
|
||||
x4, // call_data
|
||||
x2, // holder
|
||||
x1, // api_function_address
|
||||
JavaScriptFrame::context_register(), // kTargetContext
|
||||
x1, // kApiFunctionAddress
|
||||
x2, // kArgc
|
||||
};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
@ -2868,9 +2868,6 @@ Reduction JSCallReducer::ReduceCallApiFunction(
|
||||
Handle<FunctionTemplateInfo> function_template_info(
|
||||
FunctionTemplateInfo::cast(shared.object()->function_data()), isolate());
|
||||
|
||||
// CallApiCallbackStub expects the target in a register, so we count it out,
|
||||
// and counts the receiver as an implicit argument, so we count the receiver
|
||||
// out too.
|
||||
if (argc > CallApiCallbackStub::kArgMax) return NoChange();
|
||||
|
||||
// Infer the {receiver} maps, and check if we can inline the API function
|
||||
@ -2945,13 +2942,14 @@ Reduction JSCallReducer::ReduceCallApiFunction(
|
||||
node->InsertInput(graph()->zone(), 0,
|
||||
jsgraph()->HeapConstant(call_api_callback.code()));
|
||||
node->ReplaceInput(1, context);
|
||||
node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(data));
|
||||
node->InsertInput(graph()->zone(), 3, holder);
|
||||
node->InsertInput(graph()->zone(), 4,
|
||||
node->InsertInput(graph()->zone(), 2,
|
||||
jsgraph()->ExternalConstant(function_reference));
|
||||
node->ReplaceInput(5, receiver);
|
||||
node->RemoveInput(6 + argc); // Remove context input.
|
||||
node->ReplaceInput(7 + argc, effect); // Update effect input.
|
||||
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(argc));
|
||||
node->InsertInput(graph()->zone(), 4, jsgraph()->Constant(data));
|
||||
node->InsertInput(graph()->zone(), 5, holder);
|
||||
node->ReplaceInput(6, receiver);
|
||||
node->RemoveInput(7 + argc); // Remove context input.
|
||||
node->ReplaceInput(8 + argc, effect); // Update effect input.
|
||||
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
|
||||
return Changed(node);
|
||||
}
|
||||
|
@ -2038,16 +2038,17 @@ Node* JSNativeContextSpecialization::InlineApiCall(
|
||||
|
||||
// Add CallApiCallbackStub's register argument as well.
|
||||
Node* context = jsgraph()->Constant(native_context());
|
||||
Node* inputs[10] = {code, context, data, holder, function_reference,
|
||||
receiver};
|
||||
int index = 6 + argc;
|
||||
Node* inputs[11] = {
|
||||
code, context, function_reference, jsgraph()->Constant(argc), data,
|
||||
holder, receiver};
|
||||
int index = 7 + argc;
|
||||
inputs[index++] = frame_state;
|
||||
inputs[index++] = *effect;
|
||||
inputs[index++] = *control;
|
||||
// This needs to stay here because of the edge case described in
|
||||
// http://crbug.com/675648.
|
||||
if (value != nullptr) {
|
||||
inputs[6] = value;
|
||||
inputs[7] = value;
|
||||
}
|
||||
|
||||
return *effect = *control =
|
||||
|
@ -294,22 +294,32 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
|
||||
void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : call_data
|
||||
// -- ecx : holder
|
||||
// -- edx : api_function_address
|
||||
// -- esi : context
|
||||
// -- esi : kTargetContext
|
||||
// -- edx : kApiFunctionAddress
|
||||
// -- ecx : kArgc
|
||||
// --
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : last argument
|
||||
// -- ...
|
||||
// -- esp[argc * 4] : first argument
|
||||
// -- esp[(argc + 1) * 4] : receiver
|
||||
// -- esp[(argc + 2) * 4] : kHolder
|
||||
// -- esp[(argc + 3) * 4] : kCallData
|
||||
// -----------------------------------
|
||||
|
||||
Register call_data = eax;
|
||||
Register holder = ecx;
|
||||
Register api_function_address = edx;
|
||||
Register return_address = edi;
|
||||
Register argc = ecx;
|
||||
Register scratch = eax;
|
||||
|
||||
DCHECK(!AreAliased(api_function_address, argc, scratch));
|
||||
|
||||
// Stack offsets (without argc).
|
||||
static constexpr int kReceiverOffset = kPointerSize;
|
||||
static constexpr int kHolderOffset = kReceiverOffset + kPointerSize;
|
||||
static constexpr int kCallDataOffset = kHolderOffset + kPointerSize;
|
||||
|
||||
// Extra stack arguments are: the receiver, kHolder, kCallData.
|
||||
static constexpr int kExtraStackArgumentCount = 3;
|
||||
|
||||
typedef FunctionCallbackArguments FCA;
|
||||
|
||||
@ -321,64 +331,100 @@ void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
STATIC_ASSERT(FCA::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(FCA::kHolderIndex == 0);
|
||||
|
||||
__ pop(return_address);
|
||||
// Set up FunctionCallbackInfo's implicit_args on the stack as follows:
|
||||
//
|
||||
// Current state:
|
||||
// esp[0]: return address
|
||||
//
|
||||
// Target state:
|
||||
// esp[0 * kPointerSize]: return address
|
||||
// esp[1 * kPointerSize]: kHolder
|
||||
// esp[2 * kPointerSize]: kIsolate
|
||||
// esp[3 * kPointerSize]: undefined (kReturnValueDefaultValue)
|
||||
// esp[4 * kPointerSize]: undefined (kReturnValue)
|
||||
// esp[5 * kPointerSize]: kData
|
||||
// esp[6 * kPointerSize]: undefined (kNewTarget)
|
||||
|
||||
// new target
|
||||
__ PushRoot(RootIndex::kUndefinedValue);
|
||||
// Reserve space on the stack.
|
||||
__ sub(esp, Immediate(FCA::kArgsLength * kPointerSize));
|
||||
|
||||
// call data
|
||||
__ push(call_data);
|
||||
// Return address (the old stack location is overwritten later on).
|
||||
__ mov(scratch, Operand(esp, FCA::kArgsLength * kPointerSize));
|
||||
__ mov(Operand(esp, 0 * kPointerSize), scratch);
|
||||
|
||||
// return value
|
||||
__ PushRoot(RootIndex::kUndefinedValue);
|
||||
// return value default
|
||||
__ PushRoot(RootIndex::kUndefinedValue);
|
||||
// isolate
|
||||
__ Push(Immediate(ExternalReference::isolate_address(isolate())));
|
||||
// holder
|
||||
__ push(holder);
|
||||
// kHolder.
|
||||
__ mov(scratch, Operand(esp, argc, times_pointer_size,
|
||||
FCA::kArgsLength * kPointerSize + kHolderOffset));
|
||||
__ mov(Operand(esp, 1 * kPointerSize), scratch);
|
||||
|
||||
Register scratch = call_data;
|
||||
// kIsolate.
|
||||
__ Move(scratch,
|
||||
Immediate(ExternalReference::isolate_address(masm->isolate())));
|
||||
__ mov(Operand(esp, 2 * kPointerSize), scratch);
|
||||
|
||||
__ mov(scratch, esp);
|
||||
// kReturnValueDefaultValue, kReturnValue, and kNewTarget.
|
||||
__ LoadRoot(scratch, RootIndex::kUndefinedValue);
|
||||
__ mov(Operand(esp, 3 * kPointerSize), scratch);
|
||||
__ mov(Operand(esp, 4 * kPointerSize), scratch);
|
||||
__ mov(Operand(esp, 6 * kPointerSize), scratch);
|
||||
|
||||
// push return address
|
||||
__ push(return_address);
|
||||
// kData.
|
||||
__ mov(scratch, Operand(esp, argc, times_pointer_size,
|
||||
FCA::kArgsLength * kPointerSize + kCallDataOffset));
|
||||
__ mov(Operand(esp, 5 * kPointerSize), scratch);
|
||||
|
||||
// API function gets reference to the v8::Arguments. If CPU profiler
|
||||
// is enabled wrapper function will be called and we need to pass
|
||||
// address of the callback as additional parameter, always allocate
|
||||
// Keep a pointer to kHolder (= implicit_args) in a scratch register.
|
||||
// We use it below to set up the FunctionCallbackInfo object.
|
||||
__ lea(scratch, Operand(esp, 1 * kPointerSize));
|
||||
|
||||
// The API function takes a reference to v8::Arguments. If the CPU profiler
|
||||
// is enabled, a wrapper function will be called and we need to pass
|
||||
// the address of the callback as an additional parameter. Always allocate
|
||||
// space for it.
|
||||
const int kApiArgc = 1 + 1;
|
||||
static constexpr int kApiArgc = 1 + 1;
|
||||
|
||||
// Allocate the v8::Arguments structure in the arguments' space since
|
||||
// it's not controlled by GC.
|
||||
const int kApiStackSpace = 3;
|
||||
static constexpr int kApiStackSpace = 4;
|
||||
|
||||
PrepareCallApiFunction(masm, kApiArgc + kApiStackSpace, edi);
|
||||
|
||||
// FunctionCallbackInfo::implicit_args_.
|
||||
__ mov(ApiParameterOperand(2), scratch);
|
||||
__ add(scratch, Immediate((argc() + FCA::kArgsLength - 1) * kPointerSize));
|
||||
// FunctionCallbackInfo::values_.
|
||||
__ mov(ApiParameterOperand(3), scratch);
|
||||
// FunctionCallbackInfo::implicit_args_ (points at kHolder as set up above).
|
||||
__ mov(ApiParameterOperand(kApiArgc + 0), scratch);
|
||||
|
||||
// FunctionCallbackInfo::values_ (points at the first varargs argument passed
|
||||
// on the stack).
|
||||
__ lea(scratch, Operand(scratch, argc, times_pointer_size,
|
||||
(FCA::kArgsLength - 1) * kPointerSize));
|
||||
__ mov(ApiParameterOperand(kApiArgc + 1), scratch);
|
||||
|
||||
// FunctionCallbackInfo::length_.
|
||||
__ Move(ApiParameterOperand(4), Immediate(argc()));
|
||||
__ mov(ApiParameterOperand(kApiArgc + 2), argc);
|
||||
|
||||
// We also store the number of bytes to drop from the stack after returning
|
||||
// from the API function here.
|
||||
__ lea(scratch,
|
||||
Operand(argc, times_pointer_size,
|
||||
(FCA::kArgsLength + kExtraStackArgumentCount) * kPointerSize));
|
||||
__ mov(ApiParameterOperand(kApiArgc + 3), scratch);
|
||||
|
||||
// v8::InvocationCallback's argument.
|
||||
__ lea(scratch, ApiParameterOperand(2));
|
||||
__ lea(scratch, ApiParameterOperand(kApiArgc + 0));
|
||||
__ mov(ApiParameterOperand(0), scratch);
|
||||
|
||||
ExternalReference thunk_ref = ExternalReference::invoke_function_callback();
|
||||
|
||||
// Stores return the first js argument
|
||||
int return_value_offset = 2 + FCA::kReturnValueOffset;
|
||||
Operand return_value_operand(ebp, return_value_offset * kPointerSize);
|
||||
const int stack_space = argc() + FCA::kArgsLength + 1;
|
||||
Operand* stack_space_operand = nullptr;
|
||||
// There are two stack slots above the arguments we constructed on the stack:
|
||||
// the stored ebp (pushed by EnterApiExitFrame), and the return address.
|
||||
static constexpr int kStackSlotsAboveFCA = 2;
|
||||
Operand return_value_operand(
|
||||
ebp, (kStackSlotsAboveFCA + FCA::kReturnValueOffset) * kPointerSize);
|
||||
|
||||
static constexpr int kUseStackSpaceOperand = 0;
|
||||
Operand stack_space_operand = ApiParameterOperand(kApiArgc + 3);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
ApiParameterOperand(1), stack_space,
|
||||
stack_space_operand, return_value_operand);
|
||||
ApiParameterOperand(1), kUseStackSpaceOperand,
|
||||
&stack_space_operand, return_value_operand);
|
||||
}
|
||||
|
||||
|
||||
@ -449,8 +495,10 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
Operand return_value_operand(
|
||||
ebp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
Operand* const kUseStackSpaceConstant = nullptr;
|
||||
CallApiFunctionAndReturn(masm, function_address, thunk_ref, thunk_last_arg,
|
||||
kStackUnwindSpace, nullptr, return_value_operand);
|
||||
kStackUnwindSpace, kUseStackSpaceConstant,
|
||||
return_value_operand);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
@ -205,10 +205,9 @@ void ArgumentsAdaptorDescriptor::InitializePlatformSpecific(
|
||||
void ApiCallbackDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {
|
||||
JavaScriptFrame::context_register(), // callee context
|
||||
eax, // call_data
|
||||
ecx, // holder
|
||||
edx, // api_function_address
|
||||
JavaScriptFrame::context_register(), // kTargetContext
|
||||
edx, // kApiFunctionAddress
|
||||
ecx, // kArgc
|
||||
};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
@ -273,8 +273,9 @@ void AccessorAssembler::HandleLoadAccessor(
|
||||
|
||||
BIND(&load);
|
||||
Callable callable = CodeFactory::CallApiCallback(isolate(), 0);
|
||||
exit_point->Return(CallStub(callable, nullptr, context, data,
|
||||
api_holder.value(), callback, p->receiver));
|
||||
TNode<IntPtrT> argc = IntPtrConstant(0);
|
||||
exit_point->Return(CallStub(callable, nullptr, context, callback, argc,
|
||||
data, api_holder.value(), p->receiver));
|
||||
}
|
||||
|
||||
BIND(&runtime);
|
||||
@ -1415,8 +1416,9 @@ void AccessorAssembler::HandleStoreICProtoHandler(
|
||||
|
||||
BIND(&store);
|
||||
Callable callable = CodeFactory::CallApiCallback(isolate(), 1);
|
||||
Return(CallStub(callable, nullptr, context, data, api_holder.value(),
|
||||
callback, p->receiver, p->value));
|
||||
TNode<IntPtrT> argc = IntPtrConstant(1);
|
||||
Return(CallStub(callable, nullptr, context, callback, argc, data,
|
||||
api_holder.value(), p->receiver, p->value));
|
||||
}
|
||||
|
||||
BIND(&if_store_global_proxy);
|
||||
|
@ -949,15 +949,18 @@ class CEntry1ArgvOnStackDescriptor : public CallInterfaceDescriptor {
|
||||
|
||||
class ApiCallbackDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
// TODO(jgruber): This could be simplified to pass call data on the stack
|
||||
// since this is what the CallApiCallbackStub anyways. This would free a
|
||||
// register.
|
||||
DEFINE_PARAMETERS_NO_CONTEXT(kTargetContext, kCallData, kHolder,
|
||||
kApiFunctionAddress)
|
||||
DEFINE_PARAMETERS_NO_CONTEXT(kTargetContext, // register argument
|
||||
kApiFunctionAddress, // register argument
|
||||
kArgc, // register argument
|
||||
kCallData, // stack argument 1
|
||||
kHolder) // stack argument 2
|
||||
// receiver is implicit stack argument 3
|
||||
// argv are implicit stack arguments [4, 4 + kArgc[
|
||||
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kTargetContext
|
||||
MachineType::Pointer(), // kApiFunctionAddress
|
||||
MachineType::IntPtr(), // kArgc
|
||||
MachineType::AnyTagged(), // kCallData
|
||||
MachineType::AnyTagged(), // kHolder
|
||||
MachineType::Pointer()) // kApiFunctionAddress
|
||||
MachineType::AnyTagged()) // kHolder
|
||||
DECLARE_DESCRIPTOR(ApiCallbackDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
|
@ -237,7 +237,7 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
Register function_address,
|
||||
ExternalReference thunk_ref,
|
||||
int stack_space,
|
||||
int32_t stack_space_offset,
|
||||
MemOperand* stack_space_operand,
|
||||
MemOperand return_value_operand) {
|
||||
Isolate* isolate = masm->isolate();
|
||||
ExternalReference next_address =
|
||||
@ -321,15 +321,22 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
// Leave the API exit frame.
|
||||
__ bind(&leave_exit_frame);
|
||||
|
||||
if (stack_space_offset != kInvalidStackOffset) {
|
||||
// ExitFrame contains four MIPS argument slots after DirectCEntryStub call
|
||||
// so this must be accounted for.
|
||||
__ lw(s0, MemOperand(sp, stack_space_offset + kCArgsSlotsSize));
|
||||
} else {
|
||||
if (stack_space_operand == nullptr) {
|
||||
CHECK_NE(stack_space, 0);
|
||||
__ li(s0, Operand(stack_space));
|
||||
} else {
|
||||
CHECK_EQ(stack_space, 0);
|
||||
// The ExitFrame contains four MIPS argument slots after the
|
||||
// DirectCEntryStub call so this must be accounted for.
|
||||
// TODO(jgruber): Remove once the DirectCEntryStub is gone.
|
||||
__ Drop(kCArgSlotCount);
|
||||
__ lw(s0, *stack_space_operand);
|
||||
}
|
||||
__ LeaveExitFrame(false, s0, NO_EMIT_RETURN,
|
||||
stack_space_offset != kInvalidStackOffset);
|
||||
|
||||
static constexpr bool kDontSaveDoubles = false;
|
||||
static constexpr bool kRegisterContainsSlotCount = false;
|
||||
__ LeaveExitFrame(kDontSaveDoubles, s0, NO_EMIT_RETURN,
|
||||
kRegisterContainsSlotCount);
|
||||
|
||||
// Check if the function scheduled an exception.
|
||||
__ LoadRoot(t0, RootIndex::kTheHoleValue);
|
||||
@ -357,20 +364,32 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
|
||||
void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- t0 : call_data
|
||||
// -- a2 : holder
|
||||
// -- a1 : api_function_address
|
||||
// -- cp : context
|
||||
// -- cp : kTargetContext
|
||||
// -- a1 : kApiFunctionAddress
|
||||
// -- a2 : kArgc
|
||||
// --
|
||||
// -- sp[0] : last argument
|
||||
// -- ...
|
||||
// -- sp[(argc - 1)* 4] : first argument
|
||||
// -- sp[argc * 4] : receiver
|
||||
// -- sp[(argc - 1) * 4] : first argument
|
||||
// -- sp[(argc + 0) * 4] : receiver
|
||||
// -- sp[(argc + 1) * 4] : kHolder
|
||||
// -- sp[(argc + 2) * 4] : kCallData
|
||||
// -----------------------------------
|
||||
|
||||
Register call_data = t0;
|
||||
Register holder = a2;
|
||||
Register api_function_address = a1;
|
||||
Register argc = a2;
|
||||
Register scratch = t0;
|
||||
Register base = t1; // For addressing MemOperands on the stack.
|
||||
|
||||
DCHECK(!AreAliased(api_function_address, argc, scratch, base));
|
||||
|
||||
// Stack offsets (without argc).
|
||||
static constexpr int kReceiverOffset = 0 * kPointerSize;
|
||||
static constexpr int kHolderOffset = kReceiverOffset + kPointerSize;
|
||||
static constexpr int kCallDataOffset = kHolderOffset + kPointerSize;
|
||||
|
||||
// Extra stack arguments are: the receiver, kHolder, kCallData.
|
||||
static constexpr int kExtraStackArgumentCount = 3;
|
||||
|
||||
typedef FunctionCallbackArguments FCA;
|
||||
|
||||
@ -382,55 +401,90 @@ void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
STATIC_ASSERT(FCA::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(FCA::kHolderIndex == 0);
|
||||
|
||||
// new target
|
||||
__ PushRoot(RootIndex::kUndefinedValue);
|
||||
// Set up FunctionCallbackInfo's implicit_args on the stack as follows:
|
||||
//
|
||||
// Target state:
|
||||
// sp[0 * kPointerSize]: kHolder
|
||||
// sp[1 * kPointerSize]: kIsolate
|
||||
// sp[2 * kPointerSize]: undefined (kReturnValueDefaultValue)
|
||||
// sp[3 * kPointerSize]: undefined (kReturnValue)
|
||||
// sp[4 * kPointerSize]: kData
|
||||
// sp[5 * kPointerSize]: undefined (kNewTarget)
|
||||
|
||||
// call data.
|
||||
__ Push(call_data);
|
||||
// Set up the base register for addressing through MemOperands. It will point
|
||||
// at the receiver (located at sp + argc * kPointerSize).
|
||||
__ Lsa(base, sp, argc, kPointerSizeLog2);
|
||||
|
||||
Register scratch = call_data;
|
||||
__ LoadRoot(scratch, RootIndex::kUndefinedValue);
|
||||
// Push return value and default return value.
|
||||
__ Push(scratch, scratch);
|
||||
// Reserve space on the stack.
|
||||
__ Subu(sp, sp, Operand(FCA::kArgsLength * kPointerSize));
|
||||
|
||||
// kHolder.
|
||||
__ lw(scratch, MemOperand(base, kHolderOffset));
|
||||
__ sw(scratch, MemOperand(sp, 0 * kPointerSize));
|
||||
|
||||
// kIsolate.
|
||||
__ li(scratch, ExternalReference::isolate_address(masm->isolate()));
|
||||
// Push isolate and holder.
|
||||
__ Push(scratch, holder);
|
||||
__ sw(scratch, MemOperand(sp, 1 * kPointerSize));
|
||||
|
||||
// Prepare arguments.
|
||||
// kReturnValueDefaultValue, kReturnValue, and kNewTarget.
|
||||
__ LoadRoot(scratch, RootIndex::kUndefinedValue);
|
||||
__ sw(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||
__ sw(scratch, MemOperand(sp, 3 * kPointerSize));
|
||||
__ sw(scratch, MemOperand(sp, 5 * kPointerSize));
|
||||
|
||||
// kData.
|
||||
__ lw(scratch, MemOperand(base, kCallDataOffset));
|
||||
__ sw(scratch, MemOperand(sp, 4 * kPointerSize));
|
||||
|
||||
// Keep a pointer to kHolder (= implicit_args) in a scratch register.
|
||||
// We use it below to set up the FunctionCallbackInfo object.
|
||||
__ mov(scratch, sp);
|
||||
|
||||
// Allocate the v8::Arguments structure in the arguments' space since
|
||||
// it's not controlled by GC.
|
||||
const int kApiStackSpace = 3;
|
||||
|
||||
static constexpr int kApiStackSpace = 4;
|
||||
static constexpr bool kDontSaveDoubles = false;
|
||||
FrameScope frame_scope(masm, StackFrame::MANUAL);
|
||||
__ EnterExitFrame(false, kApiStackSpace);
|
||||
__ EnterExitFrame(kDontSaveDoubles, kApiStackSpace);
|
||||
|
||||
DCHECK(api_function_address != a0 && scratch != a0);
|
||||
// a0 = FunctionCallbackInfo&
|
||||
// Arguments is after the return address.
|
||||
// FunctionCallbackInfo::implicit_args_ (points at kHolder as set up above).
|
||||
// Arguments are after the return address (pushed by EnterExitFrame()).
|
||||
__ sw(scratch, MemOperand(sp, 1 * kPointerSize));
|
||||
|
||||
// FunctionCallbackInfo::values_ (points at the first varargs argument passed
|
||||
// on the stack).
|
||||
__ Subu(scratch, base, Operand(1 * kPointerSize));
|
||||
__ sw(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||
|
||||
// FunctionCallbackInfo::length_.
|
||||
__ sw(argc, MemOperand(sp, 3 * kPointerSize));
|
||||
|
||||
// We also store the number of bytes to drop from the stack after returning
|
||||
// from the API function here.
|
||||
// Note: Unlike on other architectures, this stores the number of slots to
|
||||
// drop, not the number of bytes.
|
||||
__ Addu(scratch, argc, Operand(FCA::kArgsLength + kExtraStackArgumentCount));
|
||||
__ sw(scratch, MemOperand(sp, 4 * kPointerSize));
|
||||
|
||||
// v8::InvocationCallback's argument.
|
||||
DCHECK(!AreAliased(api_function_address, scratch, a0));
|
||||
__ Addu(a0, sp, Operand(1 * kPointerSize));
|
||||
// FunctionCallbackInfo::implicit_args_
|
||||
__ sw(scratch, MemOperand(a0, 0 * kPointerSize));
|
||||
// FunctionCallbackInfo::values_
|
||||
__ Addu(kScratchReg, scratch,
|
||||
Operand((FCA::kArgsLength - 1 + argc()) * kPointerSize));
|
||||
__ sw(kScratchReg, MemOperand(a0, 1 * kPointerSize));
|
||||
// FunctionCallbackInfo::length_ = argc
|
||||
__ li(kScratchReg, Operand(argc()));
|
||||
__ sw(kScratchReg, MemOperand(a0, 2 * kPointerSize));
|
||||
|
||||
ExternalReference thunk_ref = ExternalReference::invoke_function_callback();
|
||||
|
||||
// There are two stack slots above the arguments we constructed on the stack.
|
||||
// TODO(jgruber): Document what these arguments are.
|
||||
static constexpr int kStackSlotsAboveFCA = 2;
|
||||
MemOperand return_value_operand(
|
||||
fp, (kStackSlotsAboveFCA + FCA::kReturnValueOffset) * kPointerSize);
|
||||
|
||||
static constexpr int kUseStackSpaceOperand = 0;
|
||||
MemOperand stack_space_operand(sp, 4 * kPointerSize);
|
||||
|
||||
AllowExternalCallThatCantCauseGC scope(masm);
|
||||
// Stores return the first js argument.
|
||||
int return_value_offset = 2 + FCA::kReturnValueOffset;
|
||||
MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
|
||||
const int stack_space = argc() + FCA::kArgsLength + 1;
|
||||
// TODO(adamk): Why are we clobbering this immediately?
|
||||
const int32_t stack_space_offset = kInvalidStackOffset;
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, stack_space,
|
||||
stack_space_offset, return_value_operand);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kUseStackSpaceOperand, &stack_space_operand,
|
||||
return_value_operand);
|
||||
}
|
||||
|
||||
|
||||
@ -500,8 +554,9 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
MemOperand return_value_operand(
|
||||
fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
MemOperand* const kUseStackSpaceConstant = nullptr;
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kStackUnwindSpace, kInvalidStackOffset,
|
||||
kStackUnwindSpace, kUseStackSpaceConstant,
|
||||
return_value_operand);
|
||||
}
|
||||
|
||||
|
@ -1684,9 +1684,10 @@ class Instruction : public InstructionGetters<InstructionBase> {
|
||||
// C/C++ argument slots size.
|
||||
const int kCArgSlotCount = 4;
|
||||
const int kCArgsSlotsSize = kCArgSlotCount * kInstrSize;
|
||||
const int kInvalidStackOffset = -1;
|
||||
|
||||
// JS argument slots size.
|
||||
const int kJSArgsSlotsSize = 0 * kInstrSize;
|
||||
|
||||
// Assembly builtins argument slots size.
|
||||
const int kBArgsSlotsSize = 0 * kInstrSize;
|
||||
|
||||
|
@ -203,10 +203,9 @@ void ArgumentsAdaptorDescriptor::InitializePlatformSpecific(
|
||||
void ApiCallbackDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {
|
||||
JavaScriptFrame::context_register(), // callee context
|
||||
t0, // call_data
|
||||
a2, // holder
|
||||
a1, // api_function_address
|
||||
JavaScriptFrame::context_register(), // kTargetContext
|
||||
a1, // kApiFunctionAddress
|
||||
a2, // kArgc
|
||||
};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
Register function_address,
|
||||
ExternalReference thunk_ref,
|
||||
int stack_space,
|
||||
int32_t stack_space_offset,
|
||||
MemOperand* stack_space_operand,
|
||||
MemOperand return_value_operand) {
|
||||
Isolate* isolate = masm->isolate();
|
||||
ExternalReference next_address =
|
||||
@ -324,14 +324,19 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
// Leave the API exit frame.
|
||||
__ bind(&leave_exit_frame);
|
||||
|
||||
if (stack_space_offset != kInvalidStackOffset) {
|
||||
DCHECK_EQ(kCArgsSlotsSize, 0);
|
||||
__ Ld(s0, MemOperand(sp, stack_space_offset));
|
||||
} else {
|
||||
if (stack_space_operand == nullptr) {
|
||||
CHECK_NE(stack_space, 0);
|
||||
__ li(s0, Operand(stack_space));
|
||||
} else {
|
||||
CHECK_EQ(stack_space, 0);
|
||||
STATIC_ASSERT(kCArgSlotCount == 0);
|
||||
__ Ld(s0, *stack_space_operand);
|
||||
}
|
||||
__ LeaveExitFrame(false, s0, NO_EMIT_RETURN,
|
||||
stack_space_offset != kInvalidStackOffset);
|
||||
|
||||
static constexpr bool kDontSaveDoubles = false;
|
||||
static constexpr bool kRegisterContainsSlotCount = false;
|
||||
__ LeaveExitFrame(kDontSaveDoubles, s0, NO_EMIT_RETURN,
|
||||
kRegisterContainsSlotCount);
|
||||
|
||||
// Check if the function scheduled an exception.
|
||||
__ LoadRoot(a4, RootIndex::kTheHoleValue);
|
||||
@ -359,20 +364,32 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
|
||||
void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a4 : call_data
|
||||
// -- a2 : holder
|
||||
// -- a1 : api_function_address
|
||||
// -- cp : context
|
||||
// -- cp : kTargetContext
|
||||
// -- a1 : kApiFunctionAddress
|
||||
// -- a2 : kArgc
|
||||
// --
|
||||
// -- sp[0] : last argument
|
||||
// -- ...
|
||||
// -- sp[(argc - 1) * 8] : first argument
|
||||
// -- sp[argc * 8] : receiver
|
||||
// -- sp[(argc + 0) * 8] : receiver
|
||||
// -- sp[(argc + 1) * 8] : kHolder
|
||||
// -- sp[(argc + 2) * 8] : kCallData
|
||||
// -----------------------------------
|
||||
|
||||
Register call_data = a4;
|
||||
Register holder = a2;
|
||||
Register api_function_address = a1;
|
||||
Register argc = a2;
|
||||
Register scratch = t0;
|
||||
Register base = t1; // For addressing MemOperands on the stack.
|
||||
|
||||
DCHECK(!AreAliased(api_function_address, argc, scratch, base));
|
||||
|
||||
// Stack offsets (without argc).
|
||||
static constexpr int kReceiverOffset = 0 * kPointerSize;
|
||||
static constexpr int kHolderOffset = kReceiverOffset + kPointerSize;
|
||||
static constexpr int kCallDataOffset = kHolderOffset + kPointerSize;
|
||||
|
||||
// Extra stack arguments are: the receiver, kHolder, kCallData.
|
||||
static constexpr int kExtraStackArgumentCount = 3;
|
||||
|
||||
typedef FunctionCallbackArguments FCA;
|
||||
|
||||
@ -384,57 +401,94 @@ void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
STATIC_ASSERT(FCA::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(FCA::kHolderIndex == 0);
|
||||
|
||||
// new target
|
||||
__ PushRoot(RootIndex::kUndefinedValue);
|
||||
// Set up FunctionCallbackInfo's implicit_args on the stack as follows:
|
||||
//
|
||||
// Target state:
|
||||
// sp[0 * kPointerSize]: kHolder
|
||||
// sp[1 * kPointerSize]: kIsolate
|
||||
// sp[2 * kPointerSize]: undefined (kReturnValueDefaultValue)
|
||||
// sp[3 * kPointerSize]: undefined (kReturnValue)
|
||||
// sp[4 * kPointerSize]: kData
|
||||
// sp[5 * kPointerSize]: undefined (kNewTarget)
|
||||
|
||||
// call data.
|
||||
__ Push(call_data);
|
||||
// Set up the base register for addressing through MemOperands. It will point
|
||||
// at the receiver (located at sp + argc * kPointerSize).
|
||||
__ Dlsa(base, sp, argc, kPointerSizeLog2);
|
||||
|
||||
Register scratch = call_data;
|
||||
__ LoadRoot(scratch, RootIndex::kUndefinedValue);
|
||||
// Push return value and default return value.
|
||||
__ Push(scratch, scratch);
|
||||
// Reserve space on the stack.
|
||||
__ Dsubu(sp, sp, Operand(FCA::kArgsLength * kPointerSize));
|
||||
|
||||
// kHolder.
|
||||
__ Ld(scratch, MemOperand(base, kHolderOffset));
|
||||
__ Sd(scratch, MemOperand(sp, 0 * kPointerSize));
|
||||
|
||||
// kIsolate.
|
||||
__ li(scratch, ExternalReference::isolate_address(masm->isolate()));
|
||||
// Push isolate and holder.
|
||||
__ Push(scratch, holder);
|
||||
__ Sd(scratch, MemOperand(sp, 1 * kPointerSize));
|
||||
|
||||
// Prepare arguments.
|
||||
// kReturnValueDefaultValue, kReturnValue, and kNewTarget.
|
||||
__ LoadRoot(scratch, RootIndex::kUndefinedValue);
|
||||
__ Sd(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||
__ Sd(scratch, MemOperand(sp, 3 * kPointerSize));
|
||||
__ Sd(scratch, MemOperand(sp, 5 * kPointerSize));
|
||||
|
||||
// kData.
|
||||
__ Ld(scratch, MemOperand(base, kCallDataOffset));
|
||||
__ Sd(scratch, MemOperand(sp, 4 * kPointerSize));
|
||||
|
||||
// Keep a pointer to kHolder (= implicit_args) in a scratch register.
|
||||
// We use it below to set up the FunctionCallbackInfo object.
|
||||
__ mov(scratch, sp);
|
||||
|
||||
// Allocate the v8::Arguments structure in the arguments' space since
|
||||
// it's not controlled by GC.
|
||||
const int kApiStackSpace = 3;
|
||||
|
||||
static constexpr int kApiStackSpace = 4;
|
||||
static constexpr bool kDontSaveDoubles = false;
|
||||
FrameScope frame_scope(masm, StackFrame::MANUAL);
|
||||
__ EnterExitFrame(false, kApiStackSpace);
|
||||
__ EnterExitFrame(kDontSaveDoubles, kApiStackSpace);
|
||||
|
||||
DCHECK(api_function_address != a0 && scratch != a0);
|
||||
// a0 = FunctionCallbackInfo&
|
||||
// Arguments is after the return address.
|
||||
__ Daddu(a0, sp, Operand(1 * kPointerSize));
|
||||
// FunctionCallbackInfo::implicit_args_
|
||||
__ Sd(scratch, MemOperand(a0, 0 * kPointerSize));
|
||||
// FunctionCallbackInfo::values_
|
||||
__ Daddu(kScratchReg, scratch,
|
||||
Operand((FCA::kArgsLength - 1 + argc()) * kPointerSize));
|
||||
__ Sd(kScratchReg, MemOperand(a0, 1 * kPointerSize));
|
||||
// FunctionCallbackInfo::length_ = argc
|
||||
// EnterExitFrame may align the sp.
|
||||
|
||||
// FunctionCallbackInfo::implicit_args_ (points at kHolder as set up above).
|
||||
// Arguments are after the return address (pushed by EnterExitFrame()).
|
||||
__ Sd(scratch, MemOperand(sp, 1 * kPointerSize));
|
||||
|
||||
// FunctionCallbackInfo::values_ (points at the first varargs argument passed
|
||||
// on the stack).
|
||||
__ Dsubu(scratch, base, Operand(1 * kPointerSize));
|
||||
__ Sd(scratch, MemOperand(sp, 2 * kPointerSize));
|
||||
|
||||
// FunctionCallbackInfo::length_.
|
||||
// Stored as int field, 32-bit integers within struct on stack always left
|
||||
// justified by n64 ABI.
|
||||
__ li(kScratchReg, Operand(argc()));
|
||||
__ Sw(kScratchReg, MemOperand(a0, 2 * kPointerSize));
|
||||
__ Sw(argc, MemOperand(sp, 3 * kPointerSize));
|
||||
|
||||
// We also store the number of bytes to drop from the stack after returning
|
||||
// from the API function here.
|
||||
// Note: Unlike on other architectures, this stores the number of slots to
|
||||
// drop, not the number of bytes.
|
||||
__ Daddu(scratch, argc, Operand(FCA::kArgsLength + kExtraStackArgumentCount));
|
||||
__ Sd(scratch, MemOperand(sp, 4 * kPointerSize));
|
||||
|
||||
// v8::InvocationCallback's argument.
|
||||
DCHECK(!AreAliased(api_function_address, scratch, a0));
|
||||
__ Daddu(a0, sp, Operand(1 * kPointerSize));
|
||||
|
||||
ExternalReference thunk_ref = ExternalReference::invoke_function_callback();
|
||||
|
||||
// There are two stack slots above the arguments we constructed on the stack.
|
||||
// TODO(jgruber): Document what these arguments are.
|
||||
static constexpr int kStackSlotsAboveFCA = 2;
|
||||
MemOperand return_value_operand(
|
||||
fp, (kStackSlotsAboveFCA + FCA::kReturnValueOffset) * kPointerSize);
|
||||
|
||||
static constexpr int kUseStackSpaceOperand = 0;
|
||||
MemOperand stack_space_operand(sp, 4 * kPointerSize);
|
||||
|
||||
AllowExternalCallThatCantCauseGC scope(masm);
|
||||
// Stores return the first js argument.
|
||||
int return_value_offset = 2 + FCA::kReturnValueOffset;
|
||||
MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
|
||||
const int stack_space = argc() + FCA::kArgsLength + 1;
|
||||
// TODO(adamk): Why are we clobbering this immediately?
|
||||
const int32_t stack_space_offset = kInvalidStackOffset;
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, stack_space,
|
||||
stack_space_offset, return_value_operand);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kUseStackSpaceOperand, &stack_space_operand,
|
||||
return_value_operand);
|
||||
}
|
||||
|
||||
|
||||
@ -505,8 +559,9 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
MemOperand return_value_operand(
|
||||
fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
MemOperand* const kUseStackSpaceConstant = nullptr;
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kStackUnwindSpace, kInvalidStackOffset,
|
||||
kStackUnwindSpace, kUseStackSpaceConstant,
|
||||
return_value_operand);
|
||||
}
|
||||
|
||||
|
@ -203,10 +203,9 @@ void ArgumentsAdaptorDescriptor::InitializePlatformSpecific(
|
||||
void ApiCallbackDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {
|
||||
JavaScriptFrame::context_register(), // callee context
|
||||
a4, // call_data
|
||||
a2, // holder
|
||||
a1, // api_function_address
|
||||
JavaScriptFrame::context_register(), // kTargetContext
|
||||
a1, // kApiFunctionAddress
|
||||
a2, // kArgc
|
||||
};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
@ -177,16 +177,6 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) {
|
||||
return static_cast<int>(offset);
|
||||
}
|
||||
|
||||
// Prepares stack to put arguments (aligns and so on). WIN64 calling convention
|
||||
// requires to put the pointer to the return value slot into rcx (rcx must be
|
||||
// preserverd until CallApiFunctionAndReturn). Clobbers rax. Allocates
|
||||
// arg_stack_space * kPointerSize inside the exit frame (not GCed) accessible
|
||||
// via StackSpaceOperand.
|
||||
static void PrepareCallApiFunction(MacroAssembler* masm, int arg_stack_space) {
|
||||
__ EnterApiExitFrame(arg_stack_space);
|
||||
}
|
||||
|
||||
|
||||
// Calls an API function. Allocates HandleScope, extracts returned value
|
||||
// from handle and propagates exceptions. Clobbers r14, r15, rbx and
|
||||
// caller-save registers. Restores context. On return removes
|
||||
@ -345,24 +335,40 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
|
||||
__ jmp(&leave_exit_frame);
|
||||
}
|
||||
|
||||
// TODO(jgruber): Instead of explicitly setting up implicit_args_ on the stack
|
||||
// in CallApiCallback, we could use the calling convention to set up the stack
|
||||
// correctly in the first place.
|
||||
//
|
||||
// TODO(jgruber): I suspect that most of CallApiCallback could be implemented
|
||||
// as a C++ trampoline, vastly simplifying the assembly implementation.
|
||||
|
||||
void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rbx : call_data
|
||||
// -- rcx : holder
|
||||
// -- rdx : api_function_address
|
||||
// -- rsi : context
|
||||
// -- rax : number of arguments if argc is a register
|
||||
// -- rsi : kTargetContext
|
||||
// -- rdx : kApiFunctionAddress
|
||||
// -- rcx : kArgc
|
||||
// --
|
||||
// -- rsp[0] : return address
|
||||
// -- rsp[8] : last argument
|
||||
// -- ...
|
||||
// -- rsp[argc * 8] : first argument
|
||||
// -- rsp[(argc + 1) * 8] : receiver
|
||||
// -- rsp[(argc + 2) * 8] : kHolder
|
||||
// -- rsp[(argc + 3) * 8] : kCallData
|
||||
// -----------------------------------
|
||||
|
||||
Register call_data = rbx;
|
||||
Register holder = rcx;
|
||||
Register api_function_address = rdx;
|
||||
Register return_address = r8;
|
||||
Register argc = rcx;
|
||||
|
||||
DCHECK(!AreAliased(api_function_address, argc, kScratchRegister));
|
||||
|
||||
// Stack offsets (without argc).
|
||||
static constexpr int kReceiverOffset = kPointerSize;
|
||||
static constexpr int kHolderOffset = kReceiverOffset + kPointerSize;
|
||||
static constexpr int kCallDataOffset = kHolderOffset + kPointerSize;
|
||||
|
||||
// Extra stack arguments are: the receiver, kHolder, kCallData.
|
||||
static constexpr int kExtraStackArgumentCount = 3;
|
||||
|
||||
typedef FunctionCallbackArguments FCA;
|
||||
|
||||
@ -374,52 +380,82 @@ void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
STATIC_ASSERT(FCA::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(FCA::kHolderIndex == 0);
|
||||
|
||||
__ PopReturnAddressTo(return_address);
|
||||
// Set up FunctionCallbackInfo's implicit_args on the stack as follows:
|
||||
//
|
||||
// Current state:
|
||||
// rsp[0]: return address
|
||||
//
|
||||
// Target state:
|
||||
// rsp[0 * kPointerSize]: return address
|
||||
// rsp[1 * kPointerSize]: kHolder
|
||||
// rsp[2 * kPointerSize]: kIsolate
|
||||
// rsp[3 * kPointerSize]: undefined (kReturnValueDefaultValue)
|
||||
// rsp[4 * kPointerSize]: undefined (kReturnValue)
|
||||
// rsp[5 * kPointerSize]: kData
|
||||
// rsp[6 * kPointerSize]: undefined (kNewTarget)
|
||||
|
||||
// new target
|
||||
__ PushRoot(RootIndex::kUndefinedValue);
|
||||
// Reserve space on the stack.
|
||||
__ subp(rsp, Immediate(FCA::kArgsLength * kPointerSize));
|
||||
|
||||
// call data
|
||||
__ Push(call_data);
|
||||
// Return address (the old stack location is overwritten later on).
|
||||
__ movp(kScratchRegister, Operand(rsp, FCA::kArgsLength * kPointerSize));
|
||||
__ movp(Operand(rsp, 0 * kPointerSize), kScratchRegister);
|
||||
|
||||
// return value
|
||||
__ PushRoot(RootIndex::kUndefinedValue);
|
||||
// return value default
|
||||
__ PushRoot(RootIndex::kUndefinedValue);
|
||||
// isolate
|
||||
Register scratch = call_data;
|
||||
__ Move(scratch, ExternalReference::isolate_address(masm->isolate()));
|
||||
__ Push(scratch);
|
||||
// holder
|
||||
__ Push(holder);
|
||||
// kHolder.
|
||||
__ movp(kScratchRegister,
|
||||
Operand(rsp, argc, times_pointer_size,
|
||||
FCA::kArgsLength * kPointerSize + kHolderOffset));
|
||||
__ movp(Operand(rsp, 1 * kPointerSize), kScratchRegister);
|
||||
|
||||
int argc = this->argc();
|
||||
// kIsolate.
|
||||
__ Move(kScratchRegister,
|
||||
ExternalReference::isolate_address(masm->isolate()));
|
||||
__ movp(Operand(rsp, 2 * kPointerSize), kScratchRegister);
|
||||
|
||||
__ movp(scratch, rsp);
|
||||
// Push return address back on stack.
|
||||
__ PushReturnAddressFrom(return_address);
|
||||
// kReturnValueDefaultValue, kReturnValue, and kNewTarget.
|
||||
__ LoadRoot(kScratchRegister, RootIndex::kUndefinedValue);
|
||||
__ movp(Operand(rsp, 3 * kPointerSize), kScratchRegister);
|
||||
__ movp(Operand(rsp, 4 * kPointerSize), kScratchRegister);
|
||||
__ movp(Operand(rsp, 6 * kPointerSize), kScratchRegister);
|
||||
|
||||
// kData.
|
||||
__ movp(kScratchRegister,
|
||||
Operand(rsp, argc, times_pointer_size,
|
||||
FCA::kArgsLength * kPointerSize + kCallDataOffset));
|
||||
__ movp(Operand(rsp, 5 * kPointerSize), kScratchRegister);
|
||||
|
||||
// Keep a pointer to kHolder (= implicit_args) in a scratch register.
|
||||
// We use it below to set up the FunctionCallbackInfo object.
|
||||
Register scratch = rbx;
|
||||
__ leap(scratch, Operand(rsp, 1 * kPointerSize));
|
||||
|
||||
// Allocate the v8::Arguments structure in the arguments' space since
|
||||
// it's not controlled by GC.
|
||||
const int kApiStackSpace = 3;
|
||||
static constexpr int kApiStackSpace = 4;
|
||||
__ EnterApiExitFrame(kApiStackSpace);
|
||||
|
||||
PrepareCallApiFunction(masm, kApiStackSpace);
|
||||
|
||||
// FunctionCallbackInfo::implicit_args_.
|
||||
// FunctionCallbackInfo::implicit_args_ (points at kHolder as set up above).
|
||||
__ movp(StackSpaceOperand(0), scratch);
|
||||
__ addp(scratch, Immediate((argc + FCA::kArgsLength - 1) * kPointerSize));
|
||||
// FunctionCallbackInfo::values_.
|
||||
__ movp(StackSpaceOperand(1), scratch);
|
||||
// FunctionCallbackInfo::length_.
|
||||
__ Set(StackSpaceOperand(2), argc);
|
||||
|
||||
#if defined(__MINGW64__) || defined(_WIN64)
|
||||
Register arguments_arg = rcx;
|
||||
Register callback_arg = rdx;
|
||||
#else
|
||||
Register arguments_arg = rdi;
|
||||
Register callback_arg = rsi;
|
||||
#endif
|
||||
// FunctionCallbackInfo::values_ (points at the first varargs argument passed
|
||||
// on the stack).
|
||||
__ leap(scratch, Operand(scratch, argc, times_pointer_size,
|
||||
(FCA::kArgsLength - 1) * kPointerSize));
|
||||
__ movp(StackSpaceOperand(1), scratch);
|
||||
|
||||
// FunctionCallbackInfo::length_.
|
||||
__ movp(StackSpaceOperand(2), argc);
|
||||
|
||||
// We also store the number of bytes to drop from the stack after returning
|
||||
// from the API function here.
|
||||
__ leaq(
|
||||
kScratchRegister,
|
||||
Operand(argc, times_pointer_size,
|
||||
(FCA::kArgsLength + kExtraStackArgumentCount) * kPointerSize));
|
||||
__ movp(StackSpaceOperand(3), kScratchRegister);
|
||||
|
||||
Register arguments_arg = arg_reg_1;
|
||||
Register callback_arg = arg_reg_2;
|
||||
|
||||
// It's okay if api_function_address == callback_arg
|
||||
// but not arguments_arg
|
||||
@ -430,15 +466,16 @@ void CallApiCallbackStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
ExternalReference thunk_ref = ExternalReference::invoke_function_callback();
|
||||
|
||||
// Accessor for FunctionCallbackInfo and first js arg.
|
||||
StackArgumentsAccessor args_from_rbp(rbp, FCA::kArgsLength + 1,
|
||||
ARGUMENTS_DONT_CONTAIN_RECEIVER);
|
||||
Operand return_value_operand = args_from_rbp.GetArgumentOperand(
|
||||
FCA::kArgsLength - FCA::kReturnValueOffset);
|
||||
const int stack_space = argc + FCA::kArgsLength + 1;
|
||||
Operand* stack_space_operand = nullptr;
|
||||
// There are two stack slots above the arguments we constructed on the stack:
|
||||
// the stored ebp (pushed by EnterApiExitFrame), and the return address.
|
||||
static constexpr int kStackSlotsAboveFCA = 2;
|
||||
Operand return_value_operand(
|
||||
rbp, (kStackSlotsAboveFCA + FCA::kReturnValueOffset) * kPointerSize);
|
||||
|
||||
static constexpr int kUseStackSpaceOperand = 0;
|
||||
Operand stack_space_operand = StackSpaceOperand(3);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, callback_arg,
|
||||
stack_space, stack_space_operand,
|
||||
kUseStackSpaceOperand, &stack_space_operand,
|
||||
return_value_operand);
|
||||
}
|
||||
|
||||
@ -493,14 +530,15 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// Load address of v8::PropertyAccessorInfo::args_ array.
|
||||
__ leap(scratch, Operand(rsp, 2 * kPointerSize));
|
||||
|
||||
PrepareCallApiFunction(masm, kArgStackSpace);
|
||||
__ EnterApiExitFrame(kArgStackSpace);
|
||||
|
||||
// Create v8::PropertyCallbackInfo object on the stack and initialize
|
||||
// it's args_ field.
|
||||
Operand info_object = StackSpaceOperand(0);
|
||||
__ movp(info_object, scratch);
|
||||
|
||||
__ leap(name_arg, Operand(scratch, -kPointerSize));
|
||||
// The context register (rsi) has been saved in PrepareCallApiFunction and
|
||||
// The context register (rsi) has been saved in EnterApiExitFrame and
|
||||
// could be used to pass arguments.
|
||||
__ leap(accessor_info_arg, info_object);
|
||||
|
||||
@ -518,8 +556,10 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
Operand return_value_operand(
|
||||
rbp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
Operand* const kUseStackSpaceConstant = nullptr;
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, getter_arg,
|
||||
kStackUnwindSpace, nullptr, return_value_operand);
|
||||
kStackUnwindSpace, kUseStackSpaceConstant,
|
||||
return_value_operand);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
@ -204,10 +204,9 @@ void ArgumentsAdaptorDescriptor::InitializePlatformSpecific(
|
||||
void ApiCallbackDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {
|
||||
JavaScriptFrame::context_register(), // callee context
|
||||
rbx, // call_data
|
||||
rcx, // holder
|
||||
rdx, // api_function_address
|
||||
JavaScriptFrame::context_register(), // kTargetContext
|
||||
rdx, // kApiFunctionAddress
|
||||
rcx, // kArgc
|
||||
};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user