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
This commit is contained in:
dcarney@chromium.org 2013-09-17 07:19:50 +00:00
parent 29d0f52a3c
commit 0020146f24
14 changed files with 230 additions and 137 deletions

View File

@ -2364,7 +2364,7 @@ class FunctionCallbackInfo {
V8_INLINE Isolate* GetIsolate() const;
V8_INLINE ReturnValue<T> 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,

View File

@ -237,6 +237,7 @@ class FunctionCallbackArguments
typedef FunctionCallbackInfo<Value> T;
typedef CustomArguments<T> 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<internal::Object*>(isolate);
// Here the hole is set as default value.
// It cannot escape into js as it's remove in Call below.

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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<JSFunction> function = optimization.constant_function();
__ LoadHeapObject(r5, function);
__ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset));
__ str(r5, MemOperand(sp, 2 * kPointerSize));
// Pass the additional arguments.
Handle<CallHandlerInfo> 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<JSObject> 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<Map>(object->map())));
@ -1199,7 +1218,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> 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<JSObject> 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<Address>(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<Code> CallStubCompiler::CompileFastApiCall(
CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4, name,
depth, &miss);
GenerateFastApiDirectCall(masm(), optimization, argc);
GenerateFastApiDirectCall(masm(), optimization, argc, false);
__ bind(&miss);
FreeSpaceForFastApiCall(masm());

View File

@ -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;

View File

@ -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 =

View File

@ -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,

View File

@ -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<JSFunction> 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<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> 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<int>(masm->isolate())));
__ mov(Operand(esp, 5 * kPointerSize),
masm->isolate()->factory()->undefined_value());
Immediate(reinterpret_cast<int>(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<JSObject> 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<Map>(object->map()));
@ -1172,7 +1187,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> 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<JSObject> 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<Code> 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));

View File

@ -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;

View File

@ -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

View File

@ -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.

View File

@ -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<JSFunction> 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<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> 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<Address>(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<JSObject> 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<Map>(object->map()));
@ -1104,7 +1117,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> 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<JSObject> 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<Code> 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));