}
+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
void MacroAssembler::CallApiFunctionAndReturn(
- ExternalReference function,
- Address function_address,
+ Register function_address,
ExternalReference thunk_ref,
Register thunk_last_arg,
int stack_space,
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));
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.
// 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,
}
-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);
}
__ 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:
{
optimization,
argc,
holder_reg,
- r1,
- r2,
- r3,
false);
}
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);
}
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 =
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);
V(InternalArrayConstructor) \
V(ProfileEntryHook) \
V(StoreGlobal) \
+ V(CallApiFunction) \
/* IC Handler stubs */ \
V(LoadField) \
V(KeyedLoadField) \
};
+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)
}
+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
void MacroAssembler::CallApiFunctionAndReturn(
- Address function_address,
+ Register function_address,
Address thunk_address,
Operand thunk_last_arg,
int stack_space,
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));
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) {
// 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,
}
-// 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,
__ 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:
{
optimization,
argc,
holder_reg,
- ebx,
- ecx,
- edx,
false);
}
const CallOptimization& optimization,
Register receiver,
Register scratch1,
- Register scratch2,
- Register scratch3,
int argc,
Register* values) {
// Copy return value.
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);
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,
void LoadStubCompiler::GenerateLoadCallback(
const CallOptimization& call_optimization) {
GenerateFastApiCall(
- masm(), call_optimization, receiver(), scratch1(),
- scratch2(), name(), 0, NULL);
+ masm(), call_optimization, receiver(),
+ scratch1(), 0, NULL);
}
// 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));
// 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,
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);
}
+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
void MacroAssembler::CallApiFunctionAndReturn(
- Address function_address,
+ Register function_address,
Address thunk_address,
Register thunk_last_arg,
int stack_space,
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;
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);
// 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,
}
-// 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.
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);
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);
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,
const CallOptimization& call_optimization) {
GenerateFastApiCall(
masm(), call_optimization, receiver(),
- scratch1(), scratch2(), name(), 0, NULL);
+ scratch1(), 0, NULL);
}
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,
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);