[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:
parent
6cc5c601b6
commit
20362a2214
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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[] = {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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[] = {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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(),
|
||||
|
@ -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);
|
||||
|
@ -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_));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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[] = {
|
||||
|
@ -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_;
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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, \
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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[] = {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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[] = {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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[] = {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user