Commit c142e0a2 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[builtins] Improve CallApiCallback calling convention.

Refactor the CallApiCallback builtin to

- pass the context as with other stubs, and
- pass holder and call data in registers.

This avoids having to place holder and call data onto the stack, and
thus makes it possible to easily call the CallApiCallback builtin from
other builtins while just forwarding the (stack) arguments. The idea
is to use this in the future to optimize the general case of calling
into any API method via a FunctionTemplateInfo and doing appropriate
security and/or interface checks upfront as necessary (eventually making
the HandleApiCall C++ builtin obsolete at some point).

Bug: v8:8820, chromium:913553
Change-Id: I10c0065016df4d0c24bac3d46945ea597b65ed02
Cq-Include-Trybots: luci.chromium.try:linux-blink-rel
Reviewed-on: https://chromium-review.googlesource.com/c/1469821
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59551}
parent 1534781f
......@@ -203,9 +203,10 @@ void ArgumentsAdaptorDescriptor::InitializePlatformSpecific(
void ApiCallbackDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
JavaScriptFrame::context_register(), // kTargetContext
r1, // kApiFunctionAddress
r2, // kArgc
r1, // kApiFunctionAddress
r2, // kArgc
r3, // kCallData
r0, // kHolder
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
......
......@@ -207,9 +207,10 @@ void ArgumentsAdaptorDescriptor::InitializePlatformSpecific(
void ApiCallbackDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
JavaScriptFrame::context_register(), // kTargetContext
x1, // kApiFunctionAddress
x2, // kArgc
x1, // kApiFunctionAddress
x2, // kArgc
x3, // kCallData
x0, // kHolder
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
......
......@@ -2878,32 +2878,24 @@ void CallApiFunctionAndReturn(MacroAssembler* masm, Register function_address,
void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- cp : kTargetContext
// -- r1 : kApiFunctionAddress
// -- r2 : kArgc
// --
// -- cp : context
// -- r1 : api function address
// -- r2 : arguments count (not including the receiver)
// -- r3 : call data
// -- r0 : holder
// -- sp[0] : last argument
// -- ...
// -- sp[(argc - 1) * 4] : first argument
// -- sp[(argc + 0) * 4] : receiver
// -- sp[(argc + 1) * 4] : kHolder
// -- sp[(argc + 2) * 4] : kCallData
// -----------------------------------
Register api_function_address = r1;
Register argc = r2;
Register call_data = r3;
Register holder = r0;
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;
DCHECK(!AreAliased(api_function_address, argc, call_data, holder, scratch));
typedef FunctionCallbackArguments FCA;
......@@ -2929,24 +2921,22 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
__ sub(sp, sp, Operand(FCA::kArgsLength * kPointerSize));
// kHolder.
__ add(index, argc, Operand(FCA::kArgsLength + kHolderOffset));
__ ldr(scratch, MemOperand(sp, index, LSL, kPointerSizeLog2));
__ str(scratch, MemOperand(sp, 0 * kPointerSize));
__ str(holder, MemOperand(sp, 0 * kPointerSize));
// kIsolate.
__ Move(scratch, ExternalReference::isolate_address(masm->isolate()));
__ str(scratch, MemOperand(sp, 1 * kPointerSize));
// kReturnValueDefaultValue, kReturnValue, and kNewTarget.
// kReturnValueDefaultValue and kReturnValue.
__ 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));
__ str(call_data, MemOperand(sp, 4 * kPointerSize));
// kNewTarget.
__ str(scratch, MemOperand(sp, 5 * kPointerSize));
// Keep a pointer to kHolder (= implicit_args) in a scratch register.
// We use it below to set up the FunctionCallbackInfo object.
......@@ -2975,7 +2965,7 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
// 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));
Operand((FCA::kArgsLength + 1 /* receiver */) * kPointerSize));
__ add(scratch, scratch, Operand(argc, LSL, kPointerSizeLog2));
__ str(scratch, MemOperand(sp, 4 * kPointerSize));
......
......@@ -3474,32 +3474,24 @@ void CallApiFunctionAndReturn(MacroAssembler* masm, Register function_address,
void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- cp : kTargetContext
// -- r1 : kApiFunctionAddress
// -- r2 : kArgc
// --
// -- cp : context
// -- x1 : api function address
// -- x2 : arguments count (not including the receiver)
// -- x3 : call data
// -- x0 : holder
// -- sp[0] : last argument
// -- ...
// -- sp[(argc - 1) * 8] : first argument
// -- sp[(argc + 0) * 8] : receiver
// -- sp[(argc + 1) * 8] : kHolder
// -- sp[(argc + 2) * 8] : kCallData
// -----------------------------------
Register api_function_address = x1;
Register argc = x2;
Register call_data = x3;
Register holder = x0;
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;
DCHECK(!AreAliased(api_function_address, argc, call_data, holder, scratch));
typedef FunctionCallbackArguments FCA;
......@@ -3525,24 +3517,22 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
__ Sub(sp, sp, Operand(FCA::kArgsLength * kPointerSize));
// kHolder.
__ Add(index, argc, Operand(FCA::kArgsLength + kHolderOffset));
__ Ldr(scratch, MemOperand(sp, index, LSL, kPointerSizeLog2));
__ Str(scratch, MemOperand(sp, 0 * kPointerSize));
__ Str(holder, MemOperand(sp, 0 * kPointerSize));
// kIsolate.
__ Mov(scratch, ExternalReference::isolate_address(masm->isolate()));
__ Str(scratch, MemOperand(sp, 1 * kPointerSize));
// kReturnValueDefaultValue, kReturnValue, and kNewTarget.
// kReturnValueDefaultValue and kReturnValue.
__ 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));
__ Str(call_data, MemOperand(sp, 4 * kPointerSize));
// kNewTarget.
__ Str(scratch, MemOperand(sp, 5 * kPointerSize));
// Keep a pointer to kHolder (= implicit_args) in a scratch register.
// We use it below to set up the FunctionCallbackInfo object.
......@@ -3576,7 +3566,7 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
// 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));
__ Add(scratch, argc, Operand(FCA::kArgsLength + 1 /*receiver*/));
__ Str(scratch, MemOperand(sp, 4 * kPointerSize));
// v8::InvocationCallback's argument.
......
......@@ -3108,32 +3108,28 @@ void CallApiFunctionAndReturn(MacroAssembler* masm, Register function_address,
void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- esi : kTargetContext
// -- edx : kApiFunctionAddress
// -- ecx : kArgc
// --
// -- esi : context
// -- edx : api function address
// -- ecx : arguments count (not including the receiver)
// -- eax : call data
// -- edi : holder
// -- 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 api_function_address = edx;
Register argc = ecx;
XMMRegister call_data = xmm0;
Register holder = edi;
Register scratch = eax;
DCHECK(!AreAliased(api_function_address, argc, scratch));
// Park call_data in xmm0.
__ movd(call_data, eax);
// 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;
DCHECK(!AreAliased(api_function_address, argc, holder, scratch));
typedef FunctionCallbackArguments FCA;
......@@ -3167,25 +3163,23 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
__ mov(Operand(esp, 0 * kPointerSize), scratch);
// kHolder.
__ mov(scratch, Operand(esp, argc, times_pointer_size,
FCA::kArgsLength * kPointerSize + kHolderOffset));
__ mov(Operand(esp, 1 * kPointerSize), scratch);
__ mov(Operand(esp, 1 * kPointerSize), holder);
// kIsolate.
__ Move(scratch,
Immediate(ExternalReference::isolate_address(masm->isolate())));
__ mov(Operand(esp, 2 * kPointerSize), scratch);
// kReturnValueDefaultValue, kReturnValue, and kNewTarget.
// kReturnValueDefaultValue and kReturnValue.
__ LoadRoot(scratch, RootIndex::kUndefinedValue);
__ mov(Operand(esp, 3 * kPointerSize), scratch);
__ mov(Operand(esp, 4 * kPointerSize), scratch);
__ mov(Operand(esp, 6 * kPointerSize), scratch);
// kData.
__ mov(scratch, Operand(esp, argc, times_pointer_size,
FCA::kArgsLength * kPointerSize + kCallDataOffset));
__ mov(Operand(esp, 5 * kPointerSize), scratch);
__ movd(Operand(esp, 5 * kPointerSize), call_data);
// kNewTarget.
__ mov(Operand(esp, 6 * kPointerSize), scratch);
// Keep a pointer to kHolder (= implicit_args) in a scratch register.
// We use it below to set up the FunctionCallbackInfo object.
......@@ -3219,7 +3213,7 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
// from the API function here.
__ lea(scratch,
Operand(argc, times_pointer_size,
(FCA::kArgsLength + kExtraStackArgumentCount) * kPointerSize));
(FCA::kArgsLength + 1 /* receiver */) * kPointerSize));
__ mov(ApiParameterOperand(kApiArgc + 3), scratch);
// v8::InvocationCallback's argument.
......
......@@ -3167,31 +3167,25 @@ void CallApiFunctionAndReturn(MacroAssembler* masm, Register function_address,
void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rsi : kTargetContext
// -- rdx : kApiFunctionAddress
// -- rcx : kArgc
// --
// -- rsi : context
// -- rdx : api function address
// -- rcx : arguments count (not including the receiver)
// -- rbx : call data
// -- rdi : holder
// -- 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 api_function_address = rdx;
Register argc = rcx;
Register call_data = rbx;
Register holder = rdi;
DCHECK(!AreAliased(api_function_address, argc, kScratchRegister));
// Stack offsets (without argc).
static constexpr int kReceiverOffset = kSystemPointerSize;
static constexpr int kHolderOffset = kReceiverOffset + kSystemPointerSize;
static constexpr int kCallDataOffset = kHolderOffset + kSystemPointerSize;
// Extra stack arguments are: the receiver, kHolder, kCallData.
static constexpr int kExtraStackArgumentCount = 3;
DCHECK(!AreAliased(api_function_address, argc, holder, call_data,
kScratchRegister));
typedef FunctionCallbackArguments FCA;
......@@ -3226,27 +3220,23 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
__ movq(Operand(rsp, 0 * kSystemPointerSize), kScratchRegister);
// kHolder.
__ movq(kScratchRegister,
Operand(rsp, argc, times_pointer_size,
FCA::kArgsLength * kSystemPointerSize + kHolderOffset));
__ movq(Operand(rsp, 1 * kSystemPointerSize), kScratchRegister);
__ movq(Operand(rsp, 1 * kSystemPointerSize), holder);
// kIsolate.
__ Move(kScratchRegister,
ExternalReference::isolate_address(masm->isolate()));
__ movq(Operand(rsp, 2 * kSystemPointerSize), kScratchRegister);
// kReturnValueDefaultValue, kReturnValue, and kNewTarget.
// kReturnValueDefaultValue and kReturnValue.
__ LoadRoot(kScratchRegister, RootIndex::kUndefinedValue);
__ movq(Operand(rsp, 3 * kSystemPointerSize), kScratchRegister);
__ movq(Operand(rsp, 4 * kSystemPointerSize), kScratchRegister);
__ movq(Operand(rsp, 6 * kSystemPointerSize), kScratchRegister);
// kData.
__ movq(kScratchRegister,
Operand(rsp, argc, times_pointer_size,
FCA::kArgsLength * kSystemPointerSize + kCallDataOffset));
__ movq(Operand(rsp, 5 * kSystemPointerSize), kScratchRegister);
__ movq(Operand(rsp, 5 * kSystemPointerSize), call_data);
// kNewTarget.
__ movq(Operand(rsp, 6 * kSystemPointerSize), kScratchRegister);
// Keep a pointer to kHolder (= implicit_args) in a scratch register.
// We use it below to set up the FunctionCallbackInfo object.
......@@ -3274,8 +3264,7 @@ void Builtins::Generate_CallApiCallback(MacroAssembler* masm) {
// from the API function here.
__ leaq(kScratchRegister,
Operand(argc, times_pointer_size,
(FCA::kArgsLength + kExtraStackArgumentCount) *
kSystemPointerSize));
(FCA::kArgsLength + 1 /* receiver */) * kSystemPointerSize));
__ movq(StackSpaceOperand(3), kScratchRegister);
Register arguments_arg = arg_reg_1;
......
......@@ -2875,7 +2875,6 @@ Reduction JSCallReducer::ReduceCallApiFunction(
? global_proxy
: NodeProperties::GetValueInput(node, 1);
Node* holder;
Node* context = NodeProperties::GetContextInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
......@@ -2978,14 +2977,11 @@ Reduction JSCallReducer::ReduceCallApiFunction(
&api_function, ExternalReference::DIRECT_API_CALL);
node->InsertInput(graph()->zone(), 0,
jsgraph()->HeapConstant(call_api_callback.code()));
node->ReplaceInput(1, context);
node->InsertInput(graph()->zone(), 2,
jsgraph()->ExternalConstant(function_reference));
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(1, jsgraph()->ExternalConstant(function_reference));
node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(argc));
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(data));
node->InsertInput(graph()->zone(), 4, holder);
node->ReplaceInput(5, receiver); // Update receiver input.
node->ReplaceInput(8 + argc, effect); // Update effect input.
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
return Changed(node);
......
......@@ -2108,16 +2108,17 @@ Node* JSNativeContextSpecialization::InlineApiCall(
// Add CallApiCallbackStub's register argument as well.
Node* context = jsgraph()->Constant(native_context());
Node* inputs[11] = {
code, context, function_reference, jsgraph()->Constant(argc), data,
holder, receiver};
int index = 7 + argc;
code, function_reference, jsgraph()->Constant(argc), data, holder,
receiver};
int index = 6 + argc;
inputs[index++] = context;
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[7] = value;
inputs[6] = value;
}
return *effect = *control =
......
......@@ -206,9 +206,10 @@ void ArgumentsAdaptorDescriptor::InitializePlatformSpecific(
void ApiCallbackDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
JavaScriptFrame::context_register(), // kTargetContext
edx, // kApiFunctionAddress
ecx, // kArgc
edx, // kApiFunctionAddress
ecx, // kArgc
eax, // kCallData
edi, // kHolder
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
......
......@@ -240,8 +240,8 @@ void AccessorAssembler::HandleLoadAccessor(
BIND(&load);
Callable callable = CodeFactory::CallApiCallback(isolate());
TNode<IntPtrT> argc = IntPtrConstant(0);
exit_point->Return(CallStub(callable, nullptr, context, callback, argc,
data, api_holder.value(), p->receiver));
exit_point->Return(CallStub(callable, context, callback, argc, data,
api_holder.value(), p->receiver));
}
BIND(&runtime);
......@@ -1381,7 +1381,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
BIND(&store);
Callable callable = CodeFactory::CallApiCallback(isolate());
TNode<IntPtrT> argc = IntPtrConstant(1);
Return(CallStub(callable, nullptr, context, callback, argc, data,
Return(CallStub(callable, context, callback, argc, data,
api_holder.value(), p->receiver, p->value));
}
......
......@@ -993,16 +993,12 @@ class CEntry1ArgvOnStackDescriptor : public CallInterfaceDescriptor {
class ApiCallbackDescriptor : public CallInterfaceDescriptor {
public:
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
DEFINE_PARAMETERS(kApiFunctionAddress, kActualArgumentsCount, kCallData,
kHolder)
// receiver is implicit stack argument 1
// argv are implicit stack arguments [2, 2 + kArgc[
DEFINE_PARAMETER_TYPES(MachineType::Pointer(), // kApiFunctionAddress
MachineType::IntPtr(), // kActualArgumentsCount
MachineType::AnyTagged(), // kCallData
MachineType::AnyTagged()) // kHolder
DECLARE_DESCRIPTOR(ApiCallbackDescriptor, CallInterfaceDescriptor)
......
......@@ -205,9 +205,10 @@ void ArgumentsAdaptorDescriptor::InitializePlatformSpecific(
void ApiCallbackDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
JavaScriptFrame::context_register(), // kTargetContext
rdx, // kApiFunctionAddress
rcx, // kArgc
rdx, // api function address
rcx, // argument count (not including receiver)
rbx, // call data
rdi, // holder
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment