Commit af7825c0 authored by serya@chromium.org's avatar serya@chromium.org

API call code refactoring (x64).

Review URL: http://codereview.chromium.org/5108003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5836 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f42de7dc
...@@ -2582,7 +2582,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, ...@@ -2582,7 +2582,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ j(zero, &failure_returned); __ j(zero, &failure_returned);
// Exit the JavaScript to C++ exit frame. // Exit the JavaScript to C++ exit frame.
__ LeaveExitFrame(result_size_); __ LeaveExitFrame();
__ ret(0); __ ret(0);
// Handling of failure. // Handling of failure.
......
...@@ -498,23 +498,22 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) { ...@@ -498,23 +498,22 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) {
} }
void MacroAssembler::PrepareCallApiFunction(int stack_space, void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) {
int arg_stack_space) {
#ifdef _WIN64 #ifdef _WIN64
// We need to prepare a slot for result handle on stack and put // We need to prepare a slot for result handle on stack and put
// a pointer to it into 1st arg register. // a pointer to it into 1st arg register.
EnterApiExitFrame(stack_space, arg_stack_space + 1); EnterApiExitFrame(arg_stack_space + 1);
// rcx must be used to pass the pointer to the return value slot. // rcx must be used to pass the pointer to the return value slot.
lea(rcx, StackSpaceOperand(arg_stack_space)); lea(rcx, StackSpaceOperand(arg_stack_space));
#else #else
EnterApiExitFrame(stack_space, arg_stack_space); EnterApiExitFrame(arg_stack_space);
#endif #endif
} }
MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
ApiFunction* function) { ApiFunction* function, int stack_space) {
Label empty_result; Label empty_result;
Label prologue; Label prologue;
Label promote_scheduled_exception; Label promote_scheduled_exception;
...@@ -537,7 +536,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( ...@@ -537,7 +536,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
// Allocate HandleScope in callee-save registers. // Allocate HandleScope in callee-save registers.
Register prev_next_address_reg = r14; Register prev_next_address_reg = r14;
Register prev_limit_reg = rbx; Register prev_limit_reg = rbx;
Register base_reg = kSmiConstantRegister; Register base_reg = r12;
movq(base_reg, next_address); movq(base_reg, next_address);
movq(prev_next_address_reg, Operand(base_reg, kNextOffset)); movq(prev_next_address_reg, Operand(base_reg, kNextOffset));
movq(prev_limit_reg, Operand(base_reg, kLimitOffset)); movq(prev_limit_reg, Operand(base_reg, kLimitOffset));
...@@ -566,15 +565,14 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( ...@@ -566,15 +565,14 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
cmpq(prev_limit_reg, Operand(base_reg, kLimitOffset)); cmpq(prev_limit_reg, Operand(base_reg, kLimitOffset));
j(not_equal, &delete_allocated_handles); j(not_equal, &delete_allocated_handles);
bind(&leave_exit_frame); bind(&leave_exit_frame);
InitializeSmiConstantRegister();
// Check if the function scheduled an exception. // Check if the function scheduled an exception.
movq(rsi, scheduled_exception_address); movq(rsi, scheduled_exception_address);
Cmp(Operand(rsi, 0), Factory::the_hole_value()); Cmp(Operand(rsi, 0), Factory::the_hole_value());
j(not_equal, &promote_scheduled_exception); j(not_equal, &promote_scheduled_exception);
LeaveExitFrame(); LeaveApiExitFrame();
ret(0); ret(stack_space * kPointerSize);
bind(&promote_scheduled_exception); bind(&promote_scheduled_exception);
MaybeObject* result = TryTailCallRuntime(Runtime::kPromoteScheduledException, MaybeObject* result = TryTailCallRuntime(Runtime::kPromoteScheduledException,
...@@ -1778,20 +1776,13 @@ void MacroAssembler::EnterExitFrame(int arg_stack_space) { ...@@ -1778,20 +1776,13 @@ void MacroAssembler::EnterExitFrame(int arg_stack_space) {
} }
void MacroAssembler::EnterApiExitFrame(int stack_space, void MacroAssembler::EnterApiExitFrame(int arg_stack_space) {
int arg_stack_space) {
EnterExitFramePrologue(false); EnterExitFramePrologue(false);
// Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
// so it must be retained across the C-call.
int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
lea(r12, Operand(rbp, (stack_space * kPointerSize) + offset));
EnterExitFrameEpilogue(arg_stack_space); EnterExitFrameEpilogue(arg_stack_space);
} }
void MacroAssembler::LeaveExitFrame(int result_size) { void MacroAssembler::LeaveExitFrame() {
// Registers: // Registers:
// r12 : argv // r12 : argv
...@@ -1803,6 +1794,22 @@ void MacroAssembler::LeaveExitFrame(int result_size) { ...@@ -1803,6 +1794,22 @@ void MacroAssembler::LeaveExitFrame(int result_size) {
// from the caller stack. // from the caller stack.
lea(rsp, Operand(r12, 1 * kPointerSize)); lea(rsp, Operand(r12, 1 * kPointerSize));
// Push the return address to get ready to return.
push(rcx);
LeaveExitFrameEpilogue();
}
void MacroAssembler::LeaveApiExitFrame() {
movq(rsp, rbp);
pop(rbp);
LeaveExitFrameEpilogue();
}
void MacroAssembler::LeaveExitFrameEpilogue() {
// Restore current context from top and clear it in debug mode. // Restore current context from top and clear it in debug mode.
ExternalReference context_address(Top::k_context_address); ExternalReference context_address(Top::k_context_address);
movq(kScratchRegister, context_address); movq(kScratchRegister, context_address);
...@@ -1811,9 +1818,6 @@ void MacroAssembler::LeaveExitFrame(int result_size) { ...@@ -1811,9 +1818,6 @@ void MacroAssembler::LeaveExitFrame(int result_size) {
movq(Operand(kScratchRegister, 0), Immediate(0)); movq(Operand(kScratchRegister, 0), Immediate(0));
#endif #endif
// Push the return address to get ready to return.
push(rcx);
// Clear the top frame. // Clear the top frame.
ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
movq(kScratchRegister, c_entry_fp_address); movq(kScratchRegister, c_entry_fp_address);
......
...@@ -160,14 +160,18 @@ class MacroAssembler: public Assembler { ...@@ -160,14 +160,18 @@ class MacroAssembler: public Assembler {
// accessible via StackSpaceOperand. // accessible via StackSpaceOperand.
void EnterExitFrame(int arg_stack_space = 0); void EnterExitFrame(int arg_stack_space = 0);
void EnterApiExitFrame(int stack_space, // Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize
int arg_stack_space); // memory (not GCed) on the stack accessible via StackSpaceOperand.
void EnterApiExitFrame(int arg_stack_space);
// Leave the current exit frame. Expects/provides the return value in // Leave the current exit frame. Expects/provides the return value in
// register rax:rdx (untouched) and the pointer to the first // register rax:rdx (untouched) and the pointer to the first
// argument in register rsi. // argument in register rsi.
void LeaveExitFrame(int result_size = 1); void LeaveExitFrame();
// Leave the current exit frame. Expects/provides the return value in
// register rax (untouched).
void LeaveApiExitFrame();
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// JavaScript invokes // JavaScript invokes
...@@ -835,23 +839,18 @@ class MacroAssembler: public Assembler { ...@@ -835,23 +839,18 @@ class MacroAssembler: public Assembler {
int result_size); int result_size);
// Prepares stack to put arguments (aligns and so on). // Prepares stack to put arguments (aligns and so on).
// Uses callee-saved rsi to restore stack state after call. WIN64 calling // WIN64 calling convention requires to put the pointer to the return value
// convention requires to put the pointer to the return value slot into rcx // slot into rcx (rcx must be preserverd until TryCallApiFunctionAndReturn).
// (rcx must be preserverd until TryCallApiFunctionAndReturn). argc is number // Saves context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize
// of arguments to be passed in C-function. stack_space * kPointerSize bytes // inside the exit frame (not GCed) accessible via StackSpaceOperand.
// will be removed from stack after the call. Saves context (rsi). void PrepareCallApiFunction(int arg_stack_space);
// Clobbers rax. Allocates arg_stack_space * kPointerSize inside the exit
// frame (not GCed).
//
// Assumes stack_space GCed references on top of the stack and return address.
// After call they will be removed.
void PrepareCallApiFunction(int stack_space, int arg_stack_space);
// Calls an API function. Allocates HandleScope, extracts // Calls an API function. Allocates HandleScope, extracts
// returned value from handle and propagates exceptions. // returned value from handle and propagates exceptions.
// Clobbers r12, r14, rbx and caller-save registers. Restores context. // Clobbers r12, r14, rbx and caller-save registers. Restores context.
// On return removes stack_space * kPointerSize (GCed).
MUST_USE_RESULT MaybeObject* TryCallApiFunctionAndReturn( MUST_USE_RESULT MaybeObject* TryCallApiFunctionAndReturn(
ApiFunction* function); ApiFunction* function, int stack_space);
// Before calling a C-function from generated code, align arguments on stack. // Before calling a C-function from generated code, align arguments on stack.
// After aligning the frame, arguments must be stored in esp[0], esp[4], // After aligning the frame, arguments must be stored in esp[0], esp[4],
...@@ -947,6 +946,8 @@ class MacroAssembler: public Assembler { ...@@ -947,6 +946,8 @@ class MacroAssembler: public Assembler {
// accessible via StackSpaceOperand. // accessible via StackSpaceOperand.
void EnterExitFrameEpilogue(int arg_stack_space); void EnterExitFrameEpilogue(int arg_stack_space);
void LeaveExitFrameEpilogue();
// Allocation support helpers. // Allocation support helpers.
// Loads the top of new-space into the result register. // Loads the top of new-space into the result register.
// If flags contains RESULT_CONTAINS_TOP then result_end is valid and // If flags contains RESULT_CONTAINS_TOP then result_end is valid and
......
...@@ -500,7 +500,7 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, ...@@ -500,7 +500,7 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
// Number of pointers to be reserved on stack for fast API call. // Number of pointers to be reserved on stack for fast API call.
static const int kFastApiCallArguments = 3; static const int kFastApiCallArguments = 3;
// Reserves space for the extra arguments to FastHandleApiCall in the // Reserves space for the extra arguments to API function in the
// caller's frame. // caller's frame.
// //
// These arguments are set by CheckPrototypes and GenerateFastApiCall. // These arguments are set by CheckPrototypes and GenerateFastApiCall.
...@@ -535,7 +535,7 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { ...@@ -535,7 +535,7 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
} }
// Generates call to FastHandleApiCall builtin. // Generates call to API function.
static bool GenerateFastApiCall(MacroAssembler* masm, static bool GenerateFastApiCall(MacroAssembler* masm,
const CallOptimization& optimization, const CallOptimization& optimization,
int argc, int argc,
...@@ -559,7 +559,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm, ...@@ -559,7 +559,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm,
__ Move(rdi, Handle<JSFunction>(function)); __ Move(rdi, Handle<JSFunction>(function));
__ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
// Pass the additional arguments FastHandleApiCall expects. // Pass the additional arguments.
__ movq(Operand(rsp, 2 * kPointerSize), rdi); __ movq(Operand(rsp, 2 * kPointerSize), rdi);
Object* call_data = optimization.api_call_info()->data(); Object* call_data = optimization.api_call_info()->data();
Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info()); Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
...@@ -589,7 +589,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm, ...@@ -589,7 +589,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm,
// it's not controlled by GC. // it's not controlled by GC.
const int kApiStackSpace = 4; const int kApiStackSpace = 4;
__ PrepareCallApiFunction(argc + kFastApiCallArguments + 1, kApiStackSpace); __ PrepareCallApiFunction(kApiStackSpace);
__ movq(StackSpaceOperand(0), rbx); // v8::Arguments::implicit_args_. __ movq(StackSpaceOperand(0), rbx); // v8::Arguments::implicit_args_.
__ addq(rbx, Immediate(argc * kPointerSize)); __ addq(rbx, Immediate(argc * kPointerSize));
...@@ -605,7 +605,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm, ...@@ -605,7 +605,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm,
// garbage collection but instead return the allocation failure // garbage collection but instead return the allocation failure
// object. // object.
MaybeObject* result = MaybeObject* result =
masm->TryCallApiFunctionAndReturn(&fun); masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1);
if (result->IsFailure()) { if (result->IsFailure()) {
*failure = Failure::cast(result); *failure = Failure::cast(result);
return false; return false;
...@@ -992,7 +992,9 @@ MaybeObject* CallStubCompiler::CompileCallConstant( ...@@ -992,7 +992,9 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
if (depth != kInvalidProtoDepth) { if (depth != kInvalidProtoDepth) {
__ IncrementCounter(&Counters::call_const_fast_api, 1); __ IncrementCounter(&Counters::call_const_fast_api, 1);
ReserveSpaceForFastApiCall(masm(), rax); // Allocate space for v8::Arguments implicit values. Must be initialized
// before to call any runtime function.
__ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
} }
// Check that the maps haven't changed. // Check that the maps haven't changed.
...@@ -1071,6 +1073,12 @@ MaybeObject* CallStubCompiler::CompileCallConstant( ...@@ -1071,6 +1073,12 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
if (depth != kInvalidProtoDepth) { if (depth != kInvalidProtoDepth) {
Failure* failure; Failure* failure;
// Move the return address on top of the stack.
__ movq(rax, Operand(rsp, 3 * kPointerSize));
__ movq(Operand(rsp, 0 * kPointerSize), rax);
// rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
// duplicate of return address and will be overwritten.
bool success = GenerateFastApiCall(masm(), optimization, argc, &failure); bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
if (!success) { if (!success) {
return failure; return failure;
...@@ -1082,7 +1090,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant( ...@@ -1082,7 +1090,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
// Handle call cache miss. // Handle call cache miss.
__ bind(&miss); __ bind(&miss);
if (depth != kInvalidProtoDepth) { if (depth != kInvalidProtoDepth) {
FreeSpaceForFastApiCall(masm(), rax); __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
} }
// Handle call cache miss. // Handle call cache miss.
...@@ -2633,8 +2641,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ...@@ -2633,8 +2641,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
__ pop(scratch2); // Get return address to place it below. __ pop(scratch2); // Get return address to place it below.
__ push(receiver); // receiver __ push(receiver); // receiver
ASSERT(!scratch3.is(reg));
__ movq(scratch3, rsp);
__ push(reg); // holder __ push(reg); // holder
if (Heap::InNewSpace(callback_handle->data())) { if (Heap::InNewSpace(callback_handle->data())) {
__ Move(scratch1, callback_handle); __ Move(scratch1, callback_handle);
...@@ -2642,7 +2648,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ...@@ -2642,7 +2648,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
} else { } else {
__ Push(Handle<Object>(callback_handle->data())); __ Push(Handle<Object>(callback_handle->data()));
} }
__ push(scratch3);
__ push(name_reg); // name __ push(name_reg); // name
// Save a pointer to where we pushed the arguments pointer. // Save a pointer to where we pushed the arguments pointer.
// This will be passed as the const AccessorInfo& to the C++ callback. // This will be passed as the const AccessorInfo& to the C++ callback.
...@@ -2664,22 +2669,27 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ...@@ -2664,22 +2669,27 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
Address getter_address = v8::ToCData<Address>(callback->getter()); Address getter_address = v8::ToCData<Address>(callback->getter());
ApiFunction fun(getter_address); ApiFunction fun(getter_address);
// 3 elements array for v8::Agruments::values_, handler for name and pointer // 3 elements array for v8::Agruments::values_ and handler for name.
// to the values (it considered as smi in GC). const int kStackSpace = 4;
const int kStackSpace = 5;
const int kApiArgc = 2; // Allocate v8::AccessorInfo in non-GCed stack space.
const int kArgStackSpace = 1;
__ PrepareCallApiFunction(kArgStackSpace);
__ lea(rax, Operand(name_arg, 3 * kPointerSize));
__ PrepareCallApiFunction(kStackSpace, kApiArgc); // v8::AccessorInfo::args_.
__ movq(StackSpaceOperand(0), rax);
// The context register (rsi) has been saved in PrepareCallApiFunction and // The context register (rsi) has been saved in PrepareCallApiFunction and
// could be used to pass arguments. // could be used to pass arguments.
__ lea(accessor_info_arg, Operand(name_arg, 1 * kPointerSize)); __ lea(accessor_info_arg, StackSpaceOperand(0));
// Emitting a stub call may try to allocate (if the code is not // Emitting a stub call may try to allocate (if the code is not
// already generated). Do not allow the assembler to perform a // already generated). Do not allow the assembler to perform a
// garbage collection but instead return the allocation failure // garbage collection but instead return the allocation failure
// object. // object.
MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun); MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
if (result->IsFailure()) { if (result->IsFailure()) {
*failure = Failure::cast(result); *failure = Failure::cast(result);
return false; return false;
......
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