internal::Object** implicit_args_;
internal::Object** values_;
int length_;
- bool is_construct_call_;
+ int is_construct_call_;
};
template<typename T>
bool FunctionCallbackInfo<T>::IsConstructCall() const {
- return is_construct_call_;
+ return is_construct_call_ & 0x1;
}
}
-void CallApiFunctionStub::Generate(MacroAssembler* masm) {
+static void CallApiFunctionStubHelper(MacroAssembler* masm,
+ const ParameterCount& argc,
+ bool return_first_arg,
+ bool call_data_undefined) {
// ----------- S t a t e -------------
// -- r0 : callee
// -- r4 : call_data
// -- r2 : holder
// -- r1 : api_function_address
+ // -- r3 : number of arguments if argc is a register
// -- cp : context
// --
// -- sp[0] : last argument
Register api_function_address = r1;
Register context = cp;
- int argc = this->argc();
- bool is_store = this->is_store();
- bool call_data_undefined = this->call_data_undefined();
-
typedef FunctionCallbackArguments FCA;
STATIC_ASSERT(FCA::kContextSaveIndex == 6);
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kArgsLength == 7);
+ DCHECK(argc.is_immediate() || r3.is(argc.reg()));
+
// context save
__ push(context);
// load context from callee
// return value default
__ push(scratch);
// isolate
- __ mov(scratch,
- Operand(ExternalReference::isolate_address(isolate())));
+ __ mov(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
__ push(scratch);
// holder
__ push(holder);
__ 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;
+ if (argc.is_immediate()) {
+ // FunctionCallbackInfo::values_
+ __ add(ip, scratch,
+ Operand((FCA::kArgsLength - 1 + argc.immediate()) * kPointerSize));
+ __ str(ip, MemOperand(r0, 1 * kPointerSize));
+ // FunctionCallbackInfo::length_ = argc
+ __ mov(ip, Operand(argc.immediate()));
+ __ str(ip, MemOperand(r0, 2 * kPointerSize));
+ // FunctionCallbackInfo::is_construct_call_ = 0
+ __ mov(ip, Operand::Zero());
+ __ str(ip, MemOperand(r0, 3 * kPointerSize));
+ } else {
+ // FunctionCallbackInfo::values_
+ __ add(ip, scratch, Operand(argc.reg(), LSL, kPointerSizeLog2));
+ __ add(ip, ip, Operand((FCA::kArgsLength - 1) * kPointerSize));
+ __ str(ip, MemOperand(r0, 1 * kPointerSize));
+ // FunctionCallbackInfo::length_ = argc
+ __ str(argc.reg(), MemOperand(r0, 2 * kPointerSize));
+ // FunctionCallbackInfo::is_construct_call_
+ __ add(argc.reg(), argc.reg(), Operand(FCA::kArgsLength + 1));
+ __ mov(ip, Operand(argc.reg(), LSL, kPointerSizeLog2));
+ __ str(ip, MemOperand(r0, 3 * kPointerSize));
+ }
+
ExternalReference thunk_ref =
- ExternalReference::invoke_function_callback(isolate());
+ ExternalReference::invoke_function_callback(masm->isolate());
AllowExternalCallThatCantCauseGC scope(masm);
MemOperand context_restore_operand(
fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
// Stores return the first js argument
int return_value_offset = 0;
- if (is_store) {
+ if (return_first_arg) {
return_value_offset = 2 + FCA::kArgsLength;
} else {
return_value_offset = 2 + FCA::kReturnValueOffset;
}
MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
-
- __ CallApiFunctionAndReturn(api_function_address,
- thunk_ref,
- kStackUnwindSpace,
- return_value_operand,
+ int stack_space = 0;
+ MemOperand is_construct_call_operand = MemOperand(sp, 4 * kPointerSize);
+ MemOperand* stack_space_operand = &is_construct_call_operand;
+ if (argc.is_immediate()) {
+ stack_space = argc.immediate() + FCA::kArgsLength + 1;
+ stack_space_operand = NULL;
+ }
+ __ CallApiFunctionAndReturn(api_function_address, thunk_ref, stack_space,
+ stack_space_operand, return_value_operand,
&context_restore_operand);
}
+void CallApiFunctionStub::Generate(MacroAssembler* masm) {
+ bool call_data_undefined = this->call_data_undefined();
+ CallApiFunctionStubHelper(masm, ParameterCount(r3), false,
+ call_data_undefined);
+}
+
+
+void CallApiAccessorStub::Generate(MacroAssembler* masm) {
+ bool is_store = this->is_store();
+ int argc = is_store ? 1 : 0;
+ bool call_data_undefined = this->call_data_undefined();
+ CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store,
+ call_data_undefined);
+}
+
+
void CallApiGetterStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- sp[0] : name
ExternalReference thunk_ref =
ExternalReference::invoke_accessor_getter_callback(isolate());
- __ CallApiFunctionAndReturn(api_function_address,
- thunk_ref,
- kStackUnwindSpace,
- MemOperand(fp, 6 * kPointerSize),
- NULL);
+ __ CallApiFunctionAndReturn(api_function_address, thunk_ref,
+ kStackUnwindSpace, NULL,
+ MemOperand(fp, 6 * kPointerSize), NULL);
}
r4, // call_data
r2, // holder
r1, // api_function_address
+ r3, // actual number of arguments
+ };
+ Representation representations[] = {
+ Representation::Tagged(), // context
+ Representation::Tagged(), // callee
+ Representation::Tagged(), // call_data
+ Representation::Tagged(), // holder
+ Representation::External(), // api_function_address
+ Representation::Integer32(), // actual number of arguments
+ };
+ data->Initialize(arraysize(registers), registers, representations,
+ &default_descriptor);
+}
+
+
+void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+ static PlatformInterfaceDescriptor default_descriptor =
+ PlatformInterfaceDescriptor(CAN_INLINE_TARGET_ADDRESS);
+
+ Register registers[] = {
+ cp, // context
+ r0, // callee
+ r4, // call_data
+ r2, // holder
+ r1, // api_function_address
};
Representation representations[] = {
Representation::Tagged(), // context
}
-void MacroAssembler::LeaveExitFrame(bool save_doubles,
- Register argument_count,
- bool restore_context) {
+void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
+ bool restore_context,
+ bool argument_count_is_length) {
ConstantPoolUnavailableScope constant_pool_unavailable(this);
// Optionally restore all double registers.
mov(sp, Operand(fp));
ldm(ia_w, sp, fp.bit() | lr.bit());
if (argument_count.is_valid()) {
- add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2));
+ if (argument_count_is_length) {
+ add(sp, sp, argument_count);
+ } else {
+ add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2));
+ }
}
}
void MacroAssembler::CallApiFunctionAndReturn(
- Register function_address,
- ExternalReference thunk_ref,
- int stack_space,
- MemOperand return_value_operand,
+ Register function_address, ExternalReference thunk_ref, int stack_space,
+ MemOperand* stack_space_operand, MemOperand return_value_operand,
MemOperand* context_restore_operand) {
ExternalReference next_address =
ExternalReference::handle_scope_next_address(isolate());
ldr(cp, *context_restore_operand);
}
// LeaveExitFrame expects unwind space to be in a register.
- mov(r4, Operand(stack_space));
- LeaveExitFrame(false, r4, !restore_context);
+ if (stack_space_operand != NULL) {
+ ldr(r4, *stack_space_operand);
+ } else {
+ mov(r4, Operand(stack_space));
+ }
+ LeaveExitFrame(false, r4, !restore_context, stack_space_operand != NULL);
mov(pc, lr);
bind(&promote_scheduled_exception);
// 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,
- bool restore_context);
+ void LeaveExitFrame(bool save_doubles, Register argument_count,
+ bool restore_context,
+ bool argument_count_is_length = false);
// Get the actual activation frame alignment for target environment.
static int ActivationFrameAlignment();
// - space to be unwound on exit (includes the call JS arguments space and
// the additional space allocated for the fast call).
void CallApiFunctionAndReturn(Register function_address,
- ExternalReference thunk_ref,
- int stack_space,
+ ExternalReference thunk_ref, int stack_space,
+ MemOperand* stack_space_operand,
MemOperand return_value_operand,
MemOperand* context_restore_operand);
}
-void CallApiFunctionStub::Generate(MacroAssembler* masm) {
+static void CallApiFunctionStubHelper(MacroAssembler* masm,
+ const ParameterCount& argc,
+ bool return_first_arg,
+ bool call_data_undefined) {
// ----------- S t a t e -------------
// -- x0 : callee
// -- x4 : call_data
// -- x2 : holder
// -- x1 : api_function_address
+ // -- x3 : number of arguments if argc is a register
// -- cp : context
// --
// -- sp[0] : last argument
Register api_function_address = x1;
Register context = cp;
- int argc = this->argc();
- bool is_store = this->is_store();
- bool call_data_undefined = this->call_data_undefined();
-
typedef FunctionCallbackArguments FCA;
STATIC_ASSERT(FCA::kContextSaveIndex == 6);
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kArgsLength == 7);
+ DCHECK(argc.is_immediate() || x3.is(argc.reg()));
+
// FunctionCallbackArguments: context, callee and call data.
__ Push(context, callee, call_data);
__ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
}
Register isolate_reg = x5;
- __ Mov(isolate_reg, ExternalReference::isolate_address(isolate()));
+ __ Mov(isolate_reg, ExternalReference::isolate_address(masm->isolate()));
// FunctionCallbackArguments:
// return value, return value default, isolate, holder.
// x0 = FunctionCallbackInfo&
// Arguments is after the return address.
__ Add(x0, masm->StackPointer(), 1 * kPointerSize);
- // FunctionCallbackInfo::implicit_args_ and FunctionCallbackInfo::values_
- __ Add(x10, args, Operand((FCA::kArgsLength - 1 + argc) * kPointerSize));
- __ Stp(args, x10, MemOperand(x0, 0 * kPointerSize));
- // FunctionCallbackInfo::length_ = argc and
- // FunctionCallbackInfo::is_construct_call = 0
- __ Mov(x10, argc);
- __ Stp(x10, xzr, MemOperand(x0, 2 * kPointerSize));
-
- const int kStackUnwindSpace = argc + FCA::kArgsLength + 1;
+ if (argc.is_immediate()) {
+ // FunctionCallbackInfo::implicit_args_ and FunctionCallbackInfo::values_
+ __ Add(x10, args,
+ Operand((FCA::kArgsLength - 1 + argc.immediate()) * kPointerSize));
+ __ Stp(args, x10, MemOperand(x0, 0 * kPointerSize));
+ // FunctionCallbackInfo::length_ = argc and
+ // FunctionCallbackInfo::is_construct_call = 0
+ __ Mov(x10, argc.immediate());
+ __ Stp(x10, xzr, MemOperand(x0, 2 * kPointerSize));
+ } else {
+ // FunctionCallbackInfo::implicit_args_ and FunctionCallbackInfo::values_
+ __ Add(x10, args, Operand(argc.reg(), LSL, kPointerSizeLog2));
+ __ Add(x10, x10, (FCA::kArgsLength - 1) * kPointerSize);
+ __ Stp(args, x10, MemOperand(x0, 0 * kPointerSize));
+ // FunctionCallbackInfo::length_ = argc and
+ // FunctionCallbackInfo::is_construct_call
+ __ Add(x10, argc.reg(), FCA::kArgsLength + 1);
+ __ Mov(x10, Operand(x10, LSL, kPointerSizeLog2));
+ __ Stp(argc.reg(), x10, MemOperand(x0, 2 * kPointerSize));
+ }
+
ExternalReference thunk_ref =
- ExternalReference::invoke_function_callback(isolate());
+ ExternalReference::invoke_function_callback(masm->isolate());
AllowExternalCallThatCantCauseGC scope(masm);
MemOperand context_restore_operand(
fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
// Stores return the first js argument
int return_value_offset = 0;
- if (is_store) {
+ if (return_first_arg) {
return_value_offset = 2 + FCA::kArgsLength;
} else {
return_value_offset = 2 + FCA::kReturnValueOffset;
}
MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
+ int stack_space = 0;
+ MemOperand is_construct_call_operand =
+ MemOperand(masm->StackPointer(), 4 * kPointerSize);
+ MemOperand* stack_space_operand = &is_construct_call_operand;
+ if (argc.is_immediate()) {
+ stack_space = argc.immediate() + FCA::kArgsLength + 1;
+ stack_space_operand = NULL;
+ }
const int spill_offset = 1 + kApiStackSpace;
- __ CallApiFunctionAndReturn(api_function_address,
- thunk_ref,
- kStackUnwindSpace,
- spill_offset,
- return_value_operand,
- &context_restore_operand);
+ __ CallApiFunctionAndReturn(api_function_address, thunk_ref, stack_space,
+ stack_space_operand, spill_offset,
+ return_value_operand, &context_restore_operand);
+}
+
+
+void CallApiFunctionStub::Generate(MacroAssembler* masm) {
+ bool call_data_undefined = this->call_data_undefined();
+ CallApiFunctionStubHelper(masm, ParameterCount(x3), false,
+ call_data_undefined);
+}
+
+
+void CallApiAccessorStub::Generate(MacroAssembler* masm) {
+ bool is_store = this->is_store();
+ int argc = is_store ? 1 : 0;
+ bool call_data_undefined = this->call_data_undefined();
+ CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store,
+ call_data_undefined);
}
ExternalReference::invoke_accessor_getter_callback(isolate());
const int spill_offset = 1 + kApiStackSpace;
- __ CallApiFunctionAndReturn(api_function_address,
- thunk_ref,
- kStackUnwindSpace,
- spill_offset,
- MemOperand(fp, 6 * kPointerSize),
- NULL);
+ __ CallApiFunctionAndReturn(api_function_address, thunk_ref,
+ kStackUnwindSpace, NULL, spill_offset,
+ MemOperand(fp, 6 * kPointerSize), NULL);
}
x4, // call_data
x2, // holder
x1, // api_function_address
+ x3, // actual number of arguments
+ };
+ Representation representations[] = {
+ Representation::Tagged(), // context
+ Representation::Tagged(), // callee
+ Representation::Tagged(), // call_data
+ Representation::Tagged(), // holder
+ Representation::External(), // api_function_address
+ Representation::Integer32(), // actual number of arguments
+ };
+ data->Initialize(arraysize(registers), registers, representations,
+ &default_descriptor);
+}
+
+
+void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+ static PlatformInterfaceDescriptor default_descriptor =
+ PlatformInterfaceDescriptor(CAN_INLINE_TARGET_ADDRESS);
+
+ Register registers[] = {
+ cp, // context
+ x0, // callee
+ x4, // call_data
+ x2, // holder
+ x1, // api_function_address
};
Representation representations[] = {
Representation::Tagged(), // context
void MacroAssembler::CallApiFunctionAndReturn(
- Register function_address,
- ExternalReference thunk_ref,
- int stack_space,
- int spill_offset,
- MemOperand return_value_operand,
- MemOperand* context_restore_operand) {
+ Register function_address, ExternalReference thunk_ref, int stack_space,
+ MemOperand* stack_space_operand, int spill_offset,
+ MemOperand return_value_operand, MemOperand* context_restore_operand) {
ASM_LOCATION("CallApiFunctionAndReturn");
ExternalReference next_address =
ExternalReference::handle_scope_next_address(isolate());
Ldr(cp, *context_restore_operand);
}
+ if (stack_space_operand != NULL) {
+ Ldr(w2, *stack_space_operand);
+ }
+
LeaveExitFrame(false, x1, !restore_context);
- Drop(stack_space);
+ if (stack_space_operand != NULL) {
+ Drop(x2, 1);
+ } else {
+ Drop(stack_space);
+ }
Ret();
Bind(&promote_scheduled_exception);
// 'spill_offset' is the offset from the stack pointer where
// CallApiFunctionAndReturn can spill registers.
void CallApiFunctionAndReturn(Register function_address,
- ExternalReference thunk_ref,
- int stack_space,
+ ExternalReference thunk_ref, int stack_space,
+ MemOperand* stack_space_operand,
int spill_offset,
MemOperand return_value_operand,
MemOperand* context_restore_operand);
V(ArrayConstructor) \
V(BinaryOpICWithAllocationSite) \
V(CallApiFunction) \
+ V(CallApiAccessor) \
V(CallApiGetter) \
V(CallConstruct) \
V(CallFunction) \
class CallApiFunctionStub : public PlatformCodeStub {
public:
- CallApiFunctionStub(Isolate* isolate,
- bool is_store,
- bool call_data_undefined,
- int argc) : PlatformCodeStub(isolate) {
+ explicit CallApiFunctionStub(Isolate* isolate, bool call_data_undefined)
+ : PlatformCodeStub(isolate) {
+ minor_key_ = CallDataUndefinedBits::encode(call_data_undefined);
+ }
+
+ private:
+ bool call_data_undefined() const {
+ return CallDataUndefinedBits::decode(minor_key_);
+ }
+
+ class CallDataUndefinedBits : public BitField<bool, 0, 1> {};
+
+ DEFINE_CALL_INTERFACE_DESCRIPTOR(ApiFunction);
+ DEFINE_PLATFORM_CODE_STUB(CallApiFunction, PlatformCodeStub);
+};
+
+
+class CallApiAccessorStub : public PlatformCodeStub {
+ public:
+ CallApiAccessorStub(Isolate* isolate, bool is_store, bool call_data_undefined)
+ : PlatformCodeStub(isolate) {
minor_key_ = IsStoreBits::encode(is_store) |
- CallDataUndefinedBits::encode(call_data_undefined) |
- ArgumentBits::encode(argc);
- DCHECK(!is_store || argc == 1);
+ CallDataUndefinedBits::encode(call_data_undefined);
}
private:
bool call_data_undefined() const {
return CallDataUndefinedBits::decode(minor_key_);
}
- int argc() const { return ArgumentBits::decode(minor_key_); }
class IsStoreBits: public BitField<bool, 0, 1> {};
class CallDataUndefinedBits: public BitField<bool, 1, 1> {};
- class ArgumentBits: public BitField<int, 2, Code::kArgumentsBits> {};
- STATIC_ASSERT(Code::kArgumentsBits + 2 <= kStubMinorKeyBits);
- DEFINE_CALL_INTERFACE_DESCRIPTOR(ApiFunction);
- DEFINE_PLATFORM_CODE_STUB(CallApiFunction, PlatformCodeStub);
+ DEFINE_CALL_INTERFACE_DESCRIPTOR(ApiAccessor);
+ DEFINE_PLATFORM_CODE_STUB(CallApiAccessor, PlatformCodeStub);
};
PrintF("\n");
}
- bool drop_extra = false;
+ bool is_function = false;
bool is_store = false;
switch (call_type) {
case kCallApiFunction:
}
// Includes receiver.
PushArgumentsFromEnvironment(argc + 1);
- // Drop function after call.
- drop_extra = true;
+ is_function = true;
break;
case kCallApiGetter:
// Receiver and prototype chain cannot have changed.
}
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data_obj(api_call_info->data(), isolate());
- bool call_data_is_undefined = call_data_obj->IsUndefined();
+ bool call_data_undefined = call_data_obj->IsUndefined();
HValue* call_data = Add<HConstant>(call_data_obj);
ApiFunction fun(v8::ToCData<Address>(api_call_info->callback()));
ExternalReference ref = ExternalReference(&fun,
isolate());
HValue* api_function_address = Add<HConstant>(ExternalReference(ref));
- HValue* op_vals[] = {
- context(),
- Add<HConstant>(function),
- call_data,
- holder,
- api_function_address
- };
-
- ApiFunctionDescriptor descriptor(isolate());
- CallApiFunctionStub stub(isolate(), is_store, call_data_is_undefined, argc);
- Handle<Code> code = stub.GetCode();
- HConstant* code_value = Add<HConstant>(code);
-
- DCHECK((sizeof(op_vals) / kPointerSize) == descriptor.GetEnvironmentLength());
-
- HInstruction* call = New<HCallWithDescriptor>(
- code_value, argc + 1, descriptor,
- Vector<HValue*>(op_vals, descriptor.GetEnvironmentLength()));
+ HValue* op_vals[] = {context(), Add<HConstant>(function), call_data, holder,
+ api_function_address, nullptr};
+
+ HInstruction* call = nullptr;
+ if (!is_function) {
+ CallApiAccessorStub stub(isolate(), is_store, call_data_undefined);
+ Handle<Code> code = stub.GetCode();
+ HConstant* code_value = Add<HConstant>(code);
+ ApiAccessorDescriptor descriptor(isolate());
+ DCHECK(arraysize(op_vals) - 1 == descriptor.GetEnvironmentLength());
+ call = New<HCallWithDescriptor>(
+ code_value, argc + 1, descriptor,
+ Vector<HValue*>(op_vals, descriptor.GetEnvironmentLength()));
+ } else {
+ op_vals[arraysize(op_vals) - 1] = Add<HConstant>(argc);
+ CallApiFunctionStub stub(isolate(), call_data_undefined);
+ Handle<Code> code = stub.GetCode();
+ HConstant* code_value = Add<HConstant>(code);
+ ApiFunctionDescriptor descriptor(isolate());
+ DCHECK(arraysize(op_vals) == descriptor.GetEnvironmentLength());
+ call = New<HCallWithDescriptor>(
+ code_value, argc + 1, descriptor,
+ Vector<HValue*>(op_vals, descriptor.GetEnvironmentLength()));
+ Drop(1); // Drop function.
+ }
- if (drop_extra) Drop(1); // Drop function.
ast_context()->ReturnInstruction(call, ast_id);
return true;
}
}
-void CallApiFunctionStub::Generate(MacroAssembler* masm) {
+static void CallApiFunctionStubHelper(MacroAssembler* masm,
+ const ParameterCount& argc,
+ bool return_first_arg,
+ bool call_data_undefined) {
// ----------- S t a t e -------------
// -- eax : callee
// -- ebx : call_data
// -- ecx : holder
// -- edx : api_function_address
// -- esi : context
+ // -- edi : number of arguments if argc is a register
// --
// -- esp[0] : return address
// -- esp[4] : last argument
Register call_data = ebx;
Register holder = ecx;
Register api_function_address = edx;
- Register return_address = edi;
Register context = esi;
- int argc = this->argc();
- bool is_store = this->is_store();
- bool call_data_undefined = this->call_data_undefined();
-
typedef FunctionCallbackArguments FCA;
STATIC_ASSERT(FCA::kContextSaveIndex == 6);
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kArgsLength == 7);
- __ pop(return_address);
+ DCHECK(argc.is_immediate() || edi.is(argc.reg()));
- // context save
- __ push(context);
- // load context from callee
- __ mov(context, FieldOperand(callee, JSFunction::kContextOffset));
+ // pop return address and save context
+ __ xchg(context, Operand(esp, 0));
// callee
__ push(callee);
Register scratch = call_data;
if (!call_data_undefined) {
// return value
- __ push(Immediate(isolate()->factory()->undefined_value()));
+ __ push(Immediate(masm->isolate()->factory()->undefined_value()));
// return value default
- __ push(Immediate(isolate()->factory()->undefined_value()));
+ __ push(Immediate(masm->isolate()->factory()->undefined_value()));
} else {
// return value
__ push(scratch);
__ push(scratch);
}
// isolate
- __ push(Immediate(reinterpret_cast<int>(isolate())));
+ __ push(Immediate(reinterpret_cast<int>(masm->isolate())));
// holder
__ push(holder);
__ mov(scratch, esp);
- // return address
- __ push(return_address);
+ // push return address
+ __ push(context);
+
+ // load context from callee
+ __ mov(context, FieldOperand(callee, JSFunction::kContextOffset));
// API function gets reference to the v8::Arguments. If CPU profiler
// is enabled wrapper function will be called and we need to pass
// FunctionCallbackInfo::implicit_args_.
__ mov(ApiParameterOperand(2), scratch);
- __ add(scratch, Immediate((argc + FCA::kArgsLength - 1) * kPointerSize));
- // FunctionCallbackInfo::values_.
- __ mov(ApiParameterOperand(3), scratch);
- // FunctionCallbackInfo::length_.
- __ Move(ApiParameterOperand(4), Immediate(argc));
- // FunctionCallbackInfo::is_construct_call_.
- __ Move(ApiParameterOperand(5), Immediate(0));
+ if (argc.is_immediate()) {
+ __ add(scratch,
+ Immediate((argc.immediate() + FCA::kArgsLength - 1) * kPointerSize));
+ // FunctionCallbackInfo::values_.
+ __ mov(ApiParameterOperand(3), scratch);
+ // FunctionCallbackInfo::length_.
+ __ Move(ApiParameterOperand(4), Immediate(argc.immediate()));
+ // FunctionCallbackInfo::is_construct_call_.
+ __ Move(ApiParameterOperand(5), Immediate(0));
+ } else {
+ __ lea(scratch, Operand(scratch, argc.reg(), times_pointer_size,
+ (FCA::kArgsLength - 1) * kPointerSize));
+ // FunctionCallbackInfo::values_.
+ __ mov(ApiParameterOperand(3), scratch);
+ // FunctionCallbackInfo::length_.
+ __ mov(ApiParameterOperand(4), argc.reg());
+ // FunctionCallbackInfo::is_construct_call_.
+ __ lea(argc.reg(), Operand(argc.reg(), times_pointer_size,
+ (FCA::kArgsLength + 1) * kPointerSize));
+ __ mov(ApiParameterOperand(5), argc.reg());
+ }
// v8::InvocationCallback's argument.
__ lea(scratch, ApiParameterOperand(2));
__ mov(ApiParameterOperand(0), scratch);
ExternalReference thunk_ref =
- ExternalReference::invoke_function_callback(isolate());
+ ExternalReference::invoke_function_callback(masm->isolate());
Operand context_restore_operand(ebp,
(2 + FCA::kContextSaveIndex) * kPointerSize);
// Stores return the first js argument
int return_value_offset = 0;
- if (is_store) {
+ if (return_first_arg) {
return_value_offset = 2 + FCA::kArgsLength;
} else {
return_value_offset = 2 + FCA::kReturnValueOffset;
}
Operand return_value_operand(ebp, return_value_offset * kPointerSize);
- __ CallApiFunctionAndReturn(api_function_address,
- thunk_ref,
- ApiParameterOperand(1),
- argc + FCA::kArgsLength + 1,
- return_value_operand,
- &context_restore_operand);
+ int stack_space = 0;
+ Operand is_construct_call_operand = ApiParameterOperand(5);
+ Operand* stack_space_operand = &is_construct_call_operand;
+ if (argc.is_immediate()) {
+ stack_space = argc.immediate() + FCA::kArgsLength + 1;
+ stack_space_operand = nullptr;
+ }
+ __ CallApiFunctionAndReturn(
+ api_function_address, thunk_ref, ApiParameterOperand(1), stack_space,
+ stack_space_operand, return_value_operand, &context_restore_operand);
+}
+
+
+void CallApiFunctionStub::Generate(MacroAssembler* masm) {
+ // TODO(dcarney): make eax contain the function address.
+ bool call_data_undefined = this->call_data_undefined();
+ CallApiFunctionStubHelper(masm, ParameterCount(edi), false,
+ call_data_undefined);
+}
+
+
+void CallApiAccessorStub::Generate(MacroAssembler* masm) {
+ bool is_store = this->is_store();
+ int argc = is_store ? 1 : 0;
+ bool call_data_undefined = this->call_data_undefined();
+ CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store,
+ call_data_undefined);
}
ExternalReference thunk_ref =
ExternalReference::invoke_accessor_getter_callback(isolate());
- __ CallApiFunctionAndReturn(api_function_address,
- thunk_ref,
- ApiParameterOperand(2),
- kStackSpace,
- Operand(ebp, 7 * kPointerSize),
- NULL);
+ __ CallApiFunctionAndReturn(api_function_address, thunk_ref,
+ ApiParameterOperand(2), kStackSpace, nullptr,
+ Operand(ebp, 7 * kPointerSize), NULL);
}
ebx, // call_data
ecx, // holder
edx, // api_function_address
+ edi, // actual number of arguments
+ };
+ Representation representations[] = {
+ Representation::Tagged(), // context
+ Representation::Tagged(), // callee
+ Representation::Tagged(), // call_data
+ Representation::Tagged(), // holder
+ Representation::External(), // api_function_address
+ Representation::Integer32(), // actual number of arguments
+ };
+ data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+ Register registers[] = {
+ esi, // context
+ eax, // callee
+ ebx, // call_data
+ ecx, // holder
+ edx, // api_function_address
};
Representation representations[] = {
Representation::Tagged(), // context
void MacroAssembler::CallApiFunctionAndReturn(
- Register function_address,
- ExternalReference thunk_ref,
- Operand thunk_last_arg,
- int stack_space,
- Operand return_value_operand,
- Operand* context_restore_operand) {
+ Register function_address, ExternalReference thunk_ref,
+ Operand thunk_last_arg, int stack_space, Operand* stack_space_operand,
+ Operand return_value_operand, Operand* context_restore_operand) {
ExternalReference next_address =
ExternalReference::handle_scope_next_address(isolate());
ExternalReference limit_address =
if (restore_context) {
mov(esi, *context_restore_operand);
}
+ if (stack_space_operand != nullptr) {
+ mov(ebx, *stack_space_operand);
+ }
LeaveApiExitFrame(!restore_context);
- ret(stack_space * kPointerSize);
+ if (stack_space_operand != nullptr) {
+ DCHECK_EQ(0, stack_space);
+ pop(ecx);
+ add(esp, ebx);
+ jmp(ecx);
+ } else {
+ ret(stack_space * kPointerSize);
+ }
bind(&promote_scheduled_exception);
{
// stack_space * kPointerSize (GCed).
void CallApiFunctionAndReturn(Register function_address,
ExternalReference thunk_ref,
- Operand thunk_last_arg,
- int stack_space,
+ Operand thunk_last_arg, int stack_space,
+ Operand* stack_space_operand,
Operand return_value_operand,
Operand* context_restore_operand);
// Generate call to api function.
-void PropertyHandlerCompiler::GenerateFastApiCall(
+void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch_in,
- bool is_store, int argc, Register* values) {
+ bool is_store, Register store_parameter) {
DCHECK(!receiver.is(scratch_in));
__ push(receiver);
// Write the arguments to stack frame.
- for (int i = 0; i < argc; i++) {
- Register arg = values[argc - 1 - i];
- DCHECK(!receiver.is(arg));
- DCHECK(!scratch_in.is(arg));
- __ push(arg);
+ if (is_store) {
+ DCHECK(!receiver.is(store_parameter));
+ DCHECK(!scratch_in.is(store_parameter));
+ __ push(store_parameter);
}
DCHECK(optimization.is_simple_api_call());
__ mov(api_function_address, Operand(ref));
// Jump to stub.
- CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
+ CallApiAccessorStub stub(isolate, is_store, call_data_undefined);
__ TailCallStub(&stub);
}
// Generate call to api function.
-void PropertyHandlerCompiler::GenerateFastApiCall(
+void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch,
- bool is_store, int argc, Register* values) {
+ bool is_store, Register store_parameter) {
DCHECK(!AreAliased(receiver, scratch));
MacroAssembler::PushPopQueue queue(masm);
queue.Queue(receiver);
// Write the arguments to the stack frame.
- for (int i = 0; i < argc; i++) {
- Register arg = values[argc - 1 - i];
- DCHECK(!AreAliased(receiver, scratch, arg));
- queue.Queue(arg);
+ if (is_store) {
+ DCHECK(!receiver.is(store_parameter));
+ DCHECK(!scratch.is(store_parameter));
+ queue.Queue(store_parameter);
}
queue.PushQueued();
__ Mov(api_function_address, ref);
// Jump to stub.
- CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
+ CallApiAccessorStub stub(isolate, is_store, call_data_undefined);
__ TailCallStub(&stub);
}
DCHECK(call_optimization.is_simple_api_call());
Frontend(name);
Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
- GenerateFastApiCall(masm(), call_optimization, receiver_map, receiver(),
- scratch1(), false, 0, NULL);
+ GenerateApiAccessorCall(masm(), call_optimization, receiver_map, receiver(),
+ scratch1(), false, no_reg);
return GetCode(kind(), Code::FAST, name);
}
Handle<JSObject> object, Handle<Name> name,
const CallOptimization& call_optimization) {
Frontend(name);
- Register values[] = {value()};
- GenerateFastApiCall(masm(), call_optimization, handle(object->map()),
- receiver(), scratch1(), true, 1, values);
+ GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
+ receiver(), scratch1(), true, value());
return GetCode(kind(), Code::FAST, name);
}
void DiscardVectorAndSlot();
// TODO(verwaest): Make non-static.
- static void GenerateFastApiCall(MacroAssembler* masm,
- const CallOptimization& optimization,
- Handle<Map> receiver_map, Register receiver,
- Register scratch, bool is_store, int argc,
- Register* values);
+ static void GenerateApiAccessorCall(MacroAssembler* masm,
+ const CallOptimization& optimization,
+ Handle<Map> receiver_map,
+ Register receiver, Register scratch,
+ bool is_store, Register store_parameter);
// Helper function used to check that the dictionary doesn't contain
// the property. This function may return false negatives, so miss_label
// 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.
-void PropertyHandlerCompiler::GenerateFastApiCall(
+void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch_in,
- bool is_store, int argc, Register* values) {
+ bool is_store, Register store_parameter) {
// Copy return value.
__ pop(scratch_in);
// receiver
__ push(receiver);
// Write the arguments to stack frame.
- for (int i = 0; i < argc; i++) {
- Register arg = values[argc - 1 - i];
- DCHECK(!receiver.is(arg));
- DCHECK(!scratch_in.is(arg));
- __ push(arg);
+ if (is_store) {
+ DCHECK(!receiver.is(store_parameter));
+ DCHECK(!scratch_in.is(store_parameter));
+ __ push(store_parameter);
}
__ push(scratch_in);
// Stack now matches JSFunction abi.
__ mov(api_function_address, Immediate(function_address));
// Jump to stub.
- CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
+ CallApiAccessorStub stub(isolate, is_store, call_data_undefined);
__ TailCallStub(&stub);
}
// Generate call to api function.
-void PropertyHandlerCompiler::GenerateFastApiCall(
+void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch_in,
- bool is_store, int argc, Register* values) {
+ bool is_store, Register store_parameter) {
DCHECK(optimization.is_simple_api_call());
__ PopReturnAddressTo(scratch_in);
// receiver
__ Push(receiver);
// Write the arguments to stack frame.
- for (int i = 0; i < argc; i++) {
- Register arg = values[argc - 1 - i];
- DCHECK(!receiver.is(arg));
- DCHECK(!scratch_in.is(arg));
- __ Push(arg);
+ if (is_store) {
+ DCHECK(!receiver.is(store_parameter));
+ DCHECK(!scratch_in.is(store_parameter));
+ __ Push(store_parameter);
}
__ PushReturnAddressFrom(scratch_in);
// Stack now matches JSFunction abi.
RelocInfo::EXTERNAL_REFERENCE);
// Jump to stub.
- CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
+ CallApiAccessorStub stub(isolate, is_store, call_data_undefined);
__ TailCallStub(&stub);
}
V(Named) \
V(CallHandler) \
V(ArgumentAdaptor) \
- V(ApiGetter) \
V(ApiFunction) \
+ V(ApiAccessor) \
+ V(ApiGetter) \
V(ArgumentsAccessRead) \
V(StoreArrayLiteralElement) \
V(MathPowTagged) \
};
+class ApiAccessorDescriptor : public CallInterfaceDescriptor {
+ public:
+ DECLARE_DESCRIPTOR(ApiAccessorDescriptor, CallInterfaceDescriptor)
+};
+
+
class ApiGetterDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(ApiGetterDescriptor, CallInterfaceDescriptor)
}
-void CallApiFunctionStub::Generate(MacroAssembler* masm) {
+static void CallApiFunctionStubHelper(MacroAssembler* masm,
+ const ParameterCount& argc,
+ bool return_first_arg,
+ bool call_data_undefined) {
// ----------- S t a t e -------------
// -- rax : callee
// -- rbx : call_data
// -- rcx : holder
// -- rdx : api_function_address
// -- rsi : context
- // --
+ // -- rdi : number of arguments if argc is a register
// -- rsp[0] : return address
// -- rsp[8] : last argument
// -- ...
Register call_data = rbx;
Register holder = rcx;
Register api_function_address = rdx;
- Register return_address = rdi;
Register context = rsi;
- int argc = this->argc();
- bool is_store = this->is_store();
- bool call_data_undefined = this->call_data_undefined();
-
typedef FunctionCallbackArguments FCA;
STATIC_ASSERT(FCA::kContextSaveIndex == 6);
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kArgsLength == 7);
- __ PopReturnAddressTo(return_address);
+ DCHECK(argc.is_immediate() || rdi.is(argc.reg()));
- // context save
- __ Push(context);
- // load context from callee
- __ movp(context, FieldOperand(callee, JSFunction::kContextOffset));
+ if (kPointerSize == kInt64Size) {
+ // pop return address and save context
+ __ xchgq(context, Operand(rsp, 0));
+ } else {
+ // x32 handling.
+ __ PopReturnAddressTo(kScratchRegister);
+ __ Push(context);
+ __ movq(context, kScratchRegister);
+ }
// callee
__ Push(callee);
// return value default
__ Push(scratch);
// isolate
- __ Move(scratch,
- ExternalReference::isolate_address(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);
+ __ PushReturnAddressFrom(context);
+
+ // load context from callee
+ __ movp(context, FieldOperand(callee, JSFunction::kContextOffset));
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
// FunctionCallbackInfo::implicit_args_.
__ movp(StackSpaceOperand(0), scratch);
- __ addp(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 (argc.is_immediate()) {
+ __ addp(scratch, Immediate((argc.immediate() + FCA::kArgsLength - 1) *
+ kPointerSize));
+ // FunctionCallbackInfo::values_.
+ __ movp(StackSpaceOperand(1), scratch);
+ // FunctionCallbackInfo::length_.
+ __ Set(StackSpaceOperand(2), argc.immediate());
+ // FunctionCallbackInfo::is_construct_call_.
+ __ Set(StackSpaceOperand(3), 0);
+ } else {
+ __ leap(scratch, Operand(scratch, argc.reg(), times_pointer_size,
+ (FCA::kArgsLength - 1) * kPointerSize));
+ // FunctionCallbackInfo::values_.
+ __ movp(StackSpaceOperand(1), scratch);
+ // FunctionCallbackInfo::length_.
+ __ movp(StackSpaceOperand(2), argc.reg());
+ // FunctionCallbackInfo::is_construct_call_.
+ __ leap(argc.reg(), Operand(argc.reg(), times_pointer_size,
+ (FCA::kArgsLength + 1) * kPointerSize));
+ __ movp(StackSpaceOperand(3), argc.reg());
+ }
#if defined(__MINGW64__) || defined(_WIN64)
Register arguments_arg = rcx;
__ leap(arguments_arg, StackSpaceOperand(0));
ExternalReference thunk_ref =
- ExternalReference::invoke_function_callback(isolate());
+ ExternalReference::invoke_function_callback(masm->isolate());
// Accessor for FunctionCallbackInfo and first js arg.
StackArgumentsAccessor args_from_rbp(rbp, FCA::kArgsLength + 1,
ARGUMENTS_DONT_CONTAIN_RECEIVER);
Operand context_restore_operand = args_from_rbp.GetArgumentOperand(
FCA::kArgsLength - FCA::kContextSaveIndex);
- // Stores return the first js argument
+ Operand is_construct_call_operand = StackSpaceOperand(3);
Operand return_value_operand = args_from_rbp.GetArgumentOperand(
- is_store ? 0 : FCA::kArgsLength - FCA::kReturnValueOffset);
- __ CallApiFunctionAndReturn(
- api_function_address,
- thunk_ref,
- callback_arg,
- argc + FCA::kArgsLength + 1,
- return_value_operand,
- &context_restore_operand);
+ return_first_arg ? 0 : FCA::kArgsLength - FCA::kReturnValueOffset);
+ int stack_space = 0;
+ Operand* stack_space_operand = &is_construct_call_operand;
+ if (argc.is_immediate()) {
+ stack_space = argc.immediate() + FCA::kArgsLength + 1;
+ stack_space_operand = nullptr;
+ }
+ __ CallApiFunctionAndReturn(api_function_address, thunk_ref, callback_arg,
+ stack_space, stack_space_operand,
+ return_value_operand, &context_restore_operand);
+}
+
+
+void CallApiFunctionStub::Generate(MacroAssembler* masm) {
+ // TODO(dcarney): make rax contain the function address.
+ bool call_data_undefined = this->call_data_undefined();
+ CallApiFunctionStubHelper(masm, ParameterCount(rdi), false,
+ call_data_undefined);
+}
+
+
+void CallApiAccessorStub::Generate(MacroAssembler* masm) {
+ bool is_store = this->is_store();
+ int argc = is_store ? 1 : 0;
+ bool call_data_undefined = this->call_data_undefined();
+ CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store,
+ call_data_undefined);
}
Operand return_value_operand = args.GetArgumentOperand(
PropertyCallbackArguments::kArgsLength - 1 -
PropertyCallbackArguments::kReturnValueOffset);
- __ CallApiFunctionAndReturn(api_function_address,
- thunk_ref,
- getter_arg,
- kStackSpace,
- return_value_operand,
- NULL);
+ __ CallApiFunctionAndReturn(api_function_address, thunk_ref, getter_arg,
+ kStackSpace, nullptr, return_value_operand, NULL);
}
rbx, // call_data
rcx, // holder
rdx, // api_function_address
+ rdi, // actual number of arguments
+ };
+ Representation representations[] = {
+ Representation::Tagged(), // context
+ Representation::Tagged(), // callee
+ Representation::Tagged(), // call_data
+ Representation::Tagged(), // holder
+ Representation::External(), // api_function_address
+ Representation::Integer32(), // actual number of arguments
+ };
+ data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+ Register registers[] = {
+ rsi, // context
+ rax, // callee
+ rbx, // call_data
+ rcx, // holder
+ rdx, // api_function_address
};
Representation representations[] = {
Representation::Tagged(), // context
void MacroAssembler::CallApiFunctionAndReturn(
- Register function_address,
- ExternalReference thunk_ref,
- Register thunk_last_arg,
- int stack_space,
- Operand return_value_operand,
- Operand* context_restore_operand) {
+ Register function_address, ExternalReference thunk_ref,
+ Register thunk_last_arg, int stack_space, Operand* stack_space_operand,
+ Operand return_value_operand, Operand* context_restore_operand) {
Label prologue;
Label promote_scheduled_exception;
Label exception_handled;
if (restore_context) {
movp(rsi, *context_restore_operand);
}
+ if (stack_space_operand != nullptr) {
+ movp(rbx, *stack_space_operand);
+ }
LeaveApiExitFrame(!restore_context);
- ret(stack_space * kPointerSize);
+ if (stack_space_operand != nullptr) {
+ DCHECK_EQ(stack_space, 0);
+ PopReturnAddressTo(rcx);
+ addq(rsp, rbx);
+ jmp(rcx);
+ } else {
+ ret(stack_space * kPointerSize);
+ }
bind(&promote_scheduled_exception);
{
// stack_space * kPointerSize (GCed).
void CallApiFunctionAndReturn(Register function_address,
ExternalReference thunk_ref,
- Register thunk_last_arg,
- int stack_space,
+ Register thunk_last_arg, int stack_space,
+ Operand* stack_space_operand,
Operand return_value_operand,
Operand* context_restore_operand);
int ApiCallOptimizationChecker::count = 0;
-TEST(TestFunctionCallOptimization) {
+TEST(FunctionCallOptimization) {
i::FLAG_allow_natives_syntax = true;
ApiCallOptimizationChecker checker;
checker.RunAll();
}
+static void EmptyCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {}
+
+
+TEST(FunctionCallOptimizationMultipleArgs) {
+ i::FLAG_allow_natives_syntax = true;
+ LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
+ v8::HandleScope scope(isolate);
+ Handle<Object> global = context->Global();
+ Local<v8::Function> function = Function::New(isolate, EmptyCallback);
+ global->Set(v8_str("x"), function);
+ CompileRun(
+ "function x_wrap() {\n"
+ " for (var i = 0; i < 5; i++) {\n"
+ " x(1,2,3);\n"
+ " }\n"
+ "}\n"
+ "x_wrap();\n"
+ "%OptimizeFunctionOnNextCall(x_wrap);"
+ "x_wrap();\n");
+}
+
+
static const char* last_event_message;
static int last_event_status;
void StoringEventLoggerCallback(const char* message, int status) {