[Interpreter] Implements calls through CallICStub in the interpreter.

Calls are implemented through CallICStub to collect type feedback. Adds
a new builtin called InterpreterPushArgsAndCallIC that pushes the
arguments onto stack and calls CallICStub.

Also adds two new bytecodes CallIC and CallICWide to indicate calls have to
go through CallICStub.

MIPS port contributed by balazs.kilvady.

BUG=v8:4280, v8:4680
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#34244}
This commit is contained in:
mythria 2016-02-24 03:00:51 -08:00 committed by Commit bot
parent 6cc5c601b6
commit 20362a2214
42 changed files with 1142 additions and 278 deletions

View File

@ -976,6 +976,46 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, Register index,
__ b(gt, &loop_header);
}
static void Generate_InterpreterComputeLastArgumentAddress(
MacroAssembler* masm, Register num_args, Register start_address,
Register output_reg) {
__ add(output_reg, num_args, Operand(1)); // Add one for receiver.
__ mov(output_reg, Operand(output_reg, LSL, kPointerSizeLog2));
__ sub(output_reg, start_address, output_reg);
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallICImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r4 : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -- r1 : the target to call (can be any Object).
// -- r3 : feedback vector slot id
// -- r2 : type feedback vector
// -----------------------------------
{
FrameScope scope(masm, StackFrame::INTERNAL);
// Find the address of the last argument.
Generate_InterpreterComputeLastArgumentAddress(masm, r0, r4, r5);
// Push the arguments.
Generate_InterpreterPushArgs(masm, r4, r5, r6);
// Call via the CallIC stub.
CallICState call_ic_state(0, ConvertReceiverMode::kAny, tail_call_mode,
true);
CallICStub stub(masm->isolate(), call_ic_state);
// TODO(mythria): This should be replaced by a TailCallStub, when we
// update the code to find the target IC from jump instructions.
__ CallStub(&stub);
}
__ Ret();
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
@ -989,9 +1029,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// -----------------------------------
// Find the address of the last argument.
__ add(r3, r0, Operand(1)); // Add one for receiver.
__ mov(r3, Operand(r3, LSL, kPointerSizeLog2));
__ sub(r3, r2, r3);
Generate_InterpreterComputeLastArgumentAddress(masm, r0, r2, r3);
// Push the arguments.
Generate_InterpreterPushArgs(masm, r2, r3, r4);
@ -1942,6 +1980,17 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ cmp(scratch1, Operand(0));
__ b(ne, &done);
// Drop possible internal frame pushed for calling CallICStub.
// TODO(mythria): when we tail call the CallICStub, remove this.
{
Label no_internal_callic_frame;
__ ldr(scratch3, MemOperand(fp, StandardFrameConstants::kMarkerOffset));
__ cmp(scratch3, Operand(Smi::FromInt(StackFrame::INTERNAL)));
__ b(ne, &no_internal_callic_frame);
__ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_internal_callic_frame);
}
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;

View File

@ -2067,8 +2067,6 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ cmp(r1, r5);
__ b(ne, miss);
__ mov(r0, Operand(arg_count()));
// Increment the call count for monomorphic function calls.
__ add(r2, r2, Operand::PointerOffsetFromSmiKey(r3));
__ add(r2, r2, Operand(FixedArray::kHeaderSize + kPointerSize));
@ -2078,18 +2076,30 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ mov(r2, r4);
__ mov(r3, r1);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
if (argc_in_register()) {
// Pass a default ArgumentCountKey::Any since the argc is only available
// in r0. We do not have the actual count here.
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
} else {
// arg_count() is expected in r0 if the arg_count() >= 2
// (ArgumentCountKey::MORE_THAN_ONE).
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
}
}
void CallICStub::Generate(MacroAssembler* masm) {
// r0 - number of arguments if argc_in_register() is true
// r1 - function
// r3 - slot id (Smi)
// r2 - vector
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
ParameterCount actual(argc);
if (!argc_in_register()) {
int argc = arg_count();
__ mov(r0, Operand(argc));
}
// The checks. First, does r1 match the recorded monomorphic target?
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
@ -2125,7 +2135,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ str(r3, FieldMemOperand(r2, 0));
__ bind(&call_function);
__ mov(r0, Operand(argc));
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
RelocInfo::CODE_TARGET);
@ -2165,7 +2174,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
__ bind(&call);
__ mov(r0, Operand(argc));
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET);
@ -2203,9 +2211,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(masm->isolate());
__ SmiTag(r0);
__ Push(r0);
__ Push(r1);
__ CallStub(&create_stub);
__ Pop(r1);
__ Pop(r0);
__ SmiUntag(r0);
}
__ jmp(&call_function);
@ -2222,6 +2234,10 @@ void CallICStub::Generate(MacroAssembler* masm) {
void CallICStub::GenerateMiss(MacroAssembler* masm) {
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Store the number of arguments that is required later.
__ SmiTag(r0);
__ Push(r0);
// Push the receiver and the function and feedback info.
__ Push(r1, r2, r3);
@ -2230,6 +2246,10 @@ void CallICStub::GenerateMiss(MacroAssembler* masm) {
// Move result to edi and exit the internal frame.
__ mov(r1, r0);
// Restore back the number of arguments to r0.
__ Pop(r0);
__ SmiUntag(r0);
}

View File

@ -443,6 +443,18 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallICDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
r0, // argument count (not including receiver)
r4, // address of first argument
r1, // the target callable to be call
r3, // slot id
r2 // type feedback vector
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {

View File

@ -1981,6 +1981,17 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ Cmp(scratch1, Operand(0));
__ B(ne, &done);
// Drop possible internal frame pushed for calling CallICStub.
// TODO(mythria): when we tail call the CallICStub, remove this.
{
Label no_internal_callic_frame;
__ Ldr(scratch3, MemOperand(fp, StandardFrameConstants::kMarkerOffset));
__ Cmp(scratch3, Operand(Smi::FromInt(StackFrame::INTERNAL)));
__ B(ne, &no_internal_callic_frame);
__ Ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_internal_callic_frame);
}
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
@ -2464,6 +2475,57 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
RelocInfo::CODE_TARGET);
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args,
Register start_addr) {
// Find the address of the last argument.
__ add(x5, num_args, Operand(1)); // Add one for receiver.
__ lsl(x5, x5, kPointerSizeLog2);
__ sub(x6, start_addr, x5);
// Push the arguments.
Label loop_header, loop_check;
__ Mov(x7, jssp);
__ Claim(x5, 1);
__ B(&loop_check);
__ Bind(&loop_header);
// TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
__ Ldr(x5, MemOperand(start_addr, -kPointerSize, PostIndex));
__ Str(x5, MemOperand(x7, -kPointerSize, PreIndex));
__ Bind(&loop_check);
__ Cmp(start_addr, x6);
__ B(gt, &loop_header);
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallICImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x4 : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -- x1 : the target to call (can be any Object).
// -- x3 : feedback vector slot id
// -- x2 : type feedback vector
// -----------------------------------
{
FrameScope scope(masm, StackFrame::INTERNAL);
// Push arguments to stack. Clobbers x5-x7 registers.
Generate_InterpreterPushArgs(masm, x0, x4);
// Call via the CallIC stub.
CallICState call_ic_state(0, ConvertReceiverMode::kAny, tail_call_mode,
true);
CallICStub stub(masm->isolate(), call_ic_state);
// TODO(mythria): This should be replaced by a TailCallStub, when we
// update the code to find the target IC from jump instructions.
__ CallStub(&stub);
}
__ Ret();
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
@ -2476,23 +2538,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// -- x1 : the target to call (can be any Object).
// -----------------------------------
// Find the address of the last argument.
__ add(x3, x0, Operand(1)); // Add one for receiver.
__ lsl(x3, x3, kPointerSizeLog2);
__ sub(x4, x2, x3);
// Push the arguments.
Label loop_header, loop_check;
__ Mov(x5, jssp);
__ Claim(x3, 1);
__ B(&loop_check);
__ Bind(&loop_header);
// TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
__ Ldr(x3, MemOperand(x2, -kPointerSize, PostIndex));
__ Str(x3, MemOperand(x5, -kPointerSize, PreIndex));
__ Bind(&loop_check);
__ Cmp(x2, x4);
__ B(gt, &loop_header);
// Push arguments to stack. Clobbers x5-x7 registers.
Generate_InterpreterPushArgs(masm, x0, x2);
// Call the target.
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,

View File

@ -2289,6 +2289,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// x0 - number of arguments
// x1 - function
// x3 - slot id
// x2 - vector
@ -2303,8 +2304,6 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ Cmp(function, scratch);
__ B(ne, miss);
__ Mov(x0, Operand(arg_count()));
// Increment the call count for monomorphic function calls.
__ Add(feedback_vector, feedback_vector,
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
@ -2319,20 +2318,31 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
Register new_target_arg = index;
__ Mov(allocation_site_arg, allocation_site);
__ Mov(new_target_arg, function);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
if (argc_in_register()) {
// Pass a default ArgumentCountKey::Any since the argc is only available
// in r0. We do not have the actual count here.
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
} else {
// arg_count() is expected in r0 if the arg_count() >= 2
// (ArgumentCountKey::MORE_THAN_ONE).
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
}
}
void CallICStub::Generate(MacroAssembler* masm) {
ASM_LOCATION("CallICStub");
// x0 - number of arguments if argc_in_register() is true
// x1 - function
// x3 - slot id (Smi)
// x2 - vector
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
ParameterCount actual(argc);
if (!argc_in_register()) {
__ Mov(x0, arg_count());
}
Register function = x1;
Register feedback_vector = x2;
@ -2375,7 +2385,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ Str(index, FieldMemOperand(feedback_vector, 0));
__ Bind(&call_function);
__ Mov(x0, argc);
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
RelocInfo::CODE_TARGET);
@ -2410,7 +2419,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize));
__ Bind(&call);
__ Mov(x0, argc);
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET);
@ -2448,9 +2456,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(masm->isolate());
__ SmiTag(x0);
__ Push(x0);
__ Push(function);
__ CallStub(&create_stub);
__ Pop(function);
__ Pop(x0);
__ SmiUntag(x0);
}
__ B(&call_function);
@ -2469,6 +2481,10 @@ void CallICStub::GenerateMiss(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::INTERNAL);
// Store number of arguments.
__ SmiTag(x0);
__ Push(x0);
// Push the receiver and the function and feedback info.
__ Push(x1, x2, x3);
@ -2477,6 +2493,10 @@ void CallICStub::GenerateMiss(MacroAssembler* masm) {
// Move result to edi and exit the internal frame.
__ Mov(x1, x0);
// Restore number of arguments.
__ Pop(x0);
__ SmiUntag(x0);
}

View File

@ -478,6 +478,18 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallICDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
x0, // argument count (not including receiver)
x4, // address of first argument
x1, // the target callable to be call
x3, // slot id
x2 // type feedback vector
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {

View File

@ -3999,6 +3999,18 @@ Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode) {
return Handle<Code>::null();
}
Handle<Code> Builtins::InterpreterPushArgsAndCallIC(
TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
return InterpreterPushArgsAndCallIC();
case TailCallMode::kAllow:
return InterpreterPushArgsAndTailCallIC();
}
UNREACHABLE();
return Handle<Code>::null();
}
namespace {
class RelocatableArguments

View File

@ -216,6 +216,8 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
\
V(InterpreterEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterExitTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterPushArgsAndCallIC, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterPushArgsAndTailCallIC, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterPushArgsAndCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterPushArgsAndTailCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterPushArgsAndConstruct, BUILTIN, UNINITIALIZED, kNoExtraICState) \
@ -367,6 +369,7 @@ class Builtins {
TailCallMode tail_call_mode = TailCallMode::kDisallow);
Handle<Code> CallBoundFunction(TailCallMode tail_call_mode);
Handle<Code> InterpreterPushArgsAndCall(TailCallMode tail_call_mode);
Handle<Code> InterpreterPushArgsAndCallIC(TailCallMode tail_call_mode);
Code* builtin(Name name) {
// Code::cast cannot be used here since we access builtins
@ -582,6 +585,16 @@ class Builtins {
static void Generate_InterpreterEntryTrampoline(MacroAssembler* masm);
static void Generate_InterpreterExitTrampoline(MacroAssembler* masm);
static void Generate_InterpreterPushArgsAndCallIC(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallICImpl(masm,
TailCallMode::kDisallow);
}
static void Generate_InterpreterPushArgsAndTailCallIC(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallICImpl(masm,
TailCallMode::kAllow);
}
static void Generate_InterpreterPushArgsAndCallICImpl(
MacroAssembler* masm, TailCallMode tail_call_mode);
static void Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm,
TailCallMode::kDisallow);

View File

@ -345,6 +345,13 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) {
ConstructTrampolineDescriptor(isolate));
}
// static
Callable CodeFactory::InterpreterPushArgsAndCallIC(
Isolate* isolate, TailCallMode tail_call_mode) {
return Callable(
isolate->builtins()->InterpreterPushArgsAndCallIC(tail_call_mode),
InterpreterPushArgsAndCallICDescriptor(isolate));
}
// static
Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
@ -354,7 +361,6 @@ Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
InterpreterPushArgsAndCallDescriptor(isolate));
}
// static
Callable CodeFactory::InterpreterPushArgsAndConstruct(Isolate* isolate) {
return Callable(isolate->builtins()->InterpreterPushArgsAndConstruct(),

View File

@ -106,6 +106,8 @@ class CodeFactory final {
static Callable Construct(Isolate* isolate);
static Callable ConstructFunction(Isolate* isolate);
static Callable InterpreterPushArgsAndCallIC(Isolate* isolate,
TailCallMode tail_call_mode);
static Callable InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate);

View File

@ -973,9 +973,13 @@ class CallICStub: public PlatformCodeStub {
}
protected:
int arg_count() const { return state().argc(); }
int arg_count() const {
DCHECK(!argc_in_register());
return state().argc();
}
ConvertReceiverMode convert_mode() const { return state().convert_mode(); }
TailCallMode tail_call_mode() const { return state().tail_call_mode(); }
bool argc_in_register() const { return state().argc_in_register(); }
CallICState state() const {
return CallICState(static_cast<ExtraICState>(minor_key_));

View File

@ -501,10 +501,7 @@ Node* BytecodeGraphBuilder::BuildLoadNativeContextField(int index) {
VectorSlotPair BytecodeGraphBuilder::CreateVectorSlotPair(int slot_id) {
FeedbackVectorSlot slot;
if (slot_id >= TypeFeedbackVector::kReservedIndexCount) {
slot = feedback_vector()->ToSlot(slot_id);
}
FeedbackVectorSlot slot = feedback_vector()->ToSlot(slot_id);
return VectorSlotPair(feedback_vector(), slot);
}
@ -992,6 +989,42 @@ Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
return value;
}
void BytecodeGraphBuilder::BuildCallWithFeedbackSlot(
TailCallMode tail_call_mode) {
FrameStateBeforeAndAfter states(this);
// TODO(rmcilroy): Set receiver_hint correctly based on whether the receiver
// register has been loaded with null / undefined explicitly or we are sure it
// is not null / undefined.
ConvertReceiverMode receiver_hint = ConvertReceiverMode::kAny;
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
int slot_id = bytecode_iterator().GetIndexOperand(3);
VectorSlotPair feedback = CreateVectorSlotPair(slot_id);
const Operator* call = javascript()->CallFunction(
arg_count + 1, feedback, receiver_hint, tail_call_mode);
Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1);
environment()->BindAccumulator(value, &states);
}
void BytecodeGraphBuilder::VisitCallIC() {
BuildCallWithFeedbackSlot(TailCallMode::kDisallow);
}
void BytecodeGraphBuilder::VisitCallICWide() {
BuildCallWithFeedbackSlot(TailCallMode::kDisallow);
}
void BytecodeGraphBuilder::VisitTailCallIC() {
BuildCallWithFeedbackSlot(TailCallMode::kAllow);
}
void BytecodeGraphBuilder::VisitTailCallICWide() {
BuildCallWithFeedbackSlot(TailCallMode::kAllow);
}
void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode) {
FrameStateBeforeAndAfter states(this);
// TODO(rmcilroy): Set receiver_hint correctly based on whether the receiver
@ -1002,11 +1035,9 @@ void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode) {
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(3));
const Operator* call = javascript()->CallFunction(
arg_count + 1, feedback, receiver_hint, tail_call_mode);
arg_count + 1, VectorSlotPair(), receiver_hint, tail_call_mode);
Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1);
environment()->BindAccumulator(value, &states);
}

View File

@ -124,6 +124,7 @@ class BytecodeGraphBuilder {
void BuildLdaLookupSlot(TypeofMode typeof_mode);
void BuildStaLookupSlot(LanguageMode language_mode);
void BuildCall(TailCallMode tail_call_mode);
void BuildCallWithFeedbackSlot(TailCallMode tail_call_mode);
void BuildCallJSRuntime();
void BuildCallRuntime();
void BuildCallRuntimeForPair();

View File

@ -559,6 +559,58 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
__ j(greater, &loop_header, Label::kNear);
}
static void Generate_InterpreterComputeLastArgumentAddress(MacroAssembler* masm,
Register r) {
// Find the address of the last argument.
// ----------- S t a t e -------------
// input: eax : Number of arguments.
// input: ebx : Address of the first argument.
// output: Register |r|: Address of the last argument.
// -----------------------------------
__ mov(r, eax);
__ add(r, Immediate(1)); // Add one for receiver.
__ shl(r, kPointerSizeLog2);
__ neg(r);
__ add(r, ebx);
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallICImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- ebx : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -- edi : the target to call (can be any Object).
// -- edx : feedback slot id.
// -- ecx : type feedback vector.
// -----------------------------------
{
FrameScope scope(masm, StackFrame::INTERNAL);
// Store type feedback vector on the stack since we ran out of registers.
__ Push(ecx);
// computes the address of last argument in ecx.
// ecx = ebx - (eax + 1) * kPointerSize.
Generate_InterpreterComputeLastArgumentAddress(masm, ecx);
Generate_InterpreterPushArgs(masm, ecx);
// Restore feedback vector to ebx from the stack. It was pushed
// before the arguments were pushed, so compute the correct offset.
__ mov(ebx, Operand(esp, eax, times_pointer_size, 1 * kPointerSize));
// Call via the CallIC stub.
CallICState call_ic_state(0, ConvertReceiverMode::kAny, tail_call_mode,
true);
CallICStub stub(masm->isolate(), call_ic_state);
// TODO(mythria): This should be replaced by a TailCallStub, when we
// update the code to find the target IC from jump instructions.
__ CallStub(&stub);
}
__ Ret();
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
@ -574,13 +626,9 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// Pop return address to allow tail-call after pushing arguments.
__ Pop(edx);
// Find the address of the last argument.
__ mov(ecx, eax);
__ add(ecx, Immediate(1)); // Add one for receiver.
__ shl(ecx, kPointerSizeLog2);
__ neg(ecx);
__ add(ecx, ebx);
// computes the address of last argument in ecx.
// ecx = ebx - (eax + 1) * kPointerSize.
Generate_InterpreterComputeLastArgumentAddress(masm, ecx);
Generate_InterpreterPushArgs(masm, ecx);
// Call the target.
@ -590,7 +638,6 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
RelocInfo::CODE_TARGET);
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
// ----------- S t a t e -------------
@ -602,27 +649,24 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
// they are to be pushed onto the stack.
// -----------------------------------
// Save number of arguments on the stack below where arguments are going
// to be pushed.
__ mov(ecx, eax);
__ neg(ecx);
__ mov(Operand(esp, ecx, times_pointer_size, -kPointerSize), eax);
__ mov(eax, ecx);
// Pop return address to allow tail-call after pushing arguments.
__ Pop(ecx);
// Push edi in the slot meant for receiver. We need an extra register so
// store edi temporarily on the stack.
__ Push(edi);
// Find the address of the last argument.
__ shl(eax, kPointerSizeLog2);
__ add(eax, ebx);
__ mov(edi, eax);
__ neg(edi);
__ shl(edi, kPointerSizeLog2);
__ add(edi, ebx);
// Push padding for receiver.
__ Push(Immediate(0));
Generate_InterpreterPushArgs(masm, edi);
Generate_InterpreterPushArgs(masm, eax);
// Restore number of arguments from slot on stack.
__ mov(eax, Operand(esp, -kPointerSize));
// Restore number of arguments from slot on stack. edi was pushed at
// the slot meant for receiver.
__ mov(edi, Operand(esp, eax, times_pointer_size, 0));
// Re-push return address.
__ Push(ecx);
@ -1873,6 +1917,17 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ cmp(scratch1, Immediate(0));
__ j(not_equal, &done, Label::kNear);
// Drop possible internal frame pushed for calling CallICStub.
// TODO(mythria): when we tail call the CallICStub, remove this.
{
Label no_internal_callic_frame;
__ cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
Immediate(Smi::FromInt(StackFrame::INTERNAL)));
__ j(not_equal, &no_internal_callic_frame, Label::kNear);
__ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_internal_callic_frame);
}
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;

View File

@ -1624,11 +1624,11 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// edi - function
// edx - slot id
// ebx - vector
// eax - number of arguments - if argc_in_register() is true.
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx);
__ cmp(edi, ecx);
__ j(not_equal, miss);
__ mov(eax, arg_count());
// Reload ecx.
__ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize));
@ -1640,9 +1640,17 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ mov(ebx, ecx);
__ mov(edx, edi);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
if (argc_in_register()) {
// Pass a default ArgumentCountKey::Any since the argc is only available
// in eax. We do not have the actual count here.
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
} else {
// arg_count() is expected in rax if the arg_count() >= 2
// (ArgumentCountKey::MORE_THAN_ONE).
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
}
// Unreachable.
}
@ -1651,10 +1659,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
// edi - function
// edx - slot id
// ebx - vector
// eax - number of arguments - if argc_in_register() is true.
Isolate* isolate = masm->isolate();
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
ParameterCount actual(argc);
if (!argc_in_register()) {
int argc = arg_count();
__ Set(eax, argc);
}
// The checks. First, does edi match the recorded monomorphic target?
__ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
@ -1687,7 +1698,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
Immediate(Smi::FromInt(CallICNexus::kCallCountIncrement)));
__ bind(&call_function);
__ Set(eax, argc);
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
RelocInfo::CODE_TARGET);
@ -1727,7 +1737,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
__ bind(&call);
__ Set(eax, argc);
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET);
@ -1764,9 +1773,15 @@ void CallICStub::Generate(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(isolate);
__ SmiTag(eax);
__ push(eax);
__ push(edi);
__ CallStub(&create_stub);
__ pop(edi);
__ pop(eax);
__ SmiUntag(eax);
}
__ jmp(&call_function);
@ -1786,6 +1801,9 @@ void CallICStub::Generate(MacroAssembler* masm) {
void CallICStub::GenerateMiss(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::INTERNAL);
// Store eax since we need it later.
__ SmiTag(eax);
__ push(eax);
// Push the function and feedback info.
__ push(edi);
__ push(ebx);
@ -1796,6 +1814,10 @@ void CallICStub::GenerateMiss(MacroAssembler* masm) {
// Move result to edi and exit the internal frame.
__ mov(edi, eax);
// Restore eax.
__ pop(eax);
__ SmiUntag(eax);
}

View File

@ -433,6 +433,18 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallICDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
eax, // argument count (not including receiver)
ebx, // address of first argument
edi, // the target callable to be call
edx, // feedback vector slot id
ecx // type feedback vector
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {

View File

@ -26,10 +26,11 @@ class CallICState final BASE_EMBEDDED {
explicit CallICState(ExtraICState extra_ic_state)
: bit_field_(extra_ic_state) {}
CallICState(int argc, ConvertReceiverMode convert_mode,
TailCallMode tail_call_mode)
TailCallMode tail_call_mode, bool is_argc_in_reg = false)
: bit_field_(ArgcBits::encode(argc) |
ConvertModeBits::encode(convert_mode) |
TailCallModeBits::encode(tail_call_mode)) {}
TailCallModeBits::encode(tail_call_mode) |
ArgcInRegBits::encode(is_argc_in_reg)) {}
ExtraICState GetExtraICState() const { return bit_field_; }
@ -44,11 +45,13 @@ class CallICState final BASE_EMBEDDED {
TailCallMode tail_call_mode() const {
return TailCallModeBits::decode(bit_field_);
}
bool argc_in_register() { return ArgcInRegBits::decode(bit_field_); }
private:
typedef BitField<int, 0, Code::kArgumentsBits> ArgcBits;
typedef BitField<ConvertReceiverMode, ArgcBits::kNext, 2> ConvertModeBits;
typedef BitField<TailCallMode, ConvertModeBits::kNext, 1> TailCallModeBits;
typedef BitField<bool, TailCallModeBits::kNext, 1> ArgcInRegBits;
int const bit_field_;
};

View File

@ -78,6 +78,7 @@ class PlatformInterfaceDescriptor;
V(GrowArrayElements) \
V(InterpreterDispatch) \
V(InterpreterPushArgsAndCall) \
V(InterpreterPushArgsAndCallIC) \
V(InterpreterPushArgsAndConstruct) \
V(InterpreterCEntry)
@ -757,13 +758,18 @@ class InterpreterDispatchDescriptor : public CallInterfaceDescriptor {
static const int kContextParameter = 5;
};
class InterpreterPushArgsAndCallICDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(InterpreterPushArgsAndCallICDescriptor,
CallInterfaceDescriptor)
};
class InterpreterPushArgsAndCallDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(InterpreterPushArgsAndCallDescriptor,
CallInterfaceDescriptor)
};
class InterpreterPushArgsAndConstructDescriptor
: public CallInterfaceDescriptor {
public:

View File

@ -1059,12 +1059,10 @@ void BytecodeArrayBuilder::EnsureReturn(FunctionLiteral* literal) {
}
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
Register receiver_args,
size_t receiver_args_count,
int feedback_slot,
TailCallMode tail_call_mode) {
Bytecode bytecode = BytecodeForCall(tail_call_mode);
BytecodeArrayBuilder& BytecodeArrayBuilder::CallIC(
Register callable, Register receiver_args, size_t receiver_args_count,
int feedback_slot, TailCallMode tail_call_mode) {
Bytecode bytecode = BytecodeForCallIC(tail_call_mode);
if (FitsInReg8Operand(callable) && FitsInReg8Operand(receiver_args) &&
FitsInIdx8Operand(receiver_args_count) &&
FitsInIdx8Operand(feedback_slot)) {
@ -1085,6 +1083,26 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
Register receiver_args,
size_t receiver_args_count,
TailCallMode tail_call_mode) {
Bytecode bytecode = BytecodeForCall(tail_call_mode);
if (FitsInReg8Operand(callable) && FitsInReg8Operand(receiver_args) &&
FitsInIdx8Operand(receiver_args_count)) {
Output(bytecode, callable.ToRawOperand(), receiver_args.ToRawOperand(),
static_cast<uint8_t>(receiver_args_count));
} else if (FitsInReg16Operand(callable) &&
FitsInReg16Operand(receiver_args) &&
FitsInIdx16Operand(receiver_args_count)) {
bytecode = BytecodeForWideOperands(bytecode);
Output(bytecode, callable.ToRawOperand(), receiver_args.ToRawOperand(),
static_cast<uint16_t>(receiver_args_count));
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
Register first_arg,
size_t arg_count) {
@ -1426,6 +1444,10 @@ Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
// static
Bytecode BytecodeArrayBuilder::BytecodeForWideOperands(Bytecode bytecode) {
switch (bytecode) {
case Bytecode::kCallIC:
return Bytecode::kCallICWide;
case Bytecode::kTailCallIC:
return Bytecode::kTailCallICWide;
case Bytecode::kCall:
return Bytecode::kCallWide;
case Bytecode::kTailCall:
@ -1569,6 +1591,19 @@ Bytecode BytecodeArrayBuilder::BytecodeForDelete(LanguageMode language_mode) {
return static_cast<Bytecode>(-1);
}
// static
Bytecode BytecodeArrayBuilder::BytecodeForCallIC(TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
return Bytecode::kCallIC;
case TailCallMode::kAllow:
return Bytecode::kTailCallIC;
default:
UNREACHABLE();
}
return static_cast<Bytecode>(-1);
}
// static
Bytecode BytecodeArrayBuilder::BytecodeForCall(TailCallMode tail_call_mode) {
switch (tail_call_mode) {

View File

@ -163,18 +163,28 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
// <receiver_args + receiver_arg_count - 1>.
BytecodeArrayBuilder& Call(
Register callable, Register receiver_args, size_t receiver_arg_count,
int feedback_slot, TailCallMode tail_call_mode = TailCallMode::kDisallow);
TailCallMode tail_call_mode = TailCallMode::kDisallow);
BytecodeArrayBuilder& TailCall(Register callable, Register receiver_args,
size_t receiver_arg_count, int feedback_slot) {
return Call(callable, receiver_args, receiver_arg_count, feedback_slot,
size_t receiver_arg_count) {
return Call(callable, receiver_args, receiver_arg_count,
TailCallMode::kAllow);
}
// Call a JS function. The JSFunction or Callable to be called should be in
// |callable|, the receiver should be in |receiver_args| and all subsequent
// arguments should be in registers <receiver_args + 1> to
// <receiver_args + receiver_arg_count - 1>.
// Call through CallICStub to get Typefeedback.
BytecodeArrayBuilder& CallIC(Register callable, Register receiver_args,
size_t receiver_arg_count, int feedback_slot,
TailCallMode tail_call_mode);
// Call the new operator. The accumulator holds the |new_target|.
// The |constructor| is in a register followed by |arg_count|
// consecutive arguments starting at |first_arg| for the constuctor
// invocation.
BytecodeArrayBuilder& New(Register constructor, Register first_arg,
size_t arg_count);
@ -287,6 +297,7 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
static Bytecode BytecodeForCreateArguments(CreateArgumentsType type);
static Bytecode BytecodeForDelete(LanguageMode language_mode);
static Bytecode BytecodeForCall(TailCallMode tail_call_mode);
static Bytecode BytecodeForCallIC(TailCallMode tail_call_mode);
static bool FitsInIdx8Operand(int value);
static bool FitsInIdx8Operand(size_t value);

View File

@ -2457,9 +2457,15 @@ void BytecodeGenerator::VisitCall(Call* expr) {
}
builder()->SetExpressionPosition(expr);
builder()->Call(callee, receiver, 1 + args->length(),
feedback_index(expr->CallFeedbackICSlot()),
expr->tail_call_mode());
if (expr->CallFeedbackICSlot().IsInvalid()) {
builder()->Call(callee, receiver, 1 + args->length(),
expr->tail_call_mode());
} else {
DCHECK(call_type != Call::POSSIBLY_EVAL_CALL);
builder()->CallIC(callee, receiver, 1 + args->length(),
feedback_index(expr->CallFeedbackICSlot()),
expr->tail_call_mode());
}
execution_result()->SetResultInAccumulator();
}

View File

@ -278,8 +278,10 @@ bool Bytecodes::IsJump(Bytecode bytecode) {
// static
bool Bytecodes::IsCallOrNew(Bytecode bytecode) {
return bytecode == Bytecode::kCall || bytecode == Bytecode::kTailCall ||
bytecode == Bytecode::kNew || bytecode == Bytecode::kCallWide ||
bytecode == Bytecode::kTailCallWide || bytecode == Bytecode::kNewWide;
bytecode == Bytecode::kNew || bytecode == Bytecode::kCallIC ||
bytecode == Bytecode::kCallWide ||
bytecode == Bytecode::kTailCallWide ||
bytecode == Bytecode::kNewWide || bytecode == Bytecode::kCallICWide;
}
// static

View File

@ -169,14 +169,20 @@ namespace interpreter {
V(DeletePropertySloppy, OperandType::kReg8) \
\
/* Call operations */ \
V(Call, OperandType::kReg8, OperandType::kReg8, OperandType::kRegCount8, \
V(CallIC, OperandType::kReg8, OperandType::kReg8, OperandType::kRegCount8, \
OperandType::kIdx8) \
V(CallICWide, OperandType::kReg16, OperandType::kReg16, \
OperandType::kRegCount16, OperandType::kIdx16) \
V(TailCallIC, OperandType::kReg8, OperandType::kReg8, \
OperandType::kRegCount8, OperandType::kIdx8) \
V(TailCallICWide, OperandType::kReg16, OperandType::kReg16, \
OperandType::kRegCount16, OperandType::kIdx16) \
V(Call, OperandType::kReg8, OperandType::kReg8, OperandType::kRegCount8) \
V(CallWide, OperandType::kReg16, OperandType::kReg16, \
OperandType::kRegCount16, OperandType::kIdx16) \
V(TailCall, OperandType::kReg8, OperandType::kReg8, OperandType::kRegCount8, \
OperandType::kIdx8) \
OperandType::kRegCount16) \
V(TailCall, OperandType::kReg8, OperandType::kReg8, OperandType::kRegCount8) \
V(TailCallWide, OperandType::kReg16, OperandType::kReg16, \
OperandType::kRegCount16, OperandType::kIdx16) \
OperandType::kRegCount16) \
V(CallRuntime, OperandType::kIdx16, OperandType::kMaybeReg8, \
OperandType::kRegCount8) \
V(CallRuntimeWide, OperandType::kIdx16, OperandType::kMaybeReg16, \

View File

@ -345,6 +345,19 @@ Node* InterpreterAssembler::CallJS(Node* function, Node* context,
first_arg, function);
}
Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Node* first_arg, Node* arg_count,
Node* slot_id,
Node* type_feedback_vector,
TailCallMode tail_call_mode) {
Callable callable =
CodeFactory::InterpreterPushArgsAndCallIC(isolate(), tail_call_mode);
Node* code_target = HeapConstant(callable.code());
return CallStub(callable.descriptor(), code_target, context, arg_count,
first_arg, function, slot_id, type_feedback_vector);
}
Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
Node* new_target, Node* first_arg,
Node* arg_count) {

View File

@ -87,6 +87,18 @@ class InterpreterAssembler : public compiler::CodeStubAssembler {
compiler::Node* first_arg, compiler::Node* arg_count,
TailCallMode tail_call_mode);
// Call JSFunction or Callable |function| with |arg_count|
// arguments (not including receiver) and the first argument
// located at |first_arg| with feedback slot id |slot_id| and
// type feedback vector |type_feedback_vector|.
compiler::Node* CallJSWithFeedback(compiler::Node* function,
compiler::Node* context,
compiler::Node* first_arg,
compiler::Node* arg_count,
compiler::Node* slot_id,
compiler::Node* type_feedback_vector,
TailCallMode tail_call_mode);
// Call constructor |constructor| with |arg_count| arguments (not
// including receiver) and the first argument located at
// |first_arg|. The |new_target| is the same as the

View File

@ -934,6 +934,58 @@ void Interpreter::DoDeletePropertySloppy(InterpreterAssembler* assembler) {
DoDelete(Runtime::kDeleteProperty_Sloppy, assembler);
}
void Interpreter::DoJSCallWithFeedback(InterpreterAssembler* assembler,
TailCallMode tail_call_mode) {
Node* function_reg = __ BytecodeOperandReg(0);
Node* function = __ LoadRegister(function_reg);
Node* receiver_reg = __ BytecodeOperandReg(1);
Node* receiver_arg = __ RegisterLocation(receiver_reg);
Node* receiver_args_count = __ BytecodeOperandCount(2);
Node* receiver_count = __ Int32Constant(1);
Node* args_count = __ Int32Sub(receiver_args_count, receiver_count);
Node* slot_id_raw = __ BytecodeOperandIdx(3);
Node* slot_id = __ SmiTag(slot_id_raw);
Node* type_feedback_vector = __ LoadTypeFeedbackVector();
Node* context = __ GetContext();
Node* result =
__ CallJSWithFeedback(function, context, receiver_arg, args_count,
slot_id, type_feedback_vector, tail_call_mode);
__ SetAccumulator(result);
__ Dispatch();
}
// Call <callable> <receiver> <arg_count>
//
// Call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers.
void Interpreter::DoCallIC(InterpreterAssembler* assembler) {
DoJSCallWithFeedback(assembler, TailCallMode::kDisallow);
}
// CallWide <callable> <receiver> <arg_count>
//
// Call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers.
void Interpreter::DoCallICWide(InterpreterAssembler* assembler) {
DoJSCallWithFeedback(assembler, TailCallMode::kDisallow);
}
// Call <callable> <receiver> <arg_count>
//
// Call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers.
void Interpreter::DoTailCallIC(InterpreterAssembler* assembler) {
DoJSCallWithFeedback(assembler, TailCallMode::kAllow);
}
// CallWide <callable> <receiver> <arg_count>
//
// Call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers.
void Interpreter::DoTailCallICWide(InterpreterAssembler* assembler) {
DoJSCallWithFeedback(assembler, TailCallMode::kAllow);
}
void Interpreter::DoJSCall(InterpreterAssembler* assembler,
TailCallMode tail_call_mode) {
Node* function_reg = __ BytecodeOperandReg(0);
@ -944,7 +996,6 @@ void Interpreter::DoJSCall(InterpreterAssembler* assembler,
Node* receiver_count = __ Int32Constant(1);
Node* args_count = __ Int32Sub(receiver_args_count, receiver_count);
Node* context = __ GetContext();
// TODO(rmcilroy): Use the call type feedback slot to call via CallStub.
Node* result =
__ CallJS(function, context, receiver_arg, args_count, tail_call_mode);
__ SetAccumulator(result);

View File

@ -94,6 +94,10 @@ class Interpreter {
// Generates code to perform a JS call.
void DoJSCall(InterpreterAssembler* assembler, TailCallMode tail_call_mode);
// Generates code to perform a JS call with feedback.
void DoJSCallWithFeedback(InterpreterAssembler* assembler,
TailCallMode tail_call_mode);
// Generates code to perform a runtime call.
void DoCallRuntimeCommon(InterpreterAssembler* assembler);

View File

@ -961,6 +961,58 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
__ Jump(ra);
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm, Register index,
Register limit, Register scratch) {
Label loop_header, loop_check;
__ Branch(&loop_check);
__ bind(&loop_header);
__ lw(scratch, MemOperand(index));
__ Addu(index, index, Operand(-kPointerSize));
__ push(scratch);
__ bind(&loop_check);
__ Branch(&loop_header, gt, index, Operand(limit));
}
static void Generate_InterpreterComputeLastArgumentAddress(
MacroAssembler* masm, Register num_args, Register start_address,
Register output_reg) {
__ Addu(output_reg, num_args, Operand(1)); // Add one for receiver.
__ sll(output_reg, output_reg, kPointerSizeLog2);
__ Subu(output_reg, start_address, output_reg);
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallICImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- t0 : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -- a1 : the target to call (can be any Object).
// -- a3 : feedback vector slot id
// -- a2 : type feedback vector
// -----------------------------------
{
FrameScope scope(masm, StackFrame::INTERNAL);
// Computes the address of last argument in t1.
Generate_InterpreterComputeLastArgumentAddress(masm, a0, t0, t1);
// Push the arguments.
Generate_InterpreterPushArgs(masm, t0, t1, at);
// Call via the CallIC stub.
CallICState call_ic_state(0, ConvertReceiverMode::kAny, tail_call_mode,
true);
CallICStub stub(masm->isolate(), call_ic_state);
// TODO(mythria): This should be replaced by a TailCallStub, when we
// update the code to find the target IC from jump instructions.
__ CallStub(&stub);
}
__ Ret();
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
@ -973,20 +1025,11 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// -- a1 : the target to call (can be any Object).
// -----------------------------------
// Find the address of the last argument.
__ Addu(a3, a0, Operand(1)); // Add one for receiver.
__ sll(a3, a3, kPointerSizeLog2);
__ Subu(a3, a2, Operand(a3));
// Computes the address of last argument in a3.
Generate_InterpreterComputeLastArgumentAddress(masm, a0, a2, a3);
// Push the arguments.
Label loop_header, loop_check;
__ Branch(&loop_check);
__ bind(&loop_header);
__ lw(t0, MemOperand(a2));
__ Addu(a2, a2, Operand(-kPointerSize));
__ push(t0);
__ bind(&loop_check);
__ Branch(&loop_header, gt, a2, Operand(a3));
Generate_InterpreterPushArgs(masm, a2, a3, at);
// Call the target.
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
@ -994,7 +1037,6 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
RelocInfo::CODE_TARGET);
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
// ----------- S t a t e -------------
@ -1969,6 +2011,17 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ lb(scratch1, MemOperand(at));
__ Branch(&done, ne, scratch1, Operand(zero_reg));
// Drop possible internal frame pushed for calling CallICStub.
// TODO(mythria): when we tail call the CallICStub, remove this.
{
Label no_internal_callic_frame;
__ lw(scratch3, MemOperand(fp, StandardFrameConstants::kMarkerOffset));
__ Branch(&no_internal_callic_frame, ne, scratch3,
Operand(Smi::FromInt(StackFrame::INTERNAL)));
__ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_internal_callic_frame);
}
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;

View File

@ -2181,6 +2181,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// a0 - number of arguments - if argc_in_register() is true.
// a1 - function
// a3 - slot id
// a2 - vector
@ -2188,8 +2189,6 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, at);
__ Branch(miss, ne, a1, Operand(at));
__ li(a0, Operand(arg_count()));
// Increment the call count for monomorphic function calls.
__ Lsa(at, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ lw(a3, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
@ -2198,20 +2197,32 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ mov(a2, t0);
__ mov(a3, a1);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
if (argc_in_register()) {
// Pass a default ArgumentCountKey::Any since the argc is only available
// in a0. We do not have the actual count here.
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
} else {
// arg_count() is expected in a0 if the arg_count() >= 2
// (ArgumentCountKey::MORE_THAN_ONE).
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
}
}
void CallICStub::Generate(MacroAssembler* masm) {
// a0 - number of arguments - if argc_in_register() is true.
// a1 - function
// a3 - slot id (Smi)
// a2 - vector
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
ParameterCount actual(argc);
if (!argc_in_register()) {
int argc = arg_count();
__ li(a0, argc);
}
// The checks. First, does r1 match the recorded monomorphic target?
// The checks. First, does a1 match the recorded monomorphic target?
__ Lsa(t0, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ lw(t0, FieldMemOperand(t0, FixedArray::kHeaderSize));
@ -2245,9 +2256,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&call_function);
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg),
USE_DELAY_SLOT);
__ li(a0, Operand(argc)); // In delay slot.
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg));
__ bind(&extra_checks_or_miss);
Label uninitialized, miss, not_allocation_site;
@ -2284,9 +2293,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&call);
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg),
USE_DELAY_SLOT);
__ li(a0, Operand(argc)); // In delay slot.
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg));
__ bind(&uninitialized);
@ -2320,9 +2327,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(masm->isolate());
__ Push(a1);
__ SmiTag(a0);
__ Push(a0, a1);
__ CallStub(&create_stub);
__ Pop(a1);
__ Pop(a0, a1);
__ SmiUntag(a0);
}
__ Branch(&call_function);
@ -2339,14 +2348,19 @@ void CallICStub::Generate(MacroAssembler* masm) {
void CallICStub::GenerateMiss(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::INTERNAL);
// Push the receiver and the function and feedback info.
__ Push(a1, a2, a3);
__ SmiTag(a0);
// Push number of arguments, receiver, function and feedback info.
__ Push(a0, a1, a2, a3);
// Call the entry.
__ CallRuntime(Runtime::kCallIC_Miss);
// Move result to a1 and exit the internal frame.
__ mov(a1, v0);
// Restore a0.
__ Pop(a0);
__ SmiUntag(a0);
}

View File

@ -428,6 +428,18 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallICDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // argument count (not including receiver)
t0, // address of first argument
a1, // the target callable to be call
a3, // feedback vector slot id
a2 // type feedback vector
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {

View File

@ -1077,6 +1077,58 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
__ Jump(ra);
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm, Register index,
Register limit, Register scratch) {
Label loop_header, loop_check;
__ Branch(&loop_check);
__ bind(&loop_header);
__ ld(scratch, MemOperand(index));
__ Daddu(index, index, Operand(-kPointerSize));
__ push(scratch);
__ bind(&loop_check);
__ Branch(&loop_header, gt, index, Operand(limit));
}
static void Generate_InterpreterComputeLastArgumentAddress(
MacroAssembler* masm, Register num_args, Register start_address,
Register output_reg) {
__ Daddu(output_reg, num_args, Operand(1)); // Add one for receiver.
__ dsll(output_reg, output_reg, kPointerSizeLog2);
__ Dsubu(output_reg, start_address, output_reg);
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallICImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a4 : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -- a1 : the target to call (can be any Object).
// -- a3 : feedback vector slot id
// -- a2 : type feedback vector
// -----------------------------------
{
FrameScope scope(masm, StackFrame::INTERNAL);
// Computes the address of last argument in a5.
Generate_InterpreterComputeLastArgumentAddress(masm, a0, a4, a5);
// Push the arguments.
Generate_InterpreterPushArgs(masm, a4, a5, at);
// Call via the CallIC stub.
CallICState call_ic_state(0, ConvertReceiverMode::kAny, tail_call_mode,
true);
CallICStub stub(masm->isolate(), call_ic_state);
// TODO(mythria): This should be replaced by a TailCallStub, when we
// update the code to find the target IC from jump instructions.
__ CallStub(&stub);
}
__ Ret();
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
@ -1089,20 +1141,11 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// -- a1 : the target to call (can be any Object).
// -----------------------------------
// Find the address of the last argument.
__ Daddu(a3, a0, Operand(1)); // Add one for receiver.
__ dsll(a3, a3, kPointerSizeLog2);
__ Dsubu(a3, a2, Operand(a3));
// Computes the address of last argument in a3.
Generate_InterpreterComputeLastArgumentAddress(masm, a0, a2, a3);
// Push the arguments.
Label loop_header, loop_check;
__ Branch(&loop_check);
__ bind(&loop_header);
__ ld(t0, MemOperand(a2));
__ Daddu(a2, a2, Operand(-kPointerSize));
__ push(t0);
__ bind(&loop_check);
__ Branch(&loop_header, gt, a2, Operand(a3));
Generate_InterpreterPushArgs(masm, a2, a3, at);
// Call the target.
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
@ -2088,6 +2131,17 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ lb(scratch1, MemOperand(at));
__ Branch(&done, ne, scratch1, Operand(zero_reg));
// Drop possible internal frame pushed for calling CallICStub.
// TODO(mythria): when we tail call the CallICStub, remove this.
{
Label no_internal_callic_frame;
__ ld(scratch3, MemOperand(fp, StandardFrameConstants::kMarkerOffset));
__ Branch(&no_internal_callic_frame, ne, scratch3,
Operand(Smi::FromInt(StackFrame::INTERNAL)));
__ ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_internal_callic_frame);
}
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;

View File

@ -2224,6 +2224,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// a0 - number of arguments - if argc_in_register() is true.
// a1 - function
// a3 - slot id
// a2 - vector
@ -2231,32 +2232,42 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, at);
__ Branch(miss, ne, a1, Operand(at));
__ li(a0, Operand(arg_count()));
// Increment the call count for monomorphic function calls.
__ dsrl(t0, a3, 32 - kPointerSizeLog2);
__ Daddu(a3, a2, Operand(t0));
__ ld(t0, FieldMemOperand(a3, FixedArray::kHeaderSize + kPointerSize));
__ Daddu(t0, t0, Operand(Smi::FromInt(CallICNexus::kCallCountIncrement)));
__ sd(t0, FieldMemOperand(a3, FixedArray::kHeaderSize + kPointerSize));
__ dsrl(a5, a3, kSmiShiftSize + 1 - kPointerSizeLog2);
__ Daddu(a3, a2, Operand(a5));
__ ld(a5, FieldMemOperand(a3, FixedArray::kHeaderSize + kPointerSize));
__ Daddu(a5, a5, Operand(Smi::FromInt(CallICNexus::kCallCountIncrement)));
__ sd(a5, FieldMemOperand(a3, FixedArray::kHeaderSize + kPointerSize));
__ mov(a2, a4);
__ mov(a3, a1);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
if (argc_in_register()) {
// Pass a default ArgumentCountKey::Any since the argc is only available
// in a0. We do not have the actual count here.
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
} else {
// arg_count() is expected in a0 if the arg_count() >= 2
// (ArgumentCountKey::MORE_THAN_ONE).
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
}
}
void CallICStub::Generate(MacroAssembler* masm) {
// a0 - number of arguments - if argc_in_register() is true.
// a1 - function
// a3 - slot id (Smi)
// a2 - vector
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
ParameterCount actual(argc);
if (!argc_in_register()) {
int argc = arg_count();
__ li(a0, argc);
}
// The checks. First, does r1 match the recorded monomorphic target?
__ dsrl(a4, a3, 32 - kPointerSizeLog2);
// The checks. First, does a1 match the recorded monomorphic target?
__ dsrl(a4, a3, kSmiShiftSize + 1 - kPointerSizeLog2);
__ Daddu(a4, a2, Operand(a4));
__ ld(a4, FieldMemOperand(a4, FixedArray::kHeaderSize));
@ -2291,9 +2302,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&call_function);
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg),
USE_DELAY_SLOT);
__ li(a0, Operand(argc)); // In delay slot.
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg));
__ bind(&extra_checks_or_miss);
Label uninitialized, miss, not_allocation_site;
@ -2331,9 +2340,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&call);
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg),
USE_DELAY_SLOT);
__ li(a0, Operand(argc)); // In delay slot.
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg));
__ bind(&uninitialized);
@ -2368,9 +2375,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(masm->isolate());
__ Push(a1);
__ SmiTag(a0);
__ Push(a0, a1);
__ CallStub(&create_stub);
__ Pop(a1);
__ Pop(a0, a1);
__ SmiUntag(a0);
}
__ Branch(&call_function);
@ -2387,14 +2396,19 @@ void CallICStub::Generate(MacroAssembler* masm) {
void CallICStub::GenerateMiss(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::INTERNAL);
// Push the receiver and the function and feedback info.
__ Push(a1, a2, a3);
__ SmiTag(a0);
// Push number of arguments, receiver, function and feedback info.
__ Push(a0, a1, a2, a3);
// Call the entry.
__ CallRuntime(Runtime::kCallIC_Miss);
// Move result to a1 and exit the internal frame.
__ mov(a1, v0);
// Restore a0.
__ Pop(a0);
__ SmiUntag(a0);
}

View File

@ -428,6 +428,18 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallICDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // argument count (not including receiver)
a4, // address of first argument
a1, // the target callable to be call
a3, // feedback vector slot id
a2 // type feedback vector
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {

View File

@ -639,6 +639,38 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallICImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rbx : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -- rdi : the target to call (can be any Object).
// -- rdx : Feedback vector slot-id.
// -- r9 : type feedback vector. // TODO(mythria): move to rbx to match
// CallICStub expectation.
// -----------------------------------
{
FrameScope scope(masm, StackFrame::INTERNAL);
Generate_InterpreterPushArgs(masm, true);
__ Move(rbx, r9);
// Call via the CallIC stub.
CallICState call_ic_state(0, ConvertReceiverMode::kAny, tail_call_mode,
true);
CallICStub stub(masm->isolate(), call_ic_state);
// TODO(mythria): This should be replaced by a TailCallStub, when we
// update the code to find the target IC from jump instructions.
__ CallStub(&stub);
}
__ Ret();
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
@ -662,7 +694,6 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
RelocInfo::CODE_TARGET);
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
// ----------- S t a t e -------------
@ -2073,6 +2104,17 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ cmpb(Operand(kScratchRegister, 0), Immediate(0));
__ j(not_equal, &done);
// Drop possible internal frame pushed for calling CallICStub.
// TODO(mythria): when we tail call the CallICStub, remove this.
{
Label no_internal_callic_frame;
__ Cmp(Operand(rbp, StandardFrameConstants::kMarkerOffset),
Smi::FromInt(StackFrame::INTERNAL));
__ j(not_equal, &no_internal_callic_frame, Label::kNear);
__ movp(rbp, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_internal_callic_frame);
}
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;

View File

@ -1500,13 +1500,12 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// rdi - function
// rdx - slot id
// rbx - vector
// rax - number of arguments if argc_in_register() is true.
// rcx - allocation site (loaded from vector[slot]).
__ LoadNativeContextSlot(Context::ARRAY_FUNCTION_INDEX, r8);
__ cmpp(rdi, r8);
__ j(not_equal, miss);
__ movp(rax, Immediate(arg_count()));
// Increment the call count for monomorphic function calls.
__ SmiAddConstant(FieldOperand(rbx, rdx, times_pointer_size,
FixedArray::kHeaderSize + kPointerSize),
@ -1514,8 +1513,17 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ movp(rbx, rcx);
__ movp(rdx, rdi);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
if (argc_in_register()) {
// Pass a default ArgumentCountKey::Any since the argc is only available
// in rax. We do not have the actual count here.
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
} else {
// arg_count() is expected in rax if the arg_count() >= 2
// (ArgumentCountKey::MORE_THAN_ONE).
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
}
}
@ -1524,12 +1532,14 @@ void CallICStub::Generate(MacroAssembler* masm) {
// -- rdi - function
// -- rdx - slot id
// -- rbx - vector
// -- rax - number of arguments if argc_in_register() is true.
// -----------------------------------
Isolate* isolate = masm->isolate();
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
StackArgumentsAccessor args(rsp, argc);
ParameterCount actual(argc);
if (!argc_in_register()) {
int argc = arg_count();
__ Set(rax, argc);
}
// The checks. First, does rdi match the recorded monomorphic target?
__ SmiToInteger32(rdx, rdx);
@ -1563,7 +1573,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
Smi::FromInt(CallICNexus::kCallCountIncrement));
__ bind(&call_function);
__ Set(rax, argc);
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
RelocInfo::CODE_TARGET);
@ -1602,7 +1611,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
TypeFeedbackVector::MegamorphicSentinel(isolate));
__ bind(&call);
__ Set(rax, argc);
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET);
@ -1640,10 +1648,16 @@ void CallICStub::Generate(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(isolate);
__ Integer32ToSmi(rax, rax);
__ Push(rax);
__ Integer32ToSmi(rdx, rdx);
__ Push(rdi);
__ CallStub(&create_stub);
__ Pop(rdi);
__ Pop(rax);
__ SmiToInteger32(rax, rax);
}
__ jmp(&call_function);
@ -1663,6 +1677,10 @@ void CallICStub::Generate(MacroAssembler* masm) {
void CallICStub::GenerateMiss(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::INTERNAL);
// Store the number of arguments to be used later.
__ Integer32ToSmi(rax, rax);
__ Push(rax);
// Push the receiver and the function and feedback info.
__ Push(rdi);
__ Push(rbx);
@ -1674,6 +1692,10 @@ void CallICStub::GenerateMiss(MacroAssembler* masm) {
// Move result to edi and exit the internal frame.
__ movp(rdi, rax);
// rdi, rbx, rdx are arguments to CallIC_Miss. They will be popped by
// Runtime_CallIC_Miss.
__ Pop(rax);
__ SmiToInteger32(rax, rax);
}

View File

@ -415,6 +415,19 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallICDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
rax, // argument count (not including receiver)
rbx, // address of first argument
rdi, // the target callable to be call
rdx, // slot id
r9, // type feedback vector // TODO(mythria): move to rbx to match
// CallICStub.
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {

View File

@ -563,6 +563,18 @@
'test-run-jsexceptions/ThrowMessagePosition': [FAIL],
'test-api/TryCatchMixedNesting': [FAIL],
# TODO(4680): Related to lack of code-ageing in interpreter.
'test-heap/Regress169209': [FAIL],
# TODO(4680): Related to lack of code-ageing and/or lack of compilation cache
# in interpreter.
'test-heap/CompilationCacheCachingBehavior': [FAIL],
# TODO(4680): Use CallConstructStub for new operator.
'test-heap/IncrementalMarkingPreservesMonomorphicConstructor': [FAIL],
'test-heap/IncrementalMarkingClearsMonomorphicConstructor': [FAIL],
'test-heap/WeakFunctionInConstructor': [FAIL],
# TODO(rmcilroy,4680): Test assert errors.
'test-cpu-profiler/CodeEvents': [FAIL],
'test-cpu-profiler/TickEvents': [FAIL],
@ -587,17 +599,8 @@
'test-profile-generator/LineNumber': [FAIL],
'test-profile-generator/ProfileNodeScriptId': [FAIL],
'test-profile-generator/RecordStackTraceAtStartProfiling': [FAIL],
'test-feedback-vector/VectorCallICStates': [FAIL],
'test-compiler/FeedbackVectorPreservedAcrossRecompiles': [FAIL],
'test-api/PromiseRejectCallback': [FAIL],
'test-api/SetJitCodeEventHandler': [FAIL],
'test-heap/WeakFunctionInConstructor': [FAIL],
'test-heap/Regress169209': [FAIL],
'test-heap/IncrementalMarkingClearsMonomorphicConstructor': [FAIL],
'test-heap/IncrementalMarkingPreservesMonomorphicConstructor': [FAIL],
'test-heap/IncrementalMarkingPreservesMonomorphicCallIC': [FAIL],
'test-heap/CompilationCacheCachingBehavior': [FAIL],
'test-heap/CellsInOptimizedCodeAreWeak': [FAIL],
'test-run-inlining/InlineTwice': [FAIL],
'test-serialize/SerializeInternalReference': [FAIL, ['arch == arm or arch == arm64', PASS]],
}], # ignition == True

View File

@ -136,6 +136,9 @@ class BytecodeGraphTester {
compilation_info.MarkAsDeoptimizationEnabled();
compiler::Pipeline pipeline(&compilation_info);
Handle<Code> code = pipeline.GenerateCode();
// We do not actually record weak dependencies between objects and
// code objects. We just clear the dependencies for now.
compilation_info.dependencies()->Commit(compilation_info.code());
function->ReplaceCode(*code);
return function;

View File

@ -1512,7 +1512,7 @@ TEST(PropertyCall) {
B(Star), R(1), //
B(LoadIC), R(1), U8(0), U8(vector->GetIndex(slot2)), //
B(Star), R(0), //
B(Call), R(0), R(1), U8(1), U8(vector->GetIndex(slot1)), //
B(CallIC), R(0), R(1), U8(1), U8(vector->GetIndex(slot1)), //
B(Return), //
},
1,
@ -1531,7 +1531,7 @@ TEST(PropertyCall) {
B(Star), R(2), //
B(Ldar), A(3, 4), //
B(Star), R(3), //
B(Call), R(0), R(1), U8(3), U8(vector->GetIndex(slot1)), //
B(CallIC), R(0), R(1), U8(3), U8(vector->GetIndex(slot1)), //
B(Return) //
},
1,
@ -1553,7 +1553,7 @@ TEST(PropertyCall) {
B(Star), R(2), //
B(Ldar), A(2, 3), //
B(Star), R(3), //
B(Call), R(0), R(1), U8(3), U8(vector->GetIndex(slot1)), //
B(CallIC), R(0), R(1), U8(3), U8(vector->GetIndex(slot1)), //
B(Return), //
},
1,
@ -1577,7 +1577,7 @@ TEST(PropertyCall) {
B(Star), R(1), //
B(LoadICWide), R(1), U16(0), U16(wide_idx + 4), //
B(Star), R(0), //
B(CallWide), R16(0), R16(1), U16(1), U16(wide_idx + 2), //
B(CallICWide), R16(0), R16(1), U16(1), U16(wide_idx + 2), //
B(Return), //
},
1,
@ -1826,13 +1826,13 @@ TEST(CallGlobal) {
1,
15,
{
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(1), //
B(LdaGlobal), U8(0), U8(vector->GetIndex(slot2)), //
B(Star), R(0), //
B(Call), R(0), R(1), U8(1), U8(vector->GetIndex(slot1)), //
B(Return) //
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(1), //
B(LdaGlobal), U8(0), U8(vector->GetIndex(slot2)), //
B(Star), R(0), //
B(CallIC), R(0), R(1), U8(1), U8(vector->GetIndex(slot1)), //
B(Return) //
},
1,
{"t"}},
@ -1841,19 +1841,19 @@ TEST(CallGlobal) {
1,
27,
{
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(1), //
B(LdaGlobal), U8(0), U8(vector->GetIndex(slot2)), //
B(Star), R(0), //
B(LdaSmi8), U8(1), //
B(Star), R(2), //
B(LdaSmi8), U8(2), //
B(Star), R(3), //
B(LdaSmi8), U8(3), //
B(Star), R(4), //
B(Call), R(0), R(1), U8(4), U8(vector->GetIndex(slot1)), //
B(Return) //
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(1), //
B(LdaGlobal), U8(0), U8(vector->GetIndex(slot2)), //
B(Star), R(0), //
B(LdaSmi8), U8(1), //
B(Star), R(2), //
B(LdaSmi8), U8(2), //
B(Star), R(3), //
B(LdaSmi8), U8(3), //
B(Star), R(4), //
B(CallIC), R(0), R(1), U8(4), U8(vector->GetIndex(slot1)), //
B(Return) //
},
1,
{"t"}},
@ -2300,7 +2300,7 @@ TEST(DeclareGlobals) {
B(Star), R(2), //
B(LdaGlobal), U8(1), U8(load_vector->GetIndex(load_slot_1)), //
B(Star), R(1), //
B(Call), R(1), R(2), U8(1), //
B(CallIC), R(1), R(2), U8(1), //
/* */ U8(load_vector->GetIndex(call_slot_1)), //
B(Star), R(0), //
B(Return) //
@ -3774,13 +3774,13 @@ TEST(FunctionLiterals) {
1,
15,
{
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(1), //
B(CreateClosure), U8(0), U8(0), //
B(Star), R(0), //
B(Call), R(0), R(1), U8(1), U8(vector->GetIndex(slot)), //
B(Return) //
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(1), //
B(CreateClosure), U8(0), U8(0), //
B(Star), R(0), //
B(CallIC), R(0), R(1), U8(1), U8(vector->GetIndex(slot)), //
B(Return) //
},
1,
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
@ -3789,15 +3789,15 @@ TEST(FunctionLiterals) {
1,
19,
{
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(1), //
B(CreateClosure), U8(0), U8(0), //
B(Star), R(0), //
B(LdaSmi8), U8(1), //
B(Star), R(2), //
B(Call), R(0), R(1), U8(2), U8(vector->GetIndex(slot)), //
B(Return) //
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(1), //
B(CreateClosure), U8(0), U8(0), //
B(Star), R(0), //
B(LdaSmi8), U8(1), //
B(Star), R(2), //
B(CallIC), R(0), R(1), U8(2), U8(vector->GetIndex(slot)), //
B(Return) //
},
1,
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
@ -3861,7 +3861,7 @@ TEST(RegExpLiterals) {
B(Star), R(0), //
B(LdaConstant), U8(2), //
B(Star), R(2), //
B(Call), R(0), R(1), U8(2), U8(vector->GetIndex(slot1)), //
B(CallIC), R(0), R(1), U8(2), U8(vector->GetIndex(slot1)), //
B(Return), //
},
3,
@ -5036,17 +5036,17 @@ TEST(ContextVariables) {
1,
25,
{
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
/* */ R(closure), U8(1), //
B(PushContext), R(0), //
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(2), //
B(CreateClosure), U8(0), U8(0), //
B(Star), R(1), //
B(Call), R(1), R(2), U8(1), U8(vector->GetIndex(slot)), //
B(LdaContextSlot), R(context), U8(first_context_slot), //
B(Return), //
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
/* */ R(closure), U8(1), //
B(PushContext), R(0), //
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(2), //
B(CreateClosure), U8(0), U8(0), //
B(Star), R(1), //
B(CallIC), R(1), R(2), U8(1), U8(vector->GetIndex(slot)), //
B(LdaContextSlot), R(context), U8(first_context_slot), //
B(Return), //
},
1,
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
@ -5087,7 +5087,7 @@ TEST(ContextVariables) {
"return b",
3 * kPointerSize,
1,
1042,
1041,
{
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
/* */ U8(1), //
@ -5104,9 +5104,9 @@ TEST(ContextVariables) {
B(StaContextSlot), R(context), U8(wide_slot++)), //
B(LdaUndefined), //
B(Star), R(2), //
B(LdaGlobal), U8(0), U8(1), //
B(LdaGlobal), U8(0), U8(1), //
B(Star), R(1), //
B(Call), R(1), R(2), U8(1), U8(0), //
B(Call), R(1), R(2), U8(1), //
B(LdaSmi8), U8(100), //
B(StaContextSlotWide), R(context), U16(256), //
B(LdaContextSlotWide), R(context), U16(256), //
@ -6324,13 +6324,13 @@ DISABLED_TEST(ForOf) {
B(LdaConstant), U8(1), //
B(KeyedLoadIC), R(5), U8(vector->GetIndex(slot2)), //
B(Star), R(4), //
B(Call), R(4), R(5), U8(1), U8(vector->GetIndex(slot1)), //
B(CallIC), R(4), R(5), U8(1), U8(vector->GetIndex(slot1)), //
B(Star), R(1), //
B(Ldar), R(1), //
B(Star), R(6), //
B(LoadIC), R(6), U8(2), U8(vector->GetIndex(slot4)), //
B(Star), R(5), //
B(Call), R(5), R(6), U8(1), U8(vector->GetIndex(slot3)), //
B(CallIC), R(5), R(6), U8(1), U8(vector->GetIndex(slot3)), //
B(Star), R(2), //
B(Star), R(4), //
B(CallRuntime), U16(Runtime::kInlineIsJSReceiver), R(4), U8(1), //
@ -6373,13 +6373,13 @@ DISABLED_TEST(ForOf) {
B(LdaConstant), U8(1), //
B(KeyedLoadIC), R(6), U8(vector->GetIndex(slot2)), //
B(Star), R(5), //
B(Call), R(5), R(6), U8(1), U8(vector->GetIndex(slot1)), //
B(CallIC), R(5), R(6), U8(1), U8(vector->GetIndex(slot1)), //
B(Star), R(1), //
B(Ldar), R(1), //
B(Star), R(7), //
B(LoadIC), R(7), U8(2), U8(vector->GetIndex(slot4)), //
B(Star), R(6), //
B(Call), R(6), R(7), U8(1), U8(vector->GetIndex(slot3)), //
B(CallIC), R(6), R(7), U8(1), U8(vector->GetIndex(slot3)), //
B(Star), R(2), //
B(Star), R(5), //
B(CallRuntime), U16(Runtime::kInlineIsJSReceiver), R(5), U8(1), //
@ -6424,13 +6424,13 @@ DISABLED_TEST(ForOf) {
B(LdaConstant), U8(1), //
B(KeyedLoadIC), R(5), U8(vector->GetIndex(slot2)), //
B(Star), R(4), //
B(Call), R(4), R(5), U8(1), U8(vector->GetIndex(slot1)), //
B(CallIC), R(4), R(5), U8(1), U8(vector->GetIndex(slot1)), //
B(Star), R(1), //
B(Ldar), R(1), //
B(Star), R(6), //
B(LoadIC), R(6), U8(2), U8(vector->GetIndex(slot4)), //
B(Star), R(5), //
B(Call), R(5), R(6), U8(1), U8(vector->GetIndex(slot3)), //
B(CallIC), R(5), R(6), U8(1), U8(vector->GetIndex(slot3)), //
B(Star), R(2), //
B(Star), R(4), //
B(CallRuntime), U16(Runtime::kInlineIsJSReceiver), R(4), U8(1), //
@ -6486,13 +6486,13 @@ DISABLED_TEST(ForOf) {
B(LdaConstant), U8(2), //
B(KeyedLoadIC), R(4), U8(vector->GetIndex(slot2)), //
B(Star), R(3), //
B(Call), R(3), R(4), U8(1), U8(vector->GetIndex(slot1)), //
B(CallIC), R(3), R(4), U8(1), U8(vector->GetIndex(slot1)), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Star), R(5), //
B(LoadIC), R(5), U8(3), U8(vector->GetIndex(slot4)), //
B(Star), R(4), //
B(Call), R(4), R(5), U8(1), U8(vector->GetIndex(slot3)), //
B(CallIC), R(4), R(5), U8(1), U8(vector->GetIndex(slot3)), //
B(Star), R(1), //
B(Star), R(3), //
B(CallRuntime), U16(Runtime::kInlineIsJSReceiver), R(3), U8(1), //
@ -7440,7 +7440,7 @@ TEST(Eval) {
{"return eval('1;');",
9 * kPointerSize,
1,
65,
64,
{
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
/* */ U8(1), //
@ -7468,7 +7468,7 @@ TEST(Eval) {
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), //
/* */ U8(5), //
B(Star), R(1), //
B(Call), R(1), R(2), U8(2), U8(0), //
B(Call), R(1), R(2), U8(2), //
B(Return), //
},
2,
@ -7498,7 +7498,7 @@ TEST(LookupSlot) {
{"eval('var x = 10;'); return x;",
9 * kPointerSize,
1,
67,
66,
{
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
/* */ U8(1), //
@ -7526,7 +7526,7 @@ TEST(LookupSlot) {
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), //
U8(5), //
B(Star), R(1), //
B(Call), R(1), R(2), U8(2), U8(0), //
B(Call), R(1), R(2), U8(2), //
B(LdaLookupSlot), U8(2), //
B(Return), //
},
@ -7535,7 +7535,7 @@ TEST(LookupSlot) {
{"eval('var x = 10;'); return typeof x;",
9 * kPointerSize,
1,
68,
67,
{
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
/* */ U8(1), //
@ -7563,7 +7563,7 @@ TEST(LookupSlot) {
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), //
/* */ U8(5), //
B(Star), R(1), //
B(Call), R(1), R(2), U8(2), U8(0), //
B(Call), R(1), R(2), U8(2), //
B(LdaLookupSlotInsideTypeof), U8(2), //
B(TypeOf), //
B(Return), //
@ -7573,7 +7573,7 @@ TEST(LookupSlot) {
{"x = 20; return eval('');",
9 * kPointerSize,
1,
69,
68,
{
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
U8(1), //
@ -7603,7 +7603,7 @@ TEST(LookupSlot) {
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), //
/* */ U8(5), //
B(Star), R(1), //
B(Call), R(1), R(2), U8(2), U8(0), //
B(Call), R(1), R(2), U8(2), //
B(Return), //
},
3,
@ -7641,7 +7641,7 @@ TEST(CallLookupSlot) {
{"g = function(){}; eval(''); return g();",
9 * kPointerSize,
1,
85,
84,
{
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
/* */ U8(1), //
@ -7671,12 +7671,12 @@ TEST(CallLookupSlot) {
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), //
U8(5), //
B(Star), R(1), //
B(Call), R(1), R(2), U8(2), U8(0), //
B(Call), R(1), R(2), U8(2), //
B(LdaConstant), U8(1), //
B(Star), R(3), //
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), //
R(3), U8(1), R(1), //
B(Call), R(1), R(2), U8(1), U8(vector->GetIndex(slot2)), //
B(CallIC), R(1), R(2), U8(1), U8(vector->GetIndex(slot2)), //
B(Return), //
},
4,
@ -9069,7 +9069,7 @@ TEST(ClassDeclarations) {
B(Star), R(6), //
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4), //
B(Star), R(3), //
B(LoadIC), R(3), U8(1), U8(1), //
B(LoadIC), R(3), U8(1), U8(1), //
B(Star), R(4), //
B(CallRuntime), U16(Runtime::kFinalizeClassDefinition), R(3), U8(2), //
B(Star), R(0), //
@ -9096,6 +9096,113 @@ TEST(ClassDeclarations) {
}
}
TEST(TailCall) {
bool old_tailcall_flag = FLAG_harmony_tailcalls;
FLAG_harmony_tailcalls = true;
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
int closure = Register::function_closure().index();
int context = Register::current_context().index();
int new_target = Register::new_target().index();
// clang-format off
ExpectedSnippet<const char*> snippets[] = {
{"function g() { throw new Error('foo'); };"
"var eval = g;"
"function f() {"
" 'use strict';"
" return eval('g()');"
"}",
9 * kPointerSize,
1,
63,
{
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
U8(1), //
B(PushContext), R(0), //
B(Ldar), THIS(1), //
B(StaContextSlot), R(context), U8(4), //
B(CreateUnmappedArguments), //
B(StaContextSlot), R(context), U8(5), //
B(Ldar), R(new_target), //
B(StaContextSlot), R(context), U8(6), //
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(2), //
B(LdaGlobal), U8(0), U8(1), //
B(Star), R(1), //
B(LdaConstant), U8(1), //
B(Star), R(3), //
B(Mov), R(1), R(4), //
B(Mov), R(3), R(5), //
B(Mov), R(closure), R(6), //
B(LdaSmi8), U8(1), //
B(Star), R(7), //
B(LdaSmi8), U8(64), //
B(Star), R(8), //
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), //
U8(5), //
B(Star), R(1), //
B(TailCall), R(1), R(2), U8(2), //
B(Return), //
},
2,
{"eval",
"g()"}}
};
// clang-format on
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecodeForFunction(snippets[i].code_snippet);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
FLAG_harmony_tailcalls = old_tailcall_flag;
}
TEST(TailCallIC) {
bool old_tailcall_flag = FLAG_harmony_tailcalls;
FLAG_harmony_tailcalls = true;
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
// clang-format off
ExpectedSnippet<const char*> snippets[] = {
{"function g() { return 0; };"
"function f() {"
" 'use strict';"
" return g();"
"}",
2 * kPointerSize,
1,
15,
{
B(StackCheck), //
B(LdaUndefined), //
B(Star), R(1), //
B(LdaGlobal), U8(0), U8(3), //
B(Star), R(0), //
B(TailCallIC), R(0), R(1), U8(1), U8(1), //
B(Return),
},
1,
{"g"}}
};
// clang-format on
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecodeForFunction(snippets[i].code_snippet);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
FLAG_harmony_tailcalls = old_tailcall_flag;
}
// TODO(oth): Add tests for super keyword.
} // namespace interpreter

View File

@ -928,7 +928,8 @@ TEST(InterpreterStoreKeyedProperty) {
CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
}
static void TestInterpreterCall(TailCallMode tail_call_mode) {
static void TestInterpreterCall(TailCallMode tail_call_mode,
bool has_feedback_slot) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
@ -936,10 +937,15 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
i::FeedbackVectorSpec feedback_spec(&zone);
i::FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot();
i::FeedbackVectorSlot call_slot = feedback_spec.AddCallICSlot();
Handle<i::TypeFeedbackVector> vector =
i::NewTypeFeedbackVector(isolate, &feedback_spec);
int slot_index = vector->GetIndex(slot);
int call_slot_index = -1;
if (has_feedback_slot) {
call_slot_index = vector->GetIndex(call_slot);
}
Handle<i::String> name = factory->NewStringFromAsciiChecked("func");
name = factory->string_table()->LookupString(isolate, name);
@ -949,9 +955,16 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
0, 1);
builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
.StoreAccumulatorInRegister(Register(0))
.Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode)
.Return();
.StoreAccumulatorInRegister(Register(0));
if (has_feedback_slot) {
builder.CallIC(Register(0), builder.Parameter(0), 1, call_slot_index,
tail_call_mode);
} else {
builder.Call(Register(0), builder.Parameter(0), 1, tail_call_mode);
}
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
@ -968,9 +981,14 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
0, 1);
builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
.StoreAccumulatorInRegister(Register(0))
.Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode)
.Return();
.StoreAccumulatorInRegister(Register(0));
if (has_feedback_slot) {
builder.CallIC(Register(0), builder.Parameter(0), 1, call_slot_index,
tail_call_mode);
} else {
builder.Call(Register(0), builder.Parameter(0), 1, tail_call_mode);
}
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
@ -996,9 +1014,17 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.LoadLiteral(Smi::FromInt(51))
.StoreAccumulatorInRegister(Register(2))
.LoadLiteral(Smi::FromInt(11))
.StoreAccumulatorInRegister(Register(3))
.Call(Register(0), Register(1), 3, 0, tail_call_mode)
.Return();
.StoreAccumulatorInRegister(Register(3));
if (has_feedback_slot) {
builder.CallIC(Register(0), Register(1), 3, call_slot_index,
tail_call_mode);
} else {
builder.Call(Register(0), Register(1), 3, tail_call_mode);
}
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
@ -1039,9 +1065,17 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.LoadLiteral(factory->NewStringFromAsciiChecked("i"))
.StoreAccumulatorInRegister(Register(10))
.LoadLiteral(factory->NewStringFromAsciiChecked("j"))
.StoreAccumulatorInRegister(Register(11))
.Call(Register(0), Register(1), 11, 0, tail_call_mode)
.Return();
.StoreAccumulatorInRegister(Register(11));
if (has_feedback_slot) {
builder.CallIC(Register(0), Register(1), 11, call_slot_index,
tail_call_mode);
} else {
builder.Call(Register(0), Register(1), 11, tail_call_mode);
}
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
@ -1061,9 +1095,13 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
}
}
TEST(InterpreterCall) { TestInterpreterCall(TailCallMode::kDisallow); }
TEST(InterpreterCall) { TestInterpreterCall(TailCallMode::kDisallow, false); }
TEST(InterpreterTailCall) { TestInterpreterCall(TailCallMode::kAllow); }
TEST(InterpreterTailCall) { TestInterpreterCall(TailCallMode::kAllow, false); }
TEST(InterpreterCallIC) { TestInterpreterCall(TailCallMode::kDisallow, true); }
TEST(InterpreterTailCallIC) { TestInterpreterCall(TailCallMode::kAllow, true); }
static BytecodeArrayBuilder& SetRegister(BytecodeArrayBuilder& builder,
Register reg, int value,

View File

@ -918,6 +918,12 @@
'unicodelctest-no-optimization': [SKIP],
}], # ignition == True and (arch == arm or arch == arm64)
['ignition == True and arch == x64', {
# TODO(mythria,4680): Stack call size exceeds limit.
# Try to tail call CallICStub from PushArgsAndCallIC builtin.
'regress/regress-353551': [FAIL],
}], # ignition == True and arch == x64
##############################################################################
['gcov_coverage', {
# Tests taking too long.

View File

@ -94,10 +94,14 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CreateObjectLiteral(factory->NewFixedArray(1), 0, 0);
// Call operations.
builder.Call(reg, other, 1, 0)
.Call(reg, wide, 1, 0)
.TailCall(reg, other, 1, 0)
.TailCall(reg, wide, 1, 0)
builder.Call(reg, other, 1)
.Call(reg, wide, 1)
.TailCall(reg, other, 1)
.TailCall(reg, wide, 1)
.CallIC(reg, other, 1, 0, TailCallMode::kDisallow)
.CallIC(reg, other, 1, 0, TailCallMode::kAllow)
.CallIC(reg, wide, 1, 0, TailCallMode::kDisallow)
.CallIC(reg, wide, 1, 0, TailCallMode::kAllow)
.CallRuntime(Runtime::kIsArray, reg, 1)
.CallRuntime(Runtime::kIsArray, wide, 1)
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg, 1, other)