Commit d1a10c6e authored by dcarney@chromium.org's avatar dcarney@chromium.org

stub fast api calls

R=verwaest@chromium.org, vervaest@chromium.org

BUG=

Review URL: https://codereview.chromium.org/140613004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18847 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 89ffd305
......@@ -5515,6 +5515,120 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
}
void CallApiFunctionStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : callee
// -- r4 : call_data
// -- r2 : holder
// -- r3 : api_function_address
// -- r1 : thunk_arg
// -- cp : context
// --
// -- esp[0] : last argument
// -- ...
// -- esp[(argc - 1)* 4] : first argument
// -- esp[argc * 4] : receiver
// -----------------------------------
Register callee = r0;
Register call_data = r4;
Register holder = r2;
Register api_function_address = r3;
Register thunk_arg = r1;
Register context = cp;
int argc = ArgumentBits::decode(bit_field_);
bool restore_context = RestoreContextBits::decode(bit_field_);
bool call_data_undefined = CallDataUndefinedBits::decode(bit_field_);
typedef FunctionCallbackArguments FCA;
STATIC_ASSERT(FCA::kContextSaveIndex == 6);
STATIC_ASSERT(FCA::kCalleeIndex == 5);
STATIC_ASSERT(FCA::kDataIndex == 4);
STATIC_ASSERT(FCA::kReturnValueOffset == 3);
STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
STATIC_ASSERT(FCA::kIsolateIndex == 1);
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kArgsLength == 7);
Isolate* isolate = masm->isolate();
// context save
__ push(context);
// load context from callee
__ ldr(context, FieldMemOperand(callee, JSFunction::kContextOffset));
// callee
__ push(callee);
// call data
__ push(call_data);
Register scratch = call_data;
if (!call_data_undefined) {
__ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
}
// return value
__ push(scratch);
// return value default
__ push(scratch);
// isolate
__ mov(scratch,
Operand(ExternalReference::isolate_address(isolate)));
__ push(scratch);
// holder
__ push(holder);
// Prepare arguments.
__ mov(scratch, sp);
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
const int kApiStackSpace = 4;
FrameScope frame_scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace);
ASSERT(!thunk_arg.is(r0) && !api_function_address.is(r0) && !scratch.is(r0));
// r0 = FunctionCallbackInfo&
// Arguments is after the return address.
__ add(r0, sp, Operand(1 * kPointerSize));
// FunctionCallbackInfo::implicit_args_
__ str(scratch, MemOperand(r0, 0 * kPointerSize));
// FunctionCallbackInfo::values_
__ add(ip, scratch, Operand((FCA::kArgsLength - 1 + argc) * kPointerSize));
__ str(ip, MemOperand(r0, 1 * kPointerSize));
// FunctionCallbackInfo::length_ = argc
__ mov(ip, Operand(argc));
__ str(ip, MemOperand(r0, 2 * kPointerSize));
// FunctionCallbackInfo::is_construct_call = 0
__ mov(ip, Operand::Zero());
__ str(ip, MemOperand(r0, 3 * kPointerSize));
const int kStackUnwindSpace = argc + FCA::kArgsLength + 1;
Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
ExternalReference::Type thunk_type = ExternalReference::PROFILING_API_CALL;
ApiFunction thunk_fun(thunk_address);
ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
masm->isolate());
AllowExternalCallThatCantCauseGC scope(masm);
MemOperand context_restore_operand(
fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
MemOperand return_value_operand(fp,
(2 + FCA::kReturnValueOffset) * kPointerSize);
__ CallApiFunctionAndReturn(api_function_address,
thunk_ref,
thunk_arg,
kStackUnwindSpace,
return_value_operand,
restore_context ?
&context_restore_operand : NULL);
}
#undef __
} } // namespace v8::internal
......
......@@ -2298,8 +2298,7 @@ static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
void MacroAssembler::CallApiFunctionAndReturn(
ExternalReference function,
Address function_address,
Register function_address,
ExternalReference thunk_ref,
Register thunk_last_arg,
int stack_space,
......@@ -2315,7 +2314,26 @@ void MacroAssembler::CallApiFunctionAndReturn(
ExternalReference::handle_scope_level_address(isolate()),
next_address);
ASSERT(!thunk_last_arg.is(r3));
ASSERT(function_address.is(r3));
ASSERT(thunk_last_arg.is(r1) || thunk_last_arg.is(r2));
Label profiler_disabled;
Label end_profiler_check;
bool* is_profiling_flag =
isolate()->cpu_profiler()->is_profiling_address();
STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
mov(r9, Operand(reinterpret_cast<int32_t>(is_profiling_flag)));
ldrb(r9, MemOperand(r9, 0));
cmp(r9, Operand(0));
b(eq, &profiler_disabled);
// Additional parameter is the address of the actual callback.
mov(r3, Operand(thunk_ref));
jmp(&end_profiler_check);
bind(&profiler_disabled);
Move(r3, function_address);
bind(&end_profiler_check);
// Allocate HandleScope in callee-save registers.
mov(r9, Operand(next_address));
......@@ -2334,25 +2352,6 @@ void MacroAssembler::CallApiFunctionAndReturn(
PopSafepointRegisters();
}
Label profiler_disabled;
Label end_profiler_check;
bool* is_profiling_flag =
isolate()->cpu_profiler()->is_profiling_address();
STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
mov(r3, Operand(reinterpret_cast<int32_t>(is_profiling_flag)));
ldrb(r3, MemOperand(r3, 0));
cmp(r3, Operand(0));
b(eq, &profiler_disabled);
// Additional parameter is the address of the actual callback.
mov(thunk_last_arg, Operand(reinterpret_cast<int32_t>(function_address)));
mov(r3, Operand(thunk_ref));
jmp(&end_profiler_check);
bind(&profiler_disabled);
mov(r3, Operand(function));
bind(&end_profiler_check);
// Native call returns to the DirectCEntry stub which redirects to the
// return address pushed on stack (could have moved after GC).
// DirectCEntry stub itself is generated early and never moves.
......
......@@ -1134,8 +1134,7 @@ class MacroAssembler: public Assembler {
// from handle and propagates exceptions. Restores context. stack_space
// - space to be unwound on exit (includes the call JS arguments space and
// the additional space allocated for the fast call).
void CallApiFunctionAndReturn(ExternalReference function,
Address function_address,
void CallApiFunctionAndReturn(Register function_address,
ExternalReference thunk_ref,
Register thunk_last_arg,
int stack_space,
......
......@@ -777,127 +777,56 @@ static void CompileCallLoadPropertyWithInterceptor(
}
static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
static void GenerateFastApiCallBody(MacroAssembler* masm,
const CallOptimization& optimization,
int argc,
Register holder,
Register scratch1,
Register scratch2,
Register scratch3,
Register holder_in,
bool restore_context) {
// ----------- S t a t e -------------
// -- sp[0] : last JS argument
// -- ...
// -- sp[(argc - 1) * 4] : first JS argument
// -- sp[argc * 4] : receiver
// -----------------------------------
ASSERT(optimization.is_simple_api_call());
typedef FunctionCallbackArguments FCA;
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kIsolateIndex == 1);
STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
STATIC_ASSERT(FCA::kReturnValueOffset == 3);
STATIC_ASSERT(FCA::kDataIndex == 4);
STATIC_ASSERT(FCA::kCalleeIndex == 5);
STATIC_ASSERT(FCA::kContextSaveIndex == 6);
STATIC_ASSERT(FCA::kArgsLength == 7);
// Abi for CallApiFunctionStub.
Register callee = r0;
Register call_data = r4;
Register holder = r2;
Register api_function_address = r3;
Register thunk_arg = r1;
ASSERT(!holder.is(cp));
// Put holder in place.
__ Move(holder, holder_in);
// Save calling context.
__ push(cp);
// Get the function and setup the context.
Isolate* isolate = masm->isolate();
Handle<JSFunction> function = optimization.constant_function();
__ Move(scratch1, function);
__ ldr(cp, FieldMemOperand(scratch1, JSFunction::kContextOffset));
__ push(scratch1);
// Construct the FunctionCallbackInfo.
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data(api_call_info->data(), masm->isolate());
Handle<Object> call_data_obj(api_call_info->data(), isolate);
// Put callee in place.
__ Move(callee, function);
bool call_data_undefined = false;
if (masm->isolate()->heap()->InNewSpace(*call_data)) {
__ Move(scratch1, api_call_info);
__ ldr(scratch1, FieldMemOperand(scratch1, CallHandlerInfo::kDataOffset));
} else if (call_data->IsUndefined()) {
// Put call_data in place.
if (isolate->heap()->InNewSpace(*call_data_obj)) {
__ Move(call_data, api_call_info);
__ ldr(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset));
} else if (call_data_obj->IsUndefined()) {
call_data_undefined = true;
__ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex);
__ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
} else {
__ Move(scratch1, call_data);
__ Move(call_data, call_data_obj);
}
// Store call data.
__ push(scratch1);
if (!call_data_undefined) {
__ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
}
// Store ReturnValue default and ReturnValue.
__ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
__ push(scratch1);
__ push(scratch1);
// Store isolate.
__ mov(scratch1,
Operand(ExternalReference::isolate_address(masm->isolate())));
__ push(scratch1);
// holder
__ push(holder);
// Prepare arguments.
__ mov(r2, sp);
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
const int kApiStackSpace = 4;
FrameScope frame_scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace);
// r0 = FunctionCallbackInfo&
// Arguments is after the return address.
__ add(r0, sp, Operand(1 * kPointerSize));
// FunctionCallbackInfo::implicit_args_
__ str(r2, MemOperand(r0, 0 * kPointerSize));
// FunctionCallbackInfo::values_
__ add(ip, r2, Operand((kFastApiCallArguments - 1 + argc) * kPointerSize));
__ str(ip, MemOperand(r0, 1 * kPointerSize));
// FunctionCallbackInfo::length_ = argc
__ mov(ip, Operand(argc));
__ str(ip, MemOperand(r0, 2 * kPointerSize));
// FunctionCallbackInfo::is_construct_call = 0
__ mov(ip, Operand::Zero());
__ str(ip, MemOperand(r0, 3 * kPointerSize));
const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
ExternalReference ref = ExternalReference(&fun,
type,
masm->isolate());
Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
ExternalReference::Type thunk_type = ExternalReference::PROFILING_API_CALL;
ApiFunction thunk_fun(thunk_address);
ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
masm->isolate());
__ mov(api_function_address, Operand(ref));
__ mov(thunk_arg, Operand(reinterpret_cast<int32_t>(function_address)));
AllowExternalCallThatCantCauseGC scope(masm);
MemOperand context_restore_operand(
fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
MemOperand return_value_operand(fp,
(2 + FCA::kReturnValueOffset) * kPointerSize);
__ CallApiFunctionAndReturn(ref,
function_address,
thunk_ref,
r1,
kStackUnwindSpace,
return_value_operand,
restore_context ?
&context_restore_operand : NULL);
// Jump to stub.
CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
__ TailCallStub(&stub);
}
......@@ -911,7 +840,7 @@ static void GenerateFastApiCall(MacroAssembler* masm,
__ IncrementCounter(counters->call_const_fast_api(), 1, r0, r1);
// Move holder to a register
Register holder_reg = r0;
Register holder_reg = r2;
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
{
......@@ -938,9 +867,6 @@ static void GenerateFastApiCall(MacroAssembler* masm,
optimization,
argc,
holder_reg,
r1,
r2,
r3,
false);
}
......@@ -961,21 +887,11 @@ static void GenerateFastApiCall(MacroAssembler* masm,
ASSERT(!scratch.is(arg));
__ push(arg);
}
Register scratch1 = r0;
Register scratch2 = r1;
Register scratch3 = r2;
if (!r3.is(receiver)) {
__ mov(r3, receiver);
receiver = r3;
}
// Stack now matches JSFunction abi.
GenerateFastApiCallBody(masm,
optimization,
argc,
receiver,
scratch1,
scratch2,
scratch3,
true);
}
......@@ -1423,6 +1339,10 @@ void LoadStubCompiler::GenerateLoadCallback(
ApiFunction fun(getter_address);
ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
ExternalReference ref = ExternalReference(&fun, type, isolate());
Register getter_address_reg = r3;
Register thunk_last_arg = r2;
__ mov(getter_address_reg, Operand(ref));
__ mov(thunk_last_arg, Operand(reinterpret_cast<int32_t>(getter_address)));
Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
ExternalReference::Type thunk_type =
......@@ -1430,10 +1350,9 @@ void LoadStubCompiler::GenerateLoadCallback(
ApiFunction thunk_fun(thunk_address);
ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
isolate());
__ CallApiFunctionAndReturn(ref,
getter_address,
__ CallApiFunctionAndReturn(getter_address_reg,
thunk_ref,
r2,
thunk_last_arg,
kStackUnwindSpace,
MemOperand(fp, 6 * kPointerSize),
NULL);
......
......@@ -96,6 +96,7 @@ namespace internal {
V(InternalArrayConstructor) \
V(ProfileEntryHook) \
V(StoreGlobal) \
V(CallApiFunction) \
/* IC Handler stubs */ \
V(LoadField) \
V(KeyedLoadField) \
......@@ -1035,6 +1036,32 @@ class StoreGlobalStub : public HandlerStub {
};
class CallApiFunctionStub : public PlatformCodeStub {
public:
CallApiFunctionStub(bool restore_context,
bool call_data_undefined,
int argc) {
bit_field_ =
RestoreContextBits::encode(restore_context) |
CallDataUndefinedBits::encode(call_data_undefined) |
ArgumentBits::encode(argc);
}
private:
virtual void Generate(MacroAssembler* masm) V8_OVERRIDE;
virtual Major MajorKey() V8_OVERRIDE { return CallApiFunction; }
virtual int MinorKey() V8_OVERRIDE { return bit_field_; }
class RestoreContextBits: public BitField<bool, 0, 1> {};
class CallDataUndefinedBits: public BitField<bool, 1, 1> {};
class ArgumentBits: public BitField<int, 2, Code::kArgumentsBits> {};
int bit_field_;
DISALLOW_COPY_AND_ASSIGN(CallApiFunctionStub);
};
class KeyedLoadFieldStub: public LoadFieldStub {
public:
KeyedLoadFieldStub(bool inobject, int index, Representation representation)
......
......@@ -5382,6 +5382,122 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
}
void CallApiFunctionStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : callee
// -- ebx : call_data
// -- ecx : holder
// -- edx : api_function_address
// -- esi : context
// --
// -- esp[0] : return address
// -- esp[4] : last argument
// -- ...
// -- esp[argc * 4] : first argument
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
Register callee = eax;
Register call_data = ebx;
Register holder = ecx;
Register api_function_address = edx;
Register return_address = edi;
Register context = esi;
int argc = ArgumentBits::decode(bit_field_);
bool restore_context = RestoreContextBits::decode(bit_field_);
bool call_data_undefined = CallDataUndefinedBits::decode(bit_field_);
typedef FunctionCallbackArguments FCA;
STATIC_ASSERT(FCA::kContextSaveIndex == 6);
STATIC_ASSERT(FCA::kCalleeIndex == 5);
STATIC_ASSERT(FCA::kDataIndex == 4);
STATIC_ASSERT(FCA::kReturnValueOffset == 3);
STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
STATIC_ASSERT(FCA::kIsolateIndex == 1);
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kArgsLength == 7);
Isolate* isolate = masm->isolate();
__ pop(return_address);
// context save
__ push(context);
// load context from callee
__ mov(context, FieldOperand(callee, JSFunction::kContextOffset));
// callee
__ push(callee);
// call data
__ push(call_data);
Register scratch = call_data;
if (!call_data_undefined) {
// return value
__ push(Immediate(isolate->factory()->undefined_value()));
// return value default
__ push(Immediate(isolate->factory()->undefined_value()));
} else {
// return value
__ push(scratch);
// return value default
__ push(scratch);
}
// isolate
__ push(Immediate(reinterpret_cast<int>(isolate)));
// holder
__ push(holder);
__ mov(scratch, esp);
// return address
__ push(return_address);
// API function gets reference to the v8::Arguments. If CPU profiler
// is enabled wrapper function will be called and we need to pass
// address of the callback as additional parameter, always allocate
// space for it.
const int kApiArgc = 1 + 1;
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
const int kApiStackSpace = 4;
__ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
// FunctionCallbackInfo::implicit_args_.
__ mov(ApiParameterOperand(2), scratch);
__ add(scratch, Immediate((argc + FCA::kArgsLength - 1) * kPointerSize));
// FunctionCallbackInfo::values_.
__ mov(ApiParameterOperand(3), scratch);
// FunctionCallbackInfo::length_.
__ Set(ApiParameterOperand(4), Immediate(argc));
// FunctionCallbackInfo::is_construct_call_.
__ Set(ApiParameterOperand(5), Immediate(0));
// v8::InvocationCallback's argument.
__ lea(scratch, ApiParameterOperand(2));
__ mov(ApiParameterOperand(0), scratch);
Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
Operand context_restore_operand(ebp,
(2 + FCA::kContextSaveIndex) * kPointerSize);
Operand return_value_operand(ebp,
(2 + FCA::kReturnValueOffset) * kPointerSize);
__ CallApiFunctionAndReturn(api_function_address,
thunk_address,
ApiParameterOperand(1),
argc + FCA::kArgsLength + 1,
return_value_operand,
restore_context ?
&context_restore_operand : NULL);
}
#undef __
} } // namespace v8::internal
......
......@@ -2297,7 +2297,7 @@ void MacroAssembler::PrepareCallApiFunction(int argc) {
void MacroAssembler::CallApiFunctionAndReturn(
Address function_address,
Register function_address,
Address thunk_address,
Operand thunk_last_arg,
int stack_space,
......@@ -2310,6 +2310,7 @@ void MacroAssembler::CallApiFunctionAndReturn(
ExternalReference level_address =
ExternalReference::handle_scope_level_address(isolate());
ASSERT(edx.is(function_address));
// Allocate HandleScope in callee-save registers.
mov(ebx, Operand::StaticVariable(next_address));
mov(edi, Operand::StaticVariable(limit_address));
......@@ -2336,14 +2337,14 @@ void MacroAssembler::CallApiFunctionAndReturn(
j(zero, &profiler_disabled);
// Additional parameter is the address of the actual getter function.
mov(thunk_last_arg, Immediate(function_address));
mov(thunk_last_arg, function_address);
// Call the api function.
call(thunk_address, RelocInfo::RUNTIME_ENTRY);
jmp(&end_profiler_check);
bind(&profiler_disabled);
// Call the api function.
call(function_address, RelocInfo::RUNTIME_ENTRY);
call(function_address);
bind(&end_profiler_check);
if (FLAG_log_timer_events) {
......
......@@ -815,7 +815,7 @@ class MacroAssembler: public Assembler {
// from handle and propagates exceptions. Clobbers ebx, edi and
// caller-save registers. Restores context. On return removes
// stack_space * kPointerSize (GCed).
void CallApiFunctionAndReturn(Address function_address,
void CallApiFunctionAndReturn(Register function_address,
Address thunk_address,
Operand thunk_last_arg,
int stack_space,
......
......@@ -414,18 +414,53 @@ static void CompileCallLoadPropertyWithInterceptor(
}
// Number of pointers to be reserved on stack for fast API call.
static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
static void GenerateFastApiCallBody(MacroAssembler* masm,
const CallOptimization& optimization,
int argc,
Register holder,
Register scratch1,
Register scratch2,
Register scratch3,
bool restore_context);
Register holder_in,
bool restore_context) {
ASSERT(optimization.is_simple_api_call());
// Abi for CallApiFunctionStub.
Register callee = eax;
Register call_data = ebx;
Register holder = ecx;
Register api_function_address = edx;
// Put holder in place.
__ Move(holder, holder_in);
Register scratch = edi;
Isolate* isolate = masm->isolate();
Handle<JSFunction> function = optimization.constant_function();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data_obj(api_call_info->data(), isolate);
// Put callee in place.
__ LoadHeapObject(callee, function);
bool call_data_undefined = false;
// Put call_data in place.
if (isolate->heap()->InNewSpace(*call_data_obj)) {
__ mov(scratch, api_call_info);
__ mov(call_data, FieldOperand(scratch, CallHandlerInfo::kDataOffset));
} else if (call_data_obj->IsUndefined()) {
call_data_undefined = true;
__ mov(call_data, Immediate(isolate->factory()->undefined_value()));
} else {
__ mov(call_data, call_data_obj);
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ mov(api_function_address, Immediate(function_address));
// Jump to stub.
CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
__ TailCallStub(&stub);
}
// Generates call to API function.
static void GenerateFastApiCall(MacroAssembler* masm,
......@@ -437,7 +472,7 @@ static void GenerateFastApiCall(MacroAssembler* masm,
__ IncrementCounter(counters->call_const_fast_api(), 1);
// Move holder to a register
Register holder_reg = eax;
Register holder_reg = ecx;
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
{
......@@ -463,9 +498,6 @@ static void GenerateFastApiCall(MacroAssembler* masm,
optimization,
argc,
holder_reg,
ebx,
ecx,
edx,
false);
}
......@@ -478,8 +510,6 @@ static void GenerateFastApiCall(MacroAssembler* masm,
const CallOptimization& optimization,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
int argc,
Register* values) {
// Copy return value.
......@@ -491,8 +521,6 @@ static void GenerateFastApiCall(MacroAssembler* masm,
Register arg = values[argc-1-i];
ASSERT(!receiver.is(arg));
ASSERT(!scratch1.is(arg));
ASSERT(!scratch2.is(arg));
ASSERT(!scratch3.is(arg));
__ push(arg);
}
__ push(scratch1);
......@@ -501,124 +529,10 @@ static void GenerateFastApiCall(MacroAssembler* masm,
optimization,
argc,
receiver,
scratch1,
scratch2,
scratch3,
true);
}
static void GenerateFastApiCallBody(MacroAssembler* masm,
const CallOptimization& optimization,
int argc,
Register holder,
Register scratch1,
Register scratch2,
Register scratch3,
bool restore_context) {
// ----------- S t a t e -------------
// -- esp[0] : return address
// -- esp[4] : last argument
// -- ...
// -- esp[argc * 4] : first argument
// -- esp[(argc + 1) * 4] : receiver
ASSERT(optimization.is_simple_api_call());
typedef FunctionCallbackArguments FCA;
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kIsolateIndex == 1);
STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
STATIC_ASSERT(FCA::kReturnValueOffset == 3);
STATIC_ASSERT(FCA::kDataIndex == 4);
STATIC_ASSERT(FCA::kCalleeIndex == 5);
STATIC_ASSERT(FCA::kContextSaveIndex == 6);
STATIC_ASSERT(FCA::kArgsLength == 7);
__ pop(scratch1);
ASSERT(!holder.is(esi));
// context save
__ push(esi);
// Get the function and setup the context.
Handle<JSFunction> function = optimization.constant_function();
__ LoadHeapObject(scratch2, function);
__ mov(esi, FieldOperand(scratch2, JSFunction::kContextOffset));
// callee
__ push(scratch2);
Isolate* isolate = masm->isolate();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data(api_call_info->data(), isolate);
// Push data from ExecutableAccessorInfo.
if (isolate->heap()->InNewSpace(*call_data)) {
__ mov(scratch2, api_call_info);
__ mov(scratch3, FieldOperand(scratch2, CallHandlerInfo::kDataOffset));
__ push(scratch3);
} else {
__ push(Immediate(call_data));
}
// return value
__ push(Immediate(isolate->factory()->undefined_value()));
// return value default
__ push(Immediate(isolate->factory()->undefined_value()));
// isolate
__ push(Immediate(reinterpret_cast<int>(isolate)));
// holder
__ push(holder);
// store receiver address for GenerateFastApiCallBody
ASSERT(!scratch1.is(eax));
__ mov(eax, esp);
// return address
__ push(scratch1);
// API function gets reference to the v8::Arguments. If CPU profiler
// is enabled wrapper function will be called and we need to pass
// address of the callback as additional parameter, always allocate
// space for it.
const int kApiArgc = 1 + 1;
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
const int kApiStackSpace = 4;
// Function address is a foreign pointer outside V8's heap.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
// FunctionCallbackInfo::implicit_args_.
__ mov(ApiParameterOperand(2), eax);
__ add(eax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize));
// FunctionCallbackInfo::values_.
__ mov(ApiParameterOperand(3), eax);
// FunctionCallbackInfo::length_.
__ Set(ApiParameterOperand(4), Immediate(argc));
// FunctionCallbackInfo::is_construct_call_.
__ Set(ApiParameterOperand(5), Immediate(0));
// v8::InvocationCallback's argument.
__ lea(eax, ApiParameterOperand(2));
__ mov(ApiParameterOperand(0), eax);
Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
Operand context_restore_operand(ebp,
(2 + FCA::kContextSaveIndex) * kPointerSize);
Operand return_value_operand(ebp,
(2 + FCA::kReturnValueOffset) * kPointerSize);
__ CallApiFunctionAndReturn(function_address,
thunk_address,
ApiParameterOperand(1),
argc + kFastApiCallArguments + 1,
return_value_operand,
restore_context ?
&context_restore_operand : NULL);
}
class CallInterceptorCompiler BASE_EMBEDDED {
public:
CallInterceptorCompiler(CallStubCompiler* stub_compiler,
......@@ -1361,8 +1275,8 @@ void LoadStubCompiler::GenerateLoadField(Register reg,
void LoadStubCompiler::GenerateLoadCallback(
const CallOptimization& call_optimization) {
GenerateFastApiCall(
masm(), call_optimization, receiver(), scratch1(),
scratch2(), name(), 0, NULL);
masm(), call_optimization, receiver(),
scratch1(), 0, NULL);
}
......@@ -1410,7 +1324,6 @@ void LoadStubCompiler::GenerateLoadCallback(
// CPU profiler is active.
const int kApiArgc = 2 + 1;
Address getter_address = v8::ToCData<Address>(callback->getter());
__ PrepareCallApiFunction(kApiArgc);
__ mov(ApiParameterOperand(0), ebx); // name.
__ add(ebx, Immediate(kPointerSize));
......@@ -1421,6 +1334,10 @@ void LoadStubCompiler::GenerateLoadCallback(
// garbage collection but instead return the allocation failure
// object.
Register getter_address = edx;
Address function_address = v8::ToCData<Address>(callback->getter());
__ mov(getter_address, Immediate(function_address));
Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
__ CallApiFunctionAndReturn(getter_address,
......@@ -1876,8 +1793,8 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
Register values[] = { value() };
GenerateFastApiCall(
masm(), call_optimization, receiver(), scratch1(),
scratch2(), this->name(), 1, values);
masm(), call_optimization, receiver(),
scratch1(), 1, values);
// Return the generated code.
return GetCode(kind(), Code::FAST, name);
......
......@@ -5222,6 +5222,121 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
}
void CallApiFunctionStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : callee
// -- rbx : call_data
// -- rcx : holder
// -- rdx : api_function_address
// -- rsi : context
// --
// -- rsp[0] : return address
// -- rsp[8] : last argument
// -- ...
// -- rsp[argc * 8] : first argument
// -- rsp[(argc + 1) * 8] : receiver
// -----------------------------------
Register callee = rax;
Register call_data = rbx;
Register holder = rcx;
Register api_function_address = rdx;
Register return_address = rdi;
Register context = rsi;
int argc = ArgumentBits::decode(bit_field_);
bool restore_context = RestoreContextBits::decode(bit_field_);
bool call_data_undefined = CallDataUndefinedBits::decode(bit_field_);
typedef FunctionCallbackArguments FCA;
STATIC_ASSERT(FCA::kContextSaveIndex == 6);
STATIC_ASSERT(FCA::kCalleeIndex == 5);
STATIC_ASSERT(FCA::kDataIndex == 4);
STATIC_ASSERT(FCA::kReturnValueOffset == 3);
STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
STATIC_ASSERT(FCA::kIsolateIndex == 1);
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kArgsLength == 7);
__ PopReturnAddressTo(return_address);
// context save
__ push(context);
// load context from callee
__ movp(context, FieldOperand(callee, JSFunction::kContextOffset));
// callee
__ push(callee);
// call data
__ push(call_data);
Register scratch = call_data;
if (!call_data_undefined) {
__ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
}
// return value
__ push(scratch);
// return value default
__ push(scratch);
// isolate
__ Move(scratch,
ExternalReference::isolate_address(masm->isolate()));
__ push(scratch);
// holder
__ push(holder);
__ movp(scratch, rsp);
// Push return address back on stack.
__ PushReturnAddressFrom(return_address);
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
const int kApiStackSpace = 4;
__ PrepareCallApiFunction(kApiStackSpace);
// FunctionCallbackInfo::implicit_args_.
__ movp(StackSpaceOperand(0), scratch);
__ addq(scratch, Immediate((argc + FCA::kArgsLength - 1) * kPointerSize));
__ movp(StackSpaceOperand(1), scratch); // FunctionCallbackInfo::values_.
__ Set(StackSpaceOperand(2), argc); // FunctionCallbackInfo::length_.
// FunctionCallbackInfo::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
// It's okay if callback_arg == api_function_address
// but not arguments_arg
ASSERT(!api_function_address.is(arguments_arg));
// v8::InvocationCallback's argument.
__ lea(arguments_arg, StackSpaceOperand(0));
Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback);
StackArgumentsAccessor args_from_rbp(rbp, FCA::kArgsLength,
ARGUMENTS_DONT_CONTAIN_RECEIVER);
Operand context_restore_operand = args_from_rbp.GetArgumentOperand(
FCA::kArgsLength - 1 - FCA::kContextSaveIndex);
Operand return_value_operand = args_from_rbp.GetArgumentOperand(
FCA::kArgsLength - 1 - FCA::kReturnValueOffset);
__ CallApiFunctionAndReturn(
api_function_address,
thunk_address,
callback_arg,
argc + FCA::kArgsLength + 1,
return_value_operand,
restore_context ? &context_restore_operand : NULL);
}
#undef __
} } // namespace v8::internal
......
......@@ -671,7 +671,7 @@ void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) {
void MacroAssembler::CallApiFunctionAndReturn(
Address function_address,
Register function_address,
Address thunk_address,
Register thunk_last_arg,
int stack_space,
......@@ -697,6 +697,7 @@ void MacroAssembler::CallApiFunctionAndReturn(
ExternalReference scheduled_exception_address =
ExternalReference::scheduled_exception_address(isolate());
ASSERT(rdx.is(function_address));
// Allocate HandleScope in callee-save registers.
Register prev_next_address_reg = r14;
Register prev_limit_reg = rbx;
......@@ -726,14 +727,13 @@ void MacroAssembler::CallApiFunctionAndReturn(
j(zero, &profiler_disabled);
// Third parameter is the address of the actual getter function.
Move(thunk_last_arg, function_address, RelocInfo::EXTERNAL_REFERENCE);
Move(thunk_last_arg, function_address);
Move(rax, thunk_address, RelocInfo::EXTERNAL_REFERENCE);
jmp(&end_profiler_check);
bind(&profiler_disabled);
// Call the api function!
Move(rax, reinterpret_cast<Address>(function_address),
RelocInfo::EXTERNAL_REFERENCE);
Move(rax, function_address);
bind(&end_profiler_check);
......
......@@ -1309,7 +1309,7 @@ class MacroAssembler: public Assembler {
// from handle and propagates exceptions. Clobbers r14, r15, rbx and
// caller-save registers. Restores context. On return removes
// stack_space * kPointerSize (GCed).
void CallApiFunctionAndReturn(Address function_address,
void CallApiFunctionAndReturn(Register function_address,
Address thunk_address,
Register thunk_last_arg,
int stack_space,
......
......@@ -388,18 +388,53 @@ static void CompileCallLoadPropertyWithInterceptor(
}
// Number of pointers to be reserved on stack for fast API call.
static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
static void GenerateFastApiCallBody(MacroAssembler* masm,
const CallOptimization& optimization,
int argc,
Register holder,
Register scratch1,
Register scratch2,
Register scratch3,
bool restore_context);
Register holder_in,
bool restore_context) {
ASSERT(optimization.is_simple_api_call());
// Abi for CallApiFunctionStub.
Register callee = rax;
Register call_data = rbx;
Register holder = rcx;
Register api_function_address = rdx;
// Put holder in place.
__ Move(holder, holder_in);
Register scratch = rdi;
Isolate* isolate = masm->isolate();
Handle<JSFunction> function = optimization.constant_function();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data_obj(api_call_info->data(), isolate);
// Put callee in place.
__ Move(callee, function);
bool call_data_undefined = false;
// Put call_data in place.
if (isolate->heap()->InNewSpace(*call_data_obj)) {
__ Move(scratch, api_call_info);
__ movp(call_data, FieldOperand(scratch, CallHandlerInfo::kDataOffset));
} else if (call_data_obj->IsUndefined()) {
call_data_undefined = true;
__ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
} else {
__ Move(call_data, call_data_obj);
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ Move(
api_function_address, function_address, RelocInfo::EXTERNAL_REFERENCE);
// Jump to stub.
CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
__ TailCallStub(&stub);
}
// Generates call to API function.
......@@ -439,23 +474,15 @@ static void GenerateFastApiCall(MacroAssembler* masm,
optimization,
argc,
holder_reg,
rbx,
rcx,
rdx,
false);
}
// Generate call to api function.
// This function uses push() to generate smaller, faster code than
// the version above. It is an optimization that should will be removed
// when api call ICs are generated in hydrogen.
static void GenerateFastApiCall(MacroAssembler* masm,
const CallOptimization& optimization,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
int argc,
Register* values) {
__ PopReturnAddressTo(scratch1);
......@@ -466,8 +493,6 @@ static void GenerateFastApiCall(MacroAssembler* masm,
Register arg = values[argc-1-i];
ASSERT(!receiver.is(arg));
ASSERT(!scratch1.is(arg));
ASSERT(!scratch2.is(arg));
ASSERT(!scratch3.is(arg));
__ push(arg);
}
__ PushReturnAddressFrom(scratch1);
......@@ -476,133 +501,10 @@ static void GenerateFastApiCall(MacroAssembler* masm,
optimization,
argc,
receiver,
scratch1,
scratch2,
scratch3,
true);
}
static void GenerateFastApiCallBody(MacroAssembler* masm,
const CallOptimization& optimization,
int argc,
Register holder,
Register scratch1,
Register scratch2,
Register scratch3,
bool restore_context) {
// ----------- S t a t e -------------
// -- rsp[0] : return address
// -- rsp[8] : last argument
// -- ...
// -- rsp[argc * 8] : first argument
// -- rsp[(argc + 1) * 8] : receiver
// -----------------------------------
ASSERT(optimization.is_simple_api_call());
typedef FunctionCallbackArguments FCA;
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kIsolateIndex == 1);
STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
STATIC_ASSERT(FCA::kReturnValueOffset == 3);
STATIC_ASSERT(FCA::kDataIndex == 4);
STATIC_ASSERT(FCA::kCalleeIndex == 5);
STATIC_ASSERT(FCA::kContextSaveIndex == 6);
STATIC_ASSERT(FCA::kArgsLength == 7);
__ PopReturnAddressTo(scratch1);
ASSERT(!holder.is(rsi));
// context save
__ push(rsi);
// Get the function and setup the context.
Handle<JSFunction> function = optimization.constant_function();
__ Move(scratch2, function);
__ push(scratch2);
__ movp(rsi, FieldOperand(scratch2, JSFunction::kContextOffset));
Isolate* isolate = masm->isolate();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data(api_call_info->data(), isolate);
// Push data from ExecutableAccessorInfo.
bool call_data_undefined = false;
if (isolate->heap()->InNewSpace(*call_data)) {
__ Move(scratch2, api_call_info);
__ movp(scratch3, FieldOperand(scratch2, CallHandlerInfo::kDataOffset));
} else if (call_data->IsUndefined()) {
call_data_undefined = true;
__ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex);
} else {
__ Move(scratch3, call_data);
}
// call data
__ push(scratch3);
if (!call_data_undefined) {
__ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex);
}
// return value
__ push(scratch3);
// return value default
__ push(scratch3);
// isolate
__ Move(scratch3,
ExternalReference::isolate_address(masm->isolate()));
__ push(scratch3);
// holder
__ push(holder);
ASSERT(!scratch1.is(rax));
__ movp(rax, rsp);
// Push return address back on stack.
__ PushReturnAddressFrom(scratch1);
// Function address is a foreign pointer outside V8's heap.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
const int kApiStackSpace = 4;
__ PrepareCallApiFunction(kApiStackSpace);
__ movp(StackSpaceOperand(0), rax); // FunctionCallbackInfo::implicit_args_.
__ addq(rax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize));
__ movp(StackSpaceOperand(1), rax); // FunctionCallbackInfo::values_.
__ Set(StackSpaceOperand(2), argc); // FunctionCallbackInfo::length_.
// FunctionCallbackInfo::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);
StackArgumentsAccessor args_from_rbp(rbp, kFastApiCallArguments,
ARGUMENTS_DONT_CONTAIN_RECEIVER);
Operand context_restore_operand = args_from_rbp.GetArgumentOperand(
kFastApiCallArguments - 1 - FCA::kContextSaveIndex);
Operand return_value_operand = args_from_rbp.GetArgumentOperand(
kFastApiCallArguments - 1 - FCA::kReturnValueOffset);
__ CallApiFunctionAndReturn(
function_address,
thunk_address,
callback_arg,
argc + kFastApiCallArguments + 1,
return_value_operand,
restore_context ? &context_restore_operand : NULL);
}
class CallInterceptorCompiler BASE_EMBEDDED {
public:
CallInterceptorCompiler(CallStubCompiler* stub_compiler,
......@@ -1279,7 +1181,7 @@ void LoadStubCompiler::GenerateLoadCallback(
const CallOptimization& call_optimization) {
GenerateFastApiCall(
masm(), call_optimization, receiver(),
scratch1(), scratch2(), name(), 0, NULL);
scratch1(), 0, NULL);
}
......@@ -1350,12 +1252,15 @@ void LoadStubCompiler::GenerateLoadCallback(
Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback);
Register api_function_address = rdx;
__ Move(api_function_address, getter_address, RelocInfo::EXTERNAL_REFERENCE);
// The name handler is counted as an argument.
StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength);
Operand return_value_operand = args.GetArgumentOperand(
PropertyCallbackArguments::kArgsLength - 1 -
PropertyCallbackArguments::kReturnValueOffset);
__ CallApiFunctionAndReturn(getter_address,
__ CallApiFunctionAndReturn(api_function_address,
thunk_address,
getter_arg,
kStackSpace,
......@@ -1792,8 +1697,8 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
Register values[] = { value() };
GenerateFastApiCall(
masm(), call_optimization, receiver(), scratch1(),
scratch2(), this->name(), 1, values);
masm(), call_optimization, receiver(),
scratch1(), 1, values);
// Return the generated code.
return GetCode(kind(), Code::FAST, name);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment