From 16164471f32ec060d540a92251ab9d2198d10643 Mon Sep 17 00:00:00 2001 From: "serya@chromium.org" Date: Tue, 16 Nov 2010 15:04:41 +0000 Subject: [PATCH] API call code refactoring (ia32). Review URL: http://codereview.chromium.org/5055004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5831 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/ia32/macro-assembler-ia32.cc | 57 ++++++++++++++++++-------------- src/ia32/macro-assembler-ia32.h | 14 ++++++-- src/ia32/stub-cache-ia32.cc | 22 ++++++++---- 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index c53e2730b0..298db4bcbe 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -392,13 +392,8 @@ void MacroAssembler::EnterExitFrame() { } -void MacroAssembler::EnterApiExitFrame(int stack_space, - int argc) { +void MacroAssembler::EnterApiExitFrame(int argc) { EnterExitFramePrologue(); - - int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; - lea(esi, Operand(ebp, (stack_space * kPointerSize) + offset)); - EnterExitFrameEpilogue(argc); } @@ -411,6 +406,13 @@ void MacroAssembler::LeaveExitFrame() { // Pop the arguments and the receiver from the caller stack. lea(esp, Operand(esi, 1 * kPointerSize)); + // Push the return address to get ready to return. + push(ecx); + + LeaveExitFrameEpilogue(); +} + +void MacroAssembler::LeaveExitFrameEpilogue() { // Restore current context from top and clear it in debug mode. ExternalReference context_address(Top::k_context_address); mov(esi, Operand::StaticVariable(context_address)); @@ -418,15 +420,20 @@ void MacroAssembler::LeaveExitFrame() { mov(Operand::StaticVariable(context_address), Immediate(0)); #endif - // Push the return address to get ready to return. - push(ecx); - // Clear the top frame. ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0)); } +void MacroAssembler::LeaveApiExitFrame() { + mov(esp, Operand(ebp)); + pop(ebp); + + LeaveExitFrameEpilogue(); +} + + void MacroAssembler::PushTryHandler(CodeLocation try_location, HandlerType type) { // Adjust this code if not the case. @@ -1151,21 +1158,15 @@ Operand ApiParameterOperand(int index) { } -void MacroAssembler::PrepareCallApiFunction(int stack_space, int argc) { +void MacroAssembler::PrepareCallApiFunction(int argc, Register scratch) { if (kPassHandlesDirectly) { - EnterApiExitFrame(stack_space, argc); + EnterApiExitFrame(argc); // When handles as passed directly we don't have to allocate extra // space for and pass an out parameter. } else { // We allocate two additional slots: return value and pointer to it. - EnterApiExitFrame(stack_space, argc + 2); - } -} + EnterApiExitFrame(argc + 2); - -MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, - int argc) { - if (!kPassHandlesDirectly) { // The argument slots are filled as follows: // // n + 1: output cell @@ -1177,11 +1178,19 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, // Note that this is one more "argument" than the function expects // so the out cell will have to be popped explicitly after returning // from the function. The out cell contains Handle. - lea(eax, Operand(esp, (argc + 1) * kPointerSize)); // pointer to out cell. - mov(Operand(esp, 0 * kPointerSize), eax); // output. - mov(Operand(esp, (argc + 1) * kPointerSize), Immediate(0)); // out cell. - } + // pointer to out cell. + lea(scratch, Operand(esp, (argc + 1) * kPointerSize)); + mov(Operand(esp, 0 * kPointerSize), scratch); // output. + if (FLAG_debug_code) { + mov(Operand(esp, (argc + 1) * kPointerSize), Immediate(0)); // out cell. + } + } +} + + +MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, + int stack_space) { ExternalReference next_address = ExternalReference::handle_scope_next_address(); ExternalReference limit_address = @@ -1230,8 +1239,8 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, cmp(Operand::StaticVariable(scheduled_exception_address), Immediate(Factory::the_hole_value())); j(not_equal, &promote_scheduled_exception, not_taken); - LeaveExitFrame(); - ret(0); + LeaveApiExitFrame(); + ret(stack_space * kPointerSize); bind(&promote_scheduled_exception); MaybeObject* result = TryTailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index b205f84868..9dab37a2d3 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -123,13 +123,17 @@ class MacroAssembler: public Assembler { // to the first argument in register esi. void EnterExitFrame(); - void EnterApiExitFrame(int stack_space, int argc); + void EnterApiExitFrame(int argc); // Leave the current exit frame. Expects the return value in // register eax:edx (untouched) and the pointer to the first // argument in register esi. void LeaveExitFrame(); + // Leave the current exit frame. Expects the return value in + // register eax (untouched). + void LeaveApiExitFrame(); + // Find the function context up the context chain. void LoadContext(Register dst, int context_chain_length); @@ -499,12 +503,14 @@ class MacroAssembler: public Assembler { // Uses callee-saved esi to restore stack state after call. Arguments must be // stored in ApiParameterOperand(0), ApiParameterOperand(1) etc. Saves // context (esi). - void PrepareCallApiFunction(int stack_space, int argc); + void PrepareCallApiFunction(int argc, Register scratch); // Calls an API function. Allocates HandleScope, extracts // returned value from handle and propagates exceptions. // Clobbers ebx, edi and caller-save registers. Restores context. - MaybeObject* TryCallApiFunctionAndReturn(ApiFunction* function, int argc); + // On return removes stack_space * kPointerSize (GCed). + MaybeObject* TryCallApiFunctionAndReturn(ApiFunction* function, + int stack_space); // Jump to a runtime routine. void JumpToExternalReference(const ExternalReference& ext); @@ -603,6 +609,8 @@ class MacroAssembler: public Assembler { void EnterExitFramePrologue(); void EnterExitFrameEpilogue(int argc); + + void LeaveExitFrameEpilogue(); // Allocation support helpers. void LoadAllocationTopHelper(Register result, diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 48e04c8983..116447fd76 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -499,8 +499,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm, // it's not controlled by GC. const int kApiStackSpace = 4; - __ PrepareCallApiFunction(argc + kFastApiCallArguments + 1, - kApiArgc + kApiStackSpace); + __ PrepareCallApiFunction(kApiArgc + kApiStackSpace, ebx); __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. __ add(Operand(eax), Immediate(argc * kPointerSize)); @@ -518,7 +517,7 @@ static bool GenerateFastApiCall(MacroAssembler* masm, // garbage collection but instead return the allocation failure // object. MaybeObject* result = - masm->TryCallApiFunctionAndReturn(&fun, kApiArgc + kApiStackSpace); + masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1); if (result->IsFailure()) { *failure = Failure::cast(result); return false; @@ -1109,7 +1108,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, const int kStackSpace = 5; const int kApiArgc = 2; - __ PrepareCallApiFunction(kStackSpace, kApiArgc); + __ PrepareCallApiFunction(kApiArgc, eax); __ mov(ApiParameterOperand(0), ebx); // name. __ add(Operand(ebx), Immediate(kPointerSize)); __ mov(ApiParameterOperand(1), ebx); // arguments pointer. @@ -1118,7 +1117,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, // already generated). Do not allow the assembler to perform a // garbage collection but instead return the allocation failure // object. - MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kApiArgc); + MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); if (result->IsFailure()) { *failure = Failure::cast(result); return false; @@ -2169,7 +2168,10 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, if (depth != kInvalidProtoDepth) { __ IncrementCounter(&Counters::call_const_fast_api, 1); - ReserveSpaceForFastApiCall(masm(), eax); + + // Allocate space for v8::Arguments implicit values. Must be initialized + // before to call any runtime function. + __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); } // Check that the maps haven't changed. @@ -2249,6 +2251,12 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, if (depth != kInvalidProtoDepth) { Failure* failure; + // Move the return address on top of the stack. + __ mov(eax, Operand(esp, 3 * kPointerSize)); + __ mov(Operand(esp, 0 * kPointerSize), eax); + + // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains + // duplicate of return address and will be overwritten. bool success = GenerateFastApiCall(masm(), optimization, argc, &failure); if (!success) { return failure; @@ -2260,7 +2268,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, // Handle call cache miss. __ bind(&miss); if (depth != kInvalidProtoDepth) { - FreeSpaceForFastApiCall(masm(), eax); + __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); } __ bind(&miss_in_smi_check); Object* obj;