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:
parent
29d0f52a3c
commit
0020146f24
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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 =
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user