From 0020146f24e457461767f0583a09aab6d32cf6a3 Mon Sep 17 00:00:00 2001 From: "dcarney@chromium.org" Date: Tue, 17 Sep 2013 07:19:50 +0000 Subject: [PATCH] add context save for GenerateFastApiCall R=mstarzinger@chromium.org BUG= Review URL: https://codereview.chromium.org/23461039 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16744 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8.h | 3 +- src/arguments.h | 2 + src/arm/code-stubs-arm.cc | 4 +- src/arm/macro-assembler-arm.cc | 41 ++++++++++++------- src/arm/macro-assembler-arm.h | 7 +++- src/arm/stub-cache-arm.cc | 66 +++++++++++++++++++----------- src/ia32/code-stubs-ia32.cc | 2 +- src/ia32/macro-assembler-ia32.cc | 37 +++++++++++------ src/ia32/macro-assembler-ia32.h | 7 ++-- src/ia32/stub-cache-ia32.cc | 66 ++++++++++++++++++------------ src/x64/code-stubs-x64.cc | 2 +- src/x64/macro-assembler-x64.cc | 37 +++++++++++------ src/x64/macro-assembler-x64.h | 7 ++-- src/x64/stub-cache-x64.cc | 86 +++++++++++++++++++++++----------------- 14 files changed, 230 insertions(+), 137 deletions(-) diff --git a/include/v8.h b/include/v8.h index dceebeb..92bfa45 100644 --- a/include/v8.h +++ b/include/v8.h @@ -2364,7 +2364,7 @@ class FunctionCallbackInfo { V8_INLINE Isolate* GetIsolate() const; V8_INLINE ReturnValue GetReturnValue() const; // This shouldn't be public, but the arm compiler needs it. - static const int kArgsLength = 6; + static const int kArgsLength = 7; protected: friend class internal::FunctionCallbackArguments; @@ -2375,6 +2375,7 @@ class FunctionCallbackInfo { static const int kDataIndex = -3; static const int kCalleeIndex = -4; static const int kHolderIndex = -5; + static const int kContextSaveIndex = -6; V8_INLINE FunctionCallbackInfo(internal::Object** implicit_args, internal::Object** values, diff --git a/src/arguments.h b/src/arguments.h index c1db98b..f291816 100644 --- a/src/arguments.h +++ b/src/arguments.h @@ -237,6 +237,7 @@ class FunctionCallbackArguments typedef FunctionCallbackInfo T; typedef CustomArguments Super; static const int kArgsLength = T::kArgsLength; + static const int kHolderIndex = T::kHolderIndex; FunctionCallbackArguments(internal::Isolate* isolate, internal::Object* data, @@ -253,6 +254,7 @@ class FunctionCallbackArguments values[T::kDataIndex] = data; values[T::kCalleeIndex] = callee; values[T::kHolderIndex] = holder; + values[T::kContextSaveIndex] = isolate->heap()->the_hole_value(); values[T::kIsolateIndex] = reinterpret_cast(isolate); // Here the hole is set as default value. // It cannot escape into js as it's remove in Call below. diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 39b2dc5..7ec7df9 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -2842,7 +2842,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, // sp: stack pointer // fp: frame pointer // Callee-saved register r4 still holds argc. - __ LeaveExitFrame(save_doubles_, r4); + __ LeaveExitFrame(save_doubles_, r4, true); __ mov(pc, lr); // check if we should retry or throw exception @@ -4071,7 +4071,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { DirectCEntryStub stub; stub.GenerateCall(masm, r7); - __ LeaveExitFrame(false, no_reg); + __ LeaveExitFrame(false, no_reg, true); // r0: result // subject: subject string (callee saved) diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 7df7857..07900d3 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -1020,7 +1020,8 @@ int MacroAssembler::ActivationFrameAlignment() { void MacroAssembler::LeaveExitFrame(bool save_doubles, - Register argument_count) { + Register argument_count, + bool restore_context) { // Optionally restore all double registers. if (save_doubles) { // Calculate the stack location of the saved doubles and restore them. @@ -1035,10 +1036,14 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles, mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); str(r3, MemOperand(ip)); + // Restore current context from top and clear it in debug mode. - mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); - ldr(cp, MemOperand(ip)); + if (restore_context) { + mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); + ldr(cp, MemOperand(ip)); + } #ifdef DEBUG + mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); str(r3, MemOperand(ip)); #endif @@ -2280,12 +2285,14 @@ static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { } -void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, - Address function_address, - ExternalReference thunk_ref, - Register thunk_last_arg, - int stack_space, - int return_value_offset) { +void MacroAssembler::CallApiFunctionAndReturn( + ExternalReference function, + Address function_address, + ExternalReference thunk_ref, + Register thunk_last_arg, + int stack_space, + MemOperand return_value_operand, + MemOperand* context_restore_operand) { ExternalReference next_address = ExternalReference::handle_scope_next_address(isolate()); const int kNextOffset = 0; @@ -2349,12 +2356,13 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, } Label promote_scheduled_exception; + Label exception_handled; Label delete_allocated_handles; Label leave_exit_frame; Label return_value_loaded; // load value from ReturnValue - ldr(r0, MemOperand(fp, return_value_offset*kPointerSize)); + ldr(r0, return_value_operand); bind(&return_value_loaded); // No more valid handles (the result handle was the last one). Restore // previous handle scope. @@ -2377,17 +2385,22 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, ldr(r5, MemOperand(ip)); cmp(r4, r5); b(ne, &promote_scheduled_exception); + bind(&exception_handled); + bool restore_context = context_restore_operand != NULL; + if (restore_context) { + ldr(cp, *context_restore_operand); + } // LeaveExitFrame expects unwind space to be in a register. mov(r4, Operand(stack_space)); - LeaveExitFrame(false, r4); + LeaveExitFrame(false, r4, !restore_context); mov(pc, lr); bind(&promote_scheduled_exception); - TailCallExternalReference( + CallExternalReference( ExternalReference(Runtime::kPromoteScheduledException, isolate()), - 0, - 1); + 0); + jmp(&exception_handled); // HandleScope limit has changed. Delete allocated extensions. bind(&delete_allocated_handles); diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 9abd5a0..0a7b53b 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -541,7 +541,9 @@ class MacroAssembler: public Assembler { // Leave the current exit frame. Expects the return value in r0. // Expect the number of values, pushed prior to the exit frame, to // remove in a register (or no_reg, if there is nothing to remove). - void LeaveExitFrame(bool save_doubles, Register argument_count); + void LeaveExitFrame(bool save_doubles, + Register argument_count, + bool restore_context); // Get the actual activation frame alignment for target environment. static int ActivationFrameAlignment(); @@ -1111,7 +1113,8 @@ class MacroAssembler: public Assembler { ExternalReference thunk_ref, Register thunk_last_arg, int stack_space, - int return_value_offset_from_fp); + MemOperand return_value_operand, + MemOperand* context_restore_operand); // Jump to a runtime routine. void JumpToExternalReference(const ExternalReference& builtin); diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 681299e..567eb63 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -839,23 +839,28 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm) { static void GenerateFastApiDirectCall(MacroAssembler* masm, const CallOptimization& optimization, - int argc) { + int argc, + bool restore_context) { // ----------- S t a t e ------------- - // -- sp[0] : holder (set by CheckPrototypes) - // -- sp[4] : callee JS function - // -- sp[8] : call data - // -- sp[12] : isolate - // -- sp[16] : ReturnValue default value - // -- sp[20] : ReturnValue - // -- sp[24] : last JS argument + // -- sp[0] : context + // -- sp[4] : holder (set by CheckPrototypes) + // -- sp[8] : callee JS function + // -- sp[12] : call data + // -- sp[16] : isolate + // -- sp[20] : ReturnValue default value + // -- sp[24] : ReturnValue + // -- sp[28] : last JS argument // -- ... - // -- sp[(argc + 5) * 4] : first JS argument - // -- sp[(argc + 6) * 4] : receiver + // -- sp[(argc + 6) * 4] : first JS argument + // -- sp[(argc + 7) * 4] : receiver // ----------------------------------- + // Save calling context. + __ str(cp, MemOperand(sp)); // Get the function and setup the context. Handle function = optimization.constant_function(); __ LoadHeapObject(r5, function); __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset)); + __ str(r5, MemOperand(sp, 2 * kPointerSize)); // Pass the additional arguments. Handle api_call_info = optimization.api_call_info(); @@ -866,15 +871,18 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, } else { __ Move(r6, call_data); } + // Store call data. + __ str(r6, MemOperand(sp, 3 * kPointerSize)); + // Store isolate. __ mov(r7, Operand(ExternalReference::isolate_address(masm->isolate()))); - // Store JS function, call data, isolate ReturnValue default and ReturnValue. - __ stm(ib, sp, r5.bit() | r6.bit() | r7.bit()); + __ str(r7, MemOperand(sp, 4 * kPointerSize)); + // Store ReturnValue default and ReturnValue. __ LoadRoot(r5, Heap::kUndefinedValueRootIndex); - __ str(r5, MemOperand(sp, 4 * kPointerSize)); __ str(r5, MemOperand(sp, 5 * kPointerSize)); + __ str(r5, MemOperand(sp, 6 * kPointerSize)); // Prepare arguments. - __ add(r2, sp, Operand(5 * kPointerSize)); + __ add(r2, sp, Operand((kFastApiCallArguments - 1) * kPointerSize)); // Allocate the v8::Arguments structure in the arguments' space since // it's not controlled by GC. @@ -912,12 +920,18 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, masm->isolate()); AllowExternalCallThatCantCauseGC scope(masm); + MemOperand context_restore_operand( + fp, 2 * kPointerSize); + MemOperand return_value_operand( + fp, (kFastApiCallArguments + 1) * kPointerSize); __ CallApiFunctionAndReturn(ref, function_address, thunk_ref, r1, kStackUnwindSpace, - kFastApiCallArguments + 1); + return_value_operand, + restore_context ? + &context_restore_operand : NULL); } @@ -932,10 +946,12 @@ static void GenerateFastApiCall(MacroAssembler* masm, ASSERT(!receiver.is(scratch)); const int stack_space = kFastApiCallArguments + argc + 1; + const int kHolderIndex = kFastApiCallArguments + + FunctionCallbackArguments::kHolderIndex - 1; // Assign stack space for the call arguments. __ sub(sp, sp, Operand(stack_space * kPointerSize)); // Write holder to stack frame. - __ str(receiver, MemOperand(sp, 0)); + __ str(receiver, MemOperand(sp, kHolderIndex * kPointerSize)); // Write receiver to stack frame. int index = stack_space - 1; __ str(receiver, MemOperand(sp, index * kPointerSize)); @@ -946,7 +962,7 @@ static void GenerateFastApiCall(MacroAssembler* masm, __ str(receiver, MemOperand(sp, index-- * kPointerSize)); } - GenerateFastApiDirectCall(masm, optimization, argc); + GenerateFastApiDirectCall(masm, optimization, argc, true); } @@ -1060,7 +1076,8 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Invoke function. if (can_do_fast_api_call) { - GenerateFastApiDirectCall(masm, optimization, arguments_.immediate()); + GenerateFastApiDirectCall( + masm, optimization, arguments_.immediate(), false); } else { CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) ? CALL_AS_FUNCTION @@ -1184,6 +1201,8 @@ Register StubCompiler::CheckPrototypes(Handle object, int save_at_depth, Label* miss, PrototypeCheckType check) { + const int kHolderIndex = kFastApiCallArguments + + FunctionCallbackArguments::kHolderIndex - 1; // Make sure that the type feedback oracle harvests the receiver map. // TODO(svenpanne) Remove this hack when all ICs are reworked. __ mov(scratch1, Operand(Handle(object->map()))); @@ -1199,7 +1218,7 @@ Register StubCompiler::CheckPrototypes(Handle object, int depth = 0; if (save_at_depth == depth) { - __ str(reg, MemOperand(sp)); + __ str(reg, MemOperand(sp, kHolderIndex * kPointerSize)); } // Check the maps in the prototype chain. @@ -1258,7 +1277,7 @@ Register StubCompiler::CheckPrototypes(Handle object, } if (save_at_depth == depth) { - __ str(reg, MemOperand(sp)); + __ str(reg, MemOperand(sp, kHolderIndex * kPointerSize)); } // Go to the next object in the prototype chain. @@ -1453,7 +1472,7 @@ void BaseLoadStubCompiler::GenerateLoadCallback( __ str(scratch2(), MemOperand(sp, 1 * kPointerSize)); __ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo& - const int kStackUnwindSpace = kFastApiCallArguments + 1; + const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1; Address getter_address = v8::ToCData
(callback->getter()); ApiFunction fun(getter_address); @@ -1471,7 +1490,8 @@ void BaseLoadStubCompiler::GenerateLoadCallback( thunk_ref, r2, kStackUnwindSpace, - 6); + MemOperand(fp, 6 * kPointerSize), + NULL); } @@ -2535,7 +2555,7 @@ Handle CallStubCompiler::CompileFastApiCall( CheckPrototypes(Handle::cast(object), r1, holder, r0, r3, r4, name, depth, &miss); - GenerateFastApiDirectCall(masm(), optimization, argc); + GenerateFastApiDirectCall(masm(), optimization, argc, false); __ bind(&miss); FreeSpaceForFastApiCall(masm()); diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 3ea749f..c113dfb 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -3494,7 +3494,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ call(edx); // Drop arguments and come back to JS mode. - __ LeaveApiExitFrame(); + __ LeaveApiExitFrame(true); // Check the result. Label success; diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index d8a475c..f514f29 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -1115,14 +1115,16 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) { // Push the return address to get ready to return. push(ecx); - LeaveExitFrameEpilogue(); + LeaveExitFrameEpilogue(true); } -void MacroAssembler::LeaveExitFrameEpilogue() { +void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) { // Restore current context from top and clear it in debug mode. ExternalReference context_address(Isolate::kContextAddress, isolate()); - mov(esi, Operand::StaticVariable(context_address)); + if (restore_context) { + mov(esi, Operand::StaticVariable(context_address)); + } #ifdef DEBUG mov(Operand::StaticVariable(context_address), Immediate(0)); #endif @@ -1134,11 +1136,11 @@ void MacroAssembler::LeaveExitFrameEpilogue() { } -void MacroAssembler::LeaveApiExitFrame() { +void MacroAssembler::LeaveApiExitFrame(bool restore_context) { mov(esp, ebp); pop(ebp); - LeaveExitFrameEpilogue(); + LeaveExitFrameEpilogue(restore_context); } @@ -2227,11 +2229,13 @@ void MacroAssembler::PrepareCallApiFunction(int argc) { } -void MacroAssembler::CallApiFunctionAndReturn(Address function_address, - Address thunk_address, - Operand thunk_last_arg, - int stack_space, - int return_value_offset) { +void MacroAssembler::CallApiFunctionAndReturn( + Address function_address, + Address thunk_address, + Operand thunk_last_arg, + int stack_space, + Operand return_value_operand, + Operand* context_restore_operand) { ExternalReference next_address = ExternalReference::handle_scope_next_address(isolate()); ExternalReference limit_address = @@ -2287,9 +2291,10 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, Label prologue; // Load the value from ReturnValue - mov(eax, Operand(ebp, return_value_offset * kPointerSize)); + mov(eax, return_value_operand); Label promote_scheduled_exception; + Label exception_handled; Label delete_allocated_handles; Label leave_exit_frame; @@ -2309,6 +2314,7 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, cmp(Operand::StaticVariable(scheduled_exception_address), Immediate(isolate()->factory()->the_hole_value())); j(not_equal, &promote_scheduled_exception); + bind(&exception_handled); #if ENABLE_EXTRA_CHECKS // Check if the function returned a valid JavaScript value. @@ -2345,11 +2351,16 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, bind(&ok); #endif - LeaveApiExitFrame(); + bool restore_context = context_restore_operand != NULL; + if (restore_context) { + mov(esi, *context_restore_operand); + } + LeaveApiExitFrame(!restore_context); ret(stack_space * kPointerSize); bind(&promote_scheduled_exception); - TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); + CallRuntime(Runtime::kPromoteScheduledException, 0); + jmp(&exception_handled); // HandleScope limit has changed. Delete allocated extensions. ExternalReference delete_extensions = diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index d813692..adda9fe 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -240,7 +240,7 @@ class MacroAssembler: public Assembler { // Leave the current exit frame. Expects the return value in // register eax (untouched). - void LeaveApiExitFrame(); + void LeaveApiExitFrame(bool restore_context); // Find the function context up the context chain. void LoadContext(Register dst, int context_chain_length); @@ -813,7 +813,8 @@ class MacroAssembler: public Assembler { Address thunk_address, Operand thunk_last_arg, int stack_space, - int return_value_offset_from_ebp); + Operand return_value_operand, + Operand* context_restore_operand); // Jump to a runtime routine. void JumpToExternalReference(const ExternalReference& ext); @@ -963,7 +964,7 @@ class MacroAssembler: public Assembler { void EnterExitFramePrologue(); void EnterExitFrameEpilogue(int argc, bool save_doubles); - void LeaveExitFrameEpilogue(); + void LeaveExitFrameEpilogue(bool restore_context); // Allocation support helpers. void LoadAllocationTopHelper(Register result, diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 89ea6be..d339da9 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -458,48 +458,54 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { // Generates call to API function. static void GenerateFastApiCall(MacroAssembler* masm, const CallOptimization& optimization, - int argc) { + int argc, + bool restore_context) { // ----------- S t a t e ------------- // -- esp[0] : return address - // -- esp[4] : object passing the type check + // -- esp[4] : context + // -- esp[8] : object passing the type check // (last fast api call extra argument, // set by CheckPrototypes) - // -- esp[8] : api function + // -- esp[12] : api function // (first fast api call extra argument) - // -- esp[12] : api call data - // -- esp[16] : isolate - // -- esp[20] : ReturnValue default value - // -- esp[24] : ReturnValue - // -- esp[28] : last argument + // -- esp[16] : api call data + // -- esp[20] : isolate + // -- esp[24] : ReturnValue default value + // -- esp[28] : ReturnValue + // -- esp[32] : last argument // -- ... - // -- esp[(argc + 6) * 4] : first argument - // -- esp[(argc + 7) * 4] : receiver + // -- esp[(argc + 7) * 4] : first argument + // -- esp[(argc + 8) * 4] : receiver // ----------------------------------- + + // Save calling context. + __ mov(Operand(esp, kPointerSize), esi); + // Get the function and setup the context. Handle function = optimization.constant_function(); __ LoadHeapObject(edi, function); __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); // Pass the additional arguments. - __ mov(Operand(esp, 2 * kPointerSize), edi); + __ mov(Operand(esp, 3 * kPointerSize), edi); Handle api_call_info = optimization.api_call_info(); Handle call_data(api_call_info->data(), masm->isolate()); if (masm->isolate()->heap()->InNewSpace(*call_data)) { __ mov(ecx, api_call_info); __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); - __ mov(Operand(esp, 3 * kPointerSize), ebx); + __ mov(Operand(esp, 4 * kPointerSize), ebx); } else { - __ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data)); + __ mov(Operand(esp, 4 * kPointerSize), Immediate(call_data)); } - __ mov(Operand(esp, 4 * kPointerSize), - Immediate(reinterpret_cast(masm->isolate()))); __ mov(Operand(esp, 5 * kPointerSize), - masm->isolate()->factory()->undefined_value()); + Immediate(reinterpret_cast(masm->isolate()))); __ mov(Operand(esp, 6 * kPointerSize), masm->isolate()->factory()->undefined_value()); + __ mov(Operand(esp, 7 * kPointerSize), + masm->isolate()->factory()->undefined_value()); // Prepare arguments. - STATIC_ASSERT(kFastApiCallArguments == 6); + STATIC_ASSERT(kFastApiCallArguments == 7); __ lea(eax, Operand(esp, kFastApiCallArguments * kPointerSize)); @@ -533,11 +539,16 @@ static void GenerateFastApiCall(MacroAssembler* masm, Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback); + Operand context_restore_operand(ebp, 2 * kPointerSize); + Operand return_value_operand( + ebp, (kFastApiCallArguments + 1) * kPointerSize); __ CallApiFunctionAndReturn(function_address, thunk_address, ApiParameterOperand(1), argc + kFastApiCallArguments + 1, - kFastApiCallArguments + 1); + return_value_operand, + restore_context ? + &context_restore_operand : NULL); } @@ -552,6 +563,8 @@ static void GenerateFastApiCall(MacroAssembler* masm, ASSERT(!receiver.is(scratch)); const int stack_space = kFastApiCallArguments + argc + 1; + const int kHolderIndex = kFastApiCallArguments + + FunctionCallbackArguments::kHolderIndex; // Copy return value. __ mov(scratch, Operand(esp, 0)); // Assign stack space for the call arguments. @@ -559,7 +572,7 @@ static void GenerateFastApiCall(MacroAssembler* masm, // Move the return address on top of the stack. __ mov(Operand(esp, 0), scratch); // Write holder to stack frame. - __ mov(Operand(esp, 1 * kPointerSize), receiver); + __ mov(Operand(esp, kHolderIndex * kPointerSize), receiver); // Write receiver to stack frame. int index = stack_space; __ mov(Operand(esp, index-- * kPointerSize), receiver); @@ -570,7 +583,7 @@ static void GenerateFastApiCall(MacroAssembler* masm, __ mov(Operand(esp, index-- * kPointerSize), values[i]); } - GenerateFastApiCall(masm, optimization, argc); + GenerateFastApiCall(masm, optimization, argc, true); } @@ -684,7 +697,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Invoke function. if (can_do_fast_api_call) { - GenerateFastApiCall(masm, optimization, arguments_.immediate()); + GenerateFastApiCall(masm, optimization, arguments_.immediate(), false); } else { CallKind call_kind = CallICBase::Contextual::decode(extra_state_) ? CALL_AS_FUNCTION @@ -1156,6 +1169,8 @@ Register StubCompiler::CheckPrototypes(Handle object, int save_at_depth, Label* miss, PrototypeCheckType check) { + const int kHolderIndex = kFastApiCallArguments + + FunctionCallbackArguments::kHolderIndex; // Make sure that the type feedback oracle harvests the receiver map. // TODO(svenpanne) Remove this hack when all ICs are reworked. __ mov(scratch1, Handle(object->map())); @@ -1172,7 +1187,7 @@ Register StubCompiler::CheckPrototypes(Handle object, int depth = 0; if (save_at_depth == depth) { - __ mov(Operand(esp, kPointerSize), reg); + __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); } // Traverse the prototype chain and check the maps in the prototype chain for @@ -1233,7 +1248,7 @@ Register StubCompiler::CheckPrototypes(Handle object, } if (save_at_depth == depth) { - __ mov(Operand(esp, kPointerSize), reg); + __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); } // Go to the next object in the prototype chain. @@ -1456,7 +1471,8 @@ void BaseLoadStubCompiler::GenerateLoadCallback( thunk_address, ApiParameterOperand(2), kStackSpace, - 7); + Operand(ebp, 7 * kPointerSize), + NULL); } @@ -2619,7 +2635,7 @@ Handle CallStubCompiler::CompileFastApiCall( // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains // duplicate of return address and will be overwritten. - GenerateFastApiCall(masm(), optimization, argc); + GenerateFastApiCall(masm(), optimization, argc, false); __ bind(&miss); __ add(esp, Immediate(kFastApiCallArguments * kPointerSize)); diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index d1130ad..a201624 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -2648,7 +2648,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); __ call(r11); - __ LeaveApiExitFrame(); + __ LeaveApiExitFrame(true); // Check the result. Label success; diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index fa8cf18..4ff3791 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -691,13 +691,16 @@ void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) { } -void MacroAssembler::CallApiFunctionAndReturn(Address function_address, - Address thunk_address, - Register thunk_last_arg, - int stack_space, - int return_value_offset) { +void MacroAssembler::CallApiFunctionAndReturn( + Address function_address, + Address thunk_address, + Register thunk_last_arg, + int stack_space, + Operand return_value_operand, + Operand* context_restore_operand) { Label prologue; Label promote_scheduled_exception; + Label exception_handled; Label delete_allocated_handles; Label leave_exit_frame; Label write_back; @@ -768,7 +771,7 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, } // Load the value from ReturnValue - movq(rax, Operand(rbp, return_value_offset * kPointerSize)); + movq(rax, return_value_operand); bind(&prologue); // No more valid handles (the result handle was the last one). Restore @@ -783,6 +786,7 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, movq(rsi, scheduled_exception_address); Cmp(Operand(rsi, 0), factory->the_hole_value()); j(not_equal, &promote_scheduled_exception); + bind(&exception_handled); #if ENABLE_EXTRA_CHECKS // Check if the function returned a valid JavaScript value. @@ -819,11 +823,16 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, bind(&ok); #endif - LeaveApiExitFrame(); + bool restore_context = context_restore_operand != NULL; + if (restore_context) { + movq(rsi, *context_restore_operand); + } + LeaveApiExitFrame(!restore_context); ret(stack_space * kPointerSize); bind(&promote_scheduled_exception); - TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); + CallRuntime(Runtime::kPromoteScheduledException, 0); + jmp(&exception_handled); // HandleScope limit has changed. Delete allocated extensions. bind(&delete_allocated_handles); @@ -3695,23 +3704,25 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) { PushReturnAddressFrom(rcx); - LeaveExitFrameEpilogue(); + LeaveExitFrameEpilogue(true); } -void MacroAssembler::LeaveApiExitFrame() { +void MacroAssembler::LeaveApiExitFrame(bool restore_context) { movq(rsp, rbp); pop(rbp); - LeaveExitFrameEpilogue(); + LeaveExitFrameEpilogue(restore_context); } -void MacroAssembler::LeaveExitFrameEpilogue() { +void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) { // Restore current context from top and clear it in debug mode. ExternalReference context_address(Isolate::kContextAddress, isolate()); Operand context_operand = ExternalOperand(context_address); - movq(rsi, context_operand); + if (restore_context) { + movq(rsi, context_operand); + } #ifdef DEBUG movq(context_operand, Immediate(0)); #endif diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index a1b04d5..9f8dafc 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -302,7 +302,7 @@ class MacroAssembler: public Assembler { // Leave the current exit frame. Expects/provides the return value in // register rax (untouched). - void LeaveApiExitFrame(); + void LeaveApiExitFrame(bool restore_context); // Push and pop the registers that can hold pointers. void PushSafepointRegisters() { Pushad(); } @@ -1280,7 +1280,8 @@ class MacroAssembler: public Assembler { Address thunk_address, Register thunk_last_arg, int stack_space, - int return_value_offset_from_rbp); + Operand return_value_operand, + Operand* context_restore_operand); // Before calling a C-function from generated code, align arguments on stack. // After aligning the frame, arguments must be stored in rsp[0], rsp[8], @@ -1436,7 +1437,7 @@ class MacroAssembler: public Assembler { // accessible via StackSpaceOperand. void EnterExitFrameEpilogue(int arg_stack_space, bool save_doubles); - void LeaveExitFrameEpilogue(); + void LeaveExitFrameEpilogue(bool restore_context); // Allocation support helpers. // Loads the top of new-space into the result register. diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 6cd2487..af8e55f 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -443,65 +443,61 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { // Generates call to API function. static void GenerateFastApiCall(MacroAssembler* masm, const CallOptimization& optimization, - int argc) { + int argc, + bool restore_context) { // ----------- S t a t e ------------- // -- rsp[0] : return address - // -- rsp[8] : object passing the type check + // -- rsp[8] : context save + // -- rsp[16] : object passing the type check // (last fast api call extra argument, // set by CheckPrototypes) - // -- rsp[16] : api function + // -- rsp[24] : api function // (first fast api call extra argument) - // -- rsp[24] : api call data - // -- rsp[32] : isolate - // -- rsp[40] : ReturnValue default value - // -- rsp[48] : ReturnValue + // -- rsp[32] : api call data + // -- rsp[40] : isolate + // -- rsp[48] : ReturnValue default value + // -- rsp[56] : ReturnValue // - // -- rsp[56] : last argument + // -- rsp[64] : last argument // -- ... - // -- rsp[(argc + 6) * 8] : first argument - // -- rsp[(argc + 7) * 8] : receiver + // -- rsp[(argc + 7) * 8] : first argument + // -- rsp[(argc + 8) * 8] : receiver // ----------------------------------- + int api_call_argc = argc + kFastApiCallArguments; + StackArgumentsAccessor args(rsp, api_call_argc); + + // Save calling context. + __ movq(args.GetArgumentOperand(api_call_argc), rsi); + // Get the function and setup the context. Handle function = optimization.constant_function(); __ LoadHeapObject(rdi, function); __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); - - int api_call_argc = argc + kFastApiCallArguments; - StackArgumentsAccessor args(rsp, api_call_argc); - // Pass the additional arguments. - __ movq(args.GetArgumentOperand(api_call_argc - 1), rdi); + __ movq(args.GetArgumentOperand(api_call_argc - 2), rdi); Handle api_call_info = optimization.api_call_info(); Handle call_data(api_call_info->data(), masm->isolate()); if (masm->isolate()->heap()->InNewSpace(*call_data)) { __ Move(rcx, api_call_info); __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset)); - __ movq(args.GetArgumentOperand(api_call_argc - 2), rbx); + __ movq(args.GetArgumentOperand(api_call_argc - 3), rbx); } else { - __ Move(args.GetArgumentOperand(api_call_argc - 2), call_data); + __ Move(args.GetArgumentOperand(api_call_argc - 3), call_data); } __ movq(kScratchRegister, ExternalReference::isolate_address(masm->isolate())); - __ movq(args.GetArgumentOperand(api_call_argc - 3), kScratchRegister); - __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); __ movq(args.GetArgumentOperand(api_call_argc - 4), kScratchRegister); + __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); __ movq(args.GetArgumentOperand(api_call_argc - 5), kScratchRegister); + __ movq(args.GetArgumentOperand(api_call_argc - 6), kScratchRegister); // Prepare arguments. - STATIC_ASSERT(kFastApiCallArguments == 6); + STATIC_ASSERT(kFastApiCallArguments == 7); __ lea(rbx, Operand(rsp, kFastApiCallArguments * kPointerSize)); // Function address is a foreign pointer outside V8's heap. Address function_address = v8::ToCData
(api_call_info->callback()); -#if defined(__MINGW64__) || defined(_WIN64) - Register arguments_arg = rcx; - Register callback_arg = rdx; -#else - Register arguments_arg = rdi; - Register callback_arg = rsi; -#endif - // Allocate the v8::Arguments structure in the arguments' space since // it's not controlled by GC. const int kApiStackSpace = 4; @@ -515,16 +511,29 @@ static void GenerateFastApiCall(MacroAssembler* masm, // v8::Arguments::is_construct_call_. __ Set(StackSpaceOperand(3), 0); +#if defined(__MINGW64__) || defined(_WIN64) + Register arguments_arg = rcx; + Register callback_arg = rdx; +#else + Register arguments_arg = rdi; + Register callback_arg = rsi; +#endif + // v8::InvocationCallback's argument. __ lea(arguments_arg, StackSpaceOperand(0)); Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback); + Operand context_restore_operand(rbp, 2 * kPointerSize); + Operand return_value_operand( + rbp, (kFastApiCallArguments + 1) * kPointerSize); __ CallApiFunctionAndReturn(function_address, thunk_address, callback_arg, api_call_argc + 1, - kFastApiCallArguments + 1); + return_value_operand, + restore_context ? + &context_restore_operand : NULL); } @@ -539,6 +548,8 @@ static void GenerateFastApiCall(MacroAssembler* masm, ASSERT(!receiver.is(scratch)); const int stack_space = kFastApiCallArguments + argc + 1; + const int kHolderIndex = kFastApiCallArguments + + FunctionCallbackArguments::kHolderIndex; // Copy return value. __ movq(scratch, Operand(rsp, 0)); // Assign stack space for the call arguments. @@ -546,7 +557,7 @@ static void GenerateFastApiCall(MacroAssembler* masm, // Move the return address on top of the stack. __ movq(Operand(rsp, 0), scratch); // Write holder to stack frame. - __ movq(Operand(rsp, 1 * kPointerSize), receiver); + __ movq(Operand(rsp, kHolderIndex * kPointerSize), receiver); // Write receiver to stack frame. int index = stack_space; __ movq(Operand(rsp, index-- * kPointerSize), receiver); @@ -557,7 +568,7 @@ static void GenerateFastApiCall(MacroAssembler* masm, __ movq(Operand(rsp, index-- * kPointerSize), values[i]); } - GenerateFastApiCall(masm, optimization, argc); + GenerateFastApiCall(masm, optimization, argc, true); } @@ -671,7 +682,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Invoke function. if (can_do_fast_api_call) { - GenerateFastApiCall(masm, optimization, arguments_.immediate()); + GenerateFastApiCall(masm, optimization, arguments_.immediate(), false); } else { CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_) ? CALL_AS_FUNCTION @@ -1087,6 +1098,8 @@ Register StubCompiler::CheckPrototypes(Handle object, int save_at_depth, Label* miss, PrototypeCheckType check) { + const int kHolderIndex = kFastApiCallArguments + + FunctionCallbackArguments::kHolderIndex; // Make sure that the type feedback oracle harvests the receiver map. // TODO(svenpanne) Remove this hack when all ICs are reworked. __ Move(scratch1, Handle(object->map())); @@ -1104,7 +1117,7 @@ Register StubCompiler::CheckPrototypes(Handle object, int depth = 0; if (save_at_depth == depth) { - __ movq(Operand(rsp, kPCOnStackSize), object_reg); + __ movq(Operand(rsp, kHolderIndex * kPointerSize), object_reg); } // Check the maps in the prototype chain. @@ -1164,7 +1177,7 @@ Register StubCompiler::CheckPrototypes(Handle object, } if (save_at_depth == depth) { - __ movq(Operand(rsp, kPCOnStackSize), reg); + __ movq(Operand(rsp, kHolderIndex * kPointerSize), reg); } // Go to the next object in the prototype chain. @@ -1386,7 +1399,8 @@ void BaseLoadStubCompiler::GenerateLoadCallback( thunk_address, getter_arg, kStackSpace, - 6); + Operand(rbp, 6 * kPointerSize), + NULL); } @@ -2504,7 +2518,7 @@ Handle CallStubCompiler::CompileFastApiCall( StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize)); __ movq(StackOperandForReturnAddress(0), rax); - GenerateFastApiCall(masm(), optimization, argc); + GenerateFastApiCall(masm(), optimization, argc, false); __ bind(&miss); __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); -- 2.7.4