Index: src/builtins/x64/builtins-x64.cc |
diff --git a/src/builtins/x64/builtins-x64.cc b/src/builtins/x64/builtins-x64.cc |
index 076cc8596cebf54b9b70be50beaab330660bf122..493036c0af726a86845a64b3ccb0a124a34ac96b 100644 |
--- a/src/builtins/x64/builtins-x64.cc |
+++ b/src/builtins/x64/builtins-x64.cc |
@@ -4,6 +4,7 @@ |
#if V8_TARGET_ARCH_X64 |
+#include "src/api-arguments.h" |
#include "src/code-factory.h" |
#include "src/codegen.h" |
#include "src/counters.h" |
@@ -2936,6 +2937,139 @@ void Builtins::Generate_CallWithSpread(MacroAssembler* masm) { |
} |
// static |
+void Builtins::Generate_CallFunctionCallback(MacroAssembler* masm) { |
+ // ----------- S t a t e ------------- |
+ // -- rax : the number of arguments (not incl. the receiver) |
+ // -- rdx : api function address |
+ // -- rsp[0] : return address |
+ // -- rsp[8] : holder |
+ // -- rsp[16] : isolate |
+ // -- rsp[24] : return value default |
+ // -- rsp[32] : return value |
+ // -- rsp[40] : call data |
+ // -- rsp[48] : target |
+ // -- rsp[56] : context save |
+ // -- rsp[64] : new.target |
+ // -- rsp[72] : last argument |
+ // -- rsp[64 + argc * 8] : first argument |
+ // -- rsp[72 + argc * 8] : receiver |
+ // ----------------------------------- |
+ typedef FunctionCallbackArguments FCA; |
+ |
+ STATIC_ASSERT(FCA::kNewTargetIndex == 7); |
+ STATIC_ASSERT(FCA::kContextSaveIndex == 6); |
+ STATIC_ASSERT(FCA::kCalleeIndex == 5); |
+ STATIC_ASSERT(FCA::kDataIndex == 4); |
+ STATIC_ASSERT(FCA::kReturnValueOffset == 3); |
+ STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); |
+ STATIC_ASSERT(FCA::kIsolateIndex == 1); |
+ STATIC_ASSERT(FCA::kHolderIndex == 0); |
+ STATIC_ASSERT(FCA::kArgsLength == 8); |
+ |
+ // Compute the pointer to the implicit args on the stack. |
+ __ leap(rbx, MemOperand(rsp, kPCOnStackSize)); |
+ |
+ // Allocate the v8::FunctionCallbackInfo structure in the arguments' space |
+ // since it's not controlled by the GC. |
+ const int kApiStackSpace = 3; |
+ __ EnterApiExitFrame(kApiStackSpace); |
+ // Initialize FunctionCallbackInfo::implicit_args_. |
+ __ movp(StackSpaceOperand(0), rbx); |
+ // Initialize FunctionCallbackInfo::values_. |
+ __ leap(rbx, MemOperand(rbx, rax, times_pointer_size, |
+ (FCA::kArgsLength - 1) * kPointerSize)); |
+ __ movp(StackSpaceOperand(1), rbx); |
+ // Initialize FunctionCallbackInfo::length_. |
+ __ movp(StackSpaceOperand(2), rax); |
+ |
+ // Load first argument with pointer to FunctionCallbackInfo. |
+ __ leap(arg_reg_1, StackSpaceOperand(0)); |
+ |
+ const int kNextOffset = 0; |
+ const int kLimitOffset = AddressOffset( |
+ ExternalReference::handle_scope_limit_address(masm->isolate()), |
+ ExternalReference::handle_scope_next_address(masm->isolate())); |
+ const int kLevelOffset = AddressOffset( |
+ ExternalReference::handle_scope_level_address(masm->isolate()), |
+ ExternalReference::handle_scope_next_address(masm->isolate())); |
+ |
+ // Allocate HandleScope in callee-save registers. |
+ Register const prev_next_address_reg = r14; |
+ Register const prev_limit_reg = rbx; |
+ Register const base_reg = r15; |
+ __ Move(base_reg, |
+ ExternalReference::handle_scope_next_address(masm->isolate())); |
+ __ movp(prev_next_address_reg, Operand(base_reg, kNextOffset)); |
+ __ movp(prev_limit_reg, Operand(base_reg, kLimitOffset)); |
+ __ addl(Operand(base_reg, kLevelOffset), Immediate(1)); |
+ |
+ // Check if profiling is active, and if so call the function indirectly |
+ // via the invoke_function_callback helper. |
+ Label call_indirect, done_call; |
+ __ Move(rax, ExternalReference::is_profiling_address(masm->isolate())); |
+ __ cmpb(MemOperand(rax, 0), Immediate(0)); |
+ __ j(not_zero, &call_indirect, Label::kNear); |
+ { |
+ // Call the API function directly. |
+ __ call(rdx); |
+ } |
+ __ jmp(&done_call, Label::kNear); |
+ __ bind(&call_indirect); |
+ { |
+ // Call the API function indirectly when profiling is on. |
+ __ Move(arg_reg_2, rdx); |
+ __ Call(ExternalReference::invoke_function_callback(masm->isolate())); |
+ } |
+ __ bind(&done_call); |
+ |
+ // No more valid handles (the result handle was the last one). Restore |
+ // previous handle scope. |
+ Label delete_allocated_handles; |
+ __ subl(Operand(base_reg, kLevelOffset), Immediate(1)); |
+ __ movp(Operand(base_reg, kNextOffset), prev_next_address_reg); |
+ __ cmpp(prev_limit_reg, Operand(base_reg, kLimitOffset)); |
+ __ j(not_equal, &delete_allocated_handles); |
+ |
+ // Leave the API exit frame. |
+ Label leave_exit_frame; |
+ __ bind(&leave_exit_frame); |
+ __ movp(rax, MemOperand(rbp, (2 + FCA::kReturnValueOffset) * kPointerSize)); |
+ __ movp(rsi, MemOperand(rbp, (2 + FCA::kContextSaveIndex) * kPointerSize)); |
+ __ movp(rbx, StackSpaceOperand(2)); |
+ __ LeaveApiExitFrame(false); |
+ |
+ // Check if the function scheduled an exception. |
+ Label promote_scheduled_exception; |
+ __ Move(rdi, ExternalReference::scheduled_exception_address(masm->isolate())); |
+ __ JumpIfNotRoot(MemOperand(rdi, 0), Heap::kTheHoleValueRootIndex, |
+ &promote_scheduled_exception); |
+ |
+ // Check if the function returned a valid JavaScript value. |
+ __ AssertApiCallResult(rax); |
+ |
+ // Drop the arguments and return. |
+ __ PopReturnAddressTo(rcx); |
+ __ leaq(rsp, MemOperand(rsp, rbx, times_pointer_size, |
+ (FCA::kArgsLength + 1) * kPointerSize)); |
+ __ PushReturnAddressFrom(rcx); |
+ __ Ret(); |
+ |
+ // Re-throw by promoting a scheduled exception. |
+ __ bind(&promote_scheduled_exception); |
+ __ TailCallRuntime(Runtime::kPromoteScheduledException); |
+ |
+ // HandleScope limit has changed. Delete allocated extensions. |
+ __ bind(&delete_allocated_handles); |
+ { |
+ __ movp(Operand(base_reg, kLimitOffset), prev_limit_reg); |
+ __ LoadAddress(arg_reg_1, |
+ ExternalReference::isolate_address(masm->isolate())); |
+ __ Call(ExternalReference::delete_handle_scope_extensions(masm->isolate())); |
+ } |
+ __ jmp(&leave_exit_frame); |
+} |
+ |
+// static |
void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { |
// ----------- S t a t e ------------- |
// -- rax : the number of arguments (not including the receiver) |