From af7825c05fd7a01dc65c9baeea7998b0d8a2e380 Mon Sep 17 00:00:00 2001 From: "serya@chromium.org" Date: Wed, 17 Nov 2010 10:44:16 +0000 Subject: [PATCH] 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 --- src/x64/code-stubs-x64.cc | 2 +- src/x64/macro-assembler-x64.cc | 46 +++++++++++++++++++++++------------------- src/x64/macro-assembler-x64.h | 31 ++++++++++++++-------------- src/x64/stub-cache-x64.cc | 44 ++++++++++++++++++++++++---------------- 4 files changed, 69 insertions(+), 54 deletions(-) diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 527ae61..04173e1 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -2582,7 +2582,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, __ j(zero, &failure_returned); // Exit the JavaScript to C++ exit frame. - __ LeaveExitFrame(result_size_); + __ LeaveExitFrame(); __ ret(0); // Handling of failure. diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index dd74da0..834a6f6 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -498,23 +498,22 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) { } -void MacroAssembler::PrepareCallApiFunction(int stack_space, - int arg_stack_space) { +void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) { #ifdef _WIN64 // We need to prepare a slot for result handle on stack and put // 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. lea(rcx, StackSpaceOperand(arg_stack_space)); #else - EnterApiExitFrame(stack_space, arg_stack_space); + EnterApiExitFrame(arg_stack_space); #endif } MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( - ApiFunction* function) { + ApiFunction* function, int stack_space) { Label empty_result; Label prologue; Label promote_scheduled_exception; @@ -537,7 +536,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( // Allocate HandleScope in callee-save registers. Register prev_next_address_reg = r14; Register prev_limit_reg = rbx; - Register base_reg = kSmiConstantRegister; + Register base_reg = r12; movq(base_reg, next_address); movq(prev_next_address_reg, Operand(base_reg, kNextOffset)); movq(prev_limit_reg, Operand(base_reg, kLimitOffset)); @@ -566,15 +565,14 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( cmpq(prev_limit_reg, Operand(base_reg, kLimitOffset)); j(not_equal, &delete_allocated_handles); bind(&leave_exit_frame); - InitializeSmiConstantRegister(); // Check if the function scheduled an exception. movq(rsi, scheduled_exception_address); Cmp(Operand(rsi, 0), Factory::the_hole_value()); j(not_equal, &promote_scheduled_exception); - LeaveExitFrame(); - ret(0); + LeaveApiExitFrame(); + ret(stack_space * kPointerSize); bind(&promote_scheduled_exception); MaybeObject* result = TryTailCallRuntime(Runtime::kPromoteScheduledException, @@ -1778,20 +1776,13 @@ void MacroAssembler::EnterExitFrame(int arg_stack_space) { } -void MacroAssembler::EnterApiExitFrame(int stack_space, - int arg_stack_space) { +void MacroAssembler::EnterApiExitFrame(int arg_stack_space) { 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); } -void MacroAssembler::LeaveExitFrame(int result_size) { +void MacroAssembler::LeaveExitFrame() { // Registers: // r12 : argv @@ -1803,6 +1794,22 @@ void MacroAssembler::LeaveExitFrame(int result_size) { // from the caller stack. 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. ExternalReference context_address(Top::k_context_address); movq(kScratchRegister, context_address); @@ -1811,9 +1818,6 @@ void MacroAssembler::LeaveExitFrame(int result_size) { movq(Operand(kScratchRegister, 0), Immediate(0)); #endif - // Push the return address to get ready to return. - push(rcx); - // Clear the top frame. ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); movq(kScratchRegister, c_entry_fp_address); diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index c2fc830..5b082fd 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -160,14 +160,18 @@ class MacroAssembler: public Assembler { // accessible via StackSpaceOperand. void EnterExitFrame(int arg_stack_space = 0); - void EnterApiExitFrame(int stack_space, - int arg_stack_space); + // Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize + // 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 // register rax:rdx (untouched) and the pointer to the first // 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 @@ -835,23 +839,18 @@ class MacroAssembler: public Assembler { int result_size); // Prepares stack to put arguments (aligns and so on). - // Uses callee-saved rsi to restore stack state after call. WIN64 calling - // convention requires to put the pointer to the return value slot into rcx - // (rcx must be preserverd until TryCallApiFunctionAndReturn). argc is number - // of arguments to be passed in C-function. stack_space * kPointerSize bytes - // will be removed from stack after the call. Saves context (rsi). - // 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); + // WIN64 calling convention requires to put the pointer to the return value + // slot into rcx (rcx must be preserverd until TryCallApiFunctionAndReturn). + // Saves context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize + // inside the exit frame (not GCed) accessible via StackSpaceOperand. + void PrepareCallApiFunction(int arg_stack_space); // Calls an API function. Allocates HandleScope, extracts // returned value from handle and propagates exceptions. // Clobbers r12, r14, rbx and caller-save registers. Restores context. + // On return removes stack_space * kPointerSize (GCed). MUST_USE_RESULT MaybeObject* TryCallApiFunctionAndReturn( - ApiFunction* function); + ApiFunction* function, int stack_space); // 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], @@ -947,6 +946,8 @@ class MacroAssembler: public Assembler { // accessible via StackSpaceOperand. void EnterExitFrameEpilogue(int arg_stack_space); + void LeaveExitFrameEpilogue(); + // Allocation support helpers. // Loads the top of new-space into the result register. // If flags contains RESULT_CONTAINS_TOP then result_end is valid and diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 2085333..2e60dd5 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -500,7 +500,7 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, // Number of pointers to be reserved on stack for fast API call. 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. // // These arguments are set by CheckPrototypes and GenerateFastApiCall. @@ -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, const CallOptimization& optimization, int argc, @@ -559,7 +559,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm, __ Move(rdi, Handle(function)); __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); - // Pass the additional arguments FastHandleApiCall expects. + // Pass the additional arguments. __ movq(Operand(rsp, 2 * kPointerSize), rdi); Object* call_data = optimization.api_call_info()->data(); Handle api_call_info_handle(optimization.api_call_info()); @@ -589,7 +589,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm, // it's not controlled by GC. const int kApiStackSpace = 4; - __ PrepareCallApiFunction(argc + kFastApiCallArguments + 1, kApiStackSpace); + __ PrepareCallApiFunction(kApiStackSpace); __ movq(StackSpaceOperand(0), rbx); // v8::Arguments::implicit_args_. __ addq(rbx, Immediate(argc * kPointerSize)); @@ -605,7 +605,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm, // garbage collection but instead return the allocation failure // object. MaybeObject* result = - masm->TryCallApiFunctionAndReturn(&fun); + masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1); if (result->IsFailure()) { *failure = Failure::cast(result); return false; @@ -992,7 +992,9 @@ MaybeObject* CallStubCompiler::CompileCallConstant( if (depth != kInvalidProtoDepth) { __ 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. @@ -1071,6 +1073,12 @@ MaybeObject* CallStubCompiler::CompileCallConstant( if (depth != kInvalidProtoDepth) { 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); if (!success) { return failure; @@ -1082,7 +1090,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant( // Handle call cache miss. __ bind(&miss); if (depth != kInvalidProtoDepth) { - FreeSpaceForFastApiCall(masm(), rax); + __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); } // Handle call cache miss. @@ -2633,8 +2641,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, __ pop(scratch2); // Get return address to place it below. __ push(receiver); // receiver - ASSERT(!scratch3.is(reg)); - __ movq(scratch3, rsp); __ push(reg); // holder if (Heap::InNewSpace(callback_handle->data())) { __ Move(scratch1, callback_handle); @@ -2642,7 +2648,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, } else { __ Push(Handle(callback_handle->data())); } - __ push(scratch3); __ push(name_reg); // name // Save a pointer to where we pushed the arguments pointer. // This will be passed as the const AccessorInfo& to the C++ callback. @@ -2664,22 +2669,27 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, Address getter_address = v8::ToCData
(callback->getter()); ApiFunction fun(getter_address); - // 3 elements array for v8::Agruments::values_, handler for name and pointer - // to the values (it considered as smi in GC). - const int kStackSpace = 5; - const int kApiArgc = 2; + // 3 elements array for v8::Agruments::values_ and handler for name. + const int kStackSpace = 4; + + // 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 // 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 // already generated). Do not allow the assembler to perform a // garbage collection but instead return the allocation failure // object. - MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun); + MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); if (result->IsFailure()) { *failure = Failure::cast(result); return false; -- 2.7.4