Commit 32b4bc13 authored by ishell's avatar ishell Committed by Commit bot

[es6] [interpreter] Add tail calls support to Ignition.

This CL introduces two new bytecodes TailCall and TailCallWide.

BUG=v8:4698,v8:4687
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#34083}
parent c8117f2f
...@@ -1103,7 +1103,8 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, Register index, ...@@ -1103,7 +1103,8 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, Register index,
// static // static
void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver) // -- r0 : the number of arguments (not including the receiver)
// -- r2 : the address of the first argument to be pushed. Subsequent // -- r2 : the address of the first argument to be pushed. Subsequent
...@@ -1121,7 +1122,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { ...@@ -1121,7 +1122,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
Generate_InterpreterPushArgs(masm, r2, r3, r4); Generate_InterpreterPushArgs(masm, r2, r3, r4);
// Call the target. // Call the target.
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} }
...@@ -2065,6 +2068,16 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg, ...@@ -2065,6 +2068,16 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ cmp(scratch1, Operand(0)); __ cmp(scratch1, Operand(0));
__ b(ne, &done); __ b(ne, &done);
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ ldr(scratch3, MemOperand(fp, StandardFrameConstants::kMarkerOffset));
__ cmp(scratch3, Operand(Smi::FromInt(StackFrame::STUB)));
__ b(ne, &no_interpreter_frame);
__ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_interpreter_frame);
}
// Check if next frame is an arguments adaptor frame. // Check if next frame is an arguments adaptor frame.
Label no_arguments_adaptor, formal_parameter_count_loaded; Label no_arguments_adaptor, formal_parameter_count_loaded;
__ ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); __ ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
......
...@@ -2098,6 +2098,16 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg, ...@@ -2098,6 +2098,16 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ Cmp(scratch1, Operand(0)); __ Cmp(scratch1, Operand(0));
__ B(ne, &done); __ B(ne, &done);
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ Ldr(scratch3, MemOperand(fp, StandardFrameConstants::kMarkerOffset));
__ Cmp(scratch3, Operand(Smi::FromInt(StackFrame::STUB)));
__ B(ne, &no_interpreter_frame);
__ Ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_interpreter_frame);
}
// Check if next frame is an arguments adaptor frame. // Check if next frame is an arguments adaptor frame.
Label no_arguments_adaptor, formal_parameter_count_loaded; Label no_arguments_adaptor, formal_parameter_count_loaded;
__ Ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); __ Ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
...@@ -2573,7 +2583,8 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { ...@@ -2573,7 +2583,8 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// static // static
void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver) // -- x0 : the number of arguments (not including the receiver)
// -- x2 : the address of the first argument to be pushed. Subsequent // -- x2 : the address of the first argument to be pushed. Subsequent
...@@ -2601,7 +2612,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { ...@@ -2601,7 +2612,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
__ B(gt, &loop_header); __ B(gt, &loop_header);
// Call the target. // Call the target.
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} }
......
...@@ -3989,6 +3989,16 @@ Handle<Code> Builtins::CallBoundFunction(TailCallMode tail_call_mode) { ...@@ -3989,6 +3989,16 @@ Handle<Code> Builtins::CallBoundFunction(TailCallMode tail_call_mode) {
return Handle<Code>::null(); return Handle<Code>::null();
} }
Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
return InterpreterPushArgsAndCall();
case TailCallMode::kAllow:
return InterpreterPushArgsAndTailCall();
}
UNREACHABLE();
return Handle<Code>::null();
}
namespace { namespace {
......
...@@ -214,6 +214,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) { ...@@ -214,6 +214,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(InterpreterEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(InterpreterEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterExitTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(InterpreterExitTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterPushArgsAndCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(InterpreterPushArgsAndCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterPushArgsAndTailCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterPushArgsAndConstruct, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(InterpreterPushArgsAndConstruct, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterNotifyDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(InterpreterNotifyDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InterpreterNotifySoftDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(InterpreterNotifySoftDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \
...@@ -362,6 +363,7 @@ class Builtins { ...@@ -362,6 +363,7 @@ class Builtins {
Handle<Code> Call(ConvertReceiverMode = ConvertReceiverMode::kAny, Handle<Code> Call(ConvertReceiverMode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow); TailCallMode tail_call_mode = TailCallMode::kDisallow);
Handle<Code> CallBoundFunction(TailCallMode tail_call_mode); Handle<Code> CallBoundFunction(TailCallMode tail_call_mode);
Handle<Code> InterpreterPushArgsAndCall(TailCallMode tail_call_mode);
Code* builtin(Name name) { Code* builtin(Name name) {
// Code::cast cannot be used here since we access builtins // Code::cast cannot be used here since we access builtins
...@@ -577,7 +579,15 @@ class Builtins { ...@@ -577,7 +579,15 @@ class Builtins {
static void Generate_InterpreterEntryTrampoline(MacroAssembler* masm); static void Generate_InterpreterEntryTrampoline(MacroAssembler* masm);
static void Generate_InterpreterExitTrampoline(MacroAssembler* masm); static void Generate_InterpreterExitTrampoline(MacroAssembler* masm);
static void Generate_InterpreterPushArgsAndCall(MacroAssembler* masm); static void Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm,
TailCallMode::kDisallow);
}
static void Generate_InterpreterPushArgsAndTailCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kAllow);
}
static void Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode);
static void Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm); static void Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm);
static void Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm); static void Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm);
static void Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm); static void Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm);
......
...@@ -347,9 +347,11 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) { ...@@ -347,9 +347,11 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) {
// static // static
Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate) { Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
return Callable(isolate->builtins()->InterpreterPushArgsAndCall(), TailCallMode tail_call_mode) {
InterpreterPushArgsAndCallDescriptor(isolate)); return Callable(
isolate->builtins()->InterpreterPushArgsAndCall(tail_call_mode),
InterpreterPushArgsAndCallDescriptor(isolate));
} }
......
...@@ -105,7 +105,8 @@ class CodeFactory final { ...@@ -105,7 +105,8 @@ class CodeFactory final {
static Callable Construct(Isolate* isolate); static Callable Construct(Isolate* isolate);
static Callable ConstructFunction(Isolate* isolate); static Callable ConstructFunction(Isolate* isolate);
static Callable InterpreterPushArgsAndCall(Isolate* isolate); static Callable InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate); static Callable InterpreterPushArgsAndConstruct(Isolate* isolate);
static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1); static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1);
}; };
......
...@@ -993,7 +993,7 @@ Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op, ...@@ -993,7 +993,7 @@ Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
return value; return value;
} }
void BytecodeGraphBuilder::BuildCall() { void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode) {
FrameStateBeforeAndAfter states(this); FrameStateBeforeAndAfter states(this);
// TODO(rmcilroy): Set receiver_hint correctly based on whether the receiver // TODO(rmcilroy): Set receiver_hint correctly based on whether the receiver
// register has been loaded with null / undefined explicitly or we are sure it // register has been loaded with null / undefined explicitly or we are sure it
...@@ -1006,16 +1006,23 @@ void BytecodeGraphBuilder::BuildCall() { ...@@ -1006,16 +1006,23 @@ void BytecodeGraphBuilder::BuildCall() {
VectorSlotPair feedback = VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(3)); CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(3));
// TODO(ishell): provide correct tail_call_mode value to CallFunction. const Operator* call = javascript()->CallFunction(
const Operator* call = arg_count + 1, feedback, receiver_hint, tail_call_mode);
javascript()->CallFunction(arg_count + 1, feedback, receiver_hint);
Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1); Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1);
environment()->BindAccumulator(value, &states); environment()->BindAccumulator(value, &states);
} }
void BytecodeGraphBuilder::VisitCall() { BuildCall(); } void BytecodeGraphBuilder::VisitCall() { BuildCall(TailCallMode::kDisallow); }
void BytecodeGraphBuilder::VisitCallWide() { BuildCall(); } void BytecodeGraphBuilder::VisitCallWide() {
BuildCall(TailCallMode::kDisallow);
}
void BytecodeGraphBuilder::VisitTailCall() { BuildCall(TailCallMode::kAllow); }
void BytecodeGraphBuilder::VisitTailCallWide() {
BuildCall(TailCallMode::kAllow);
}
void BytecodeGraphBuilder::BuildCallJSRuntime() { void BytecodeGraphBuilder::BuildCallJSRuntime() {
FrameStateBeforeAndAfter states(this); FrameStateBeforeAndAfter states(this);
......
...@@ -123,7 +123,7 @@ class BytecodeGraphBuilder { ...@@ -123,7 +123,7 @@ class BytecodeGraphBuilder {
void BuildKeyedStore(LanguageMode language_mode); void BuildKeyedStore(LanguageMode language_mode);
void BuildLdaLookupSlot(TypeofMode typeof_mode); void BuildLdaLookupSlot(TypeofMode typeof_mode);
void BuildStaLookupSlot(LanguageMode language_mode); void BuildStaLookupSlot(LanguageMode language_mode);
void BuildCall(); void BuildCall(TailCallMode tail_call_mode);
void BuildCallJSRuntime(); void BuildCallJSRuntime();
void BuildCallRuntime(); void BuildCallRuntime();
void BuildCallRuntimeForPair(); void BuildCallRuntimeForPair();
......
...@@ -676,7 +676,8 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, ...@@ -676,7 +676,8 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static // static
void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver) // -- eax : the number of arguments (not including the receiver)
// -- ebx : the address of the first argument to be pushed. Subsequent // -- ebx : the address of the first argument to be pushed. Subsequent
...@@ -699,7 +700,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { ...@@ -699,7 +700,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
// Call the target. // Call the target.
__ Push(edx); // Re-push return address. __ Push(edx); // Re-push return address.
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} }
...@@ -1989,6 +1992,16 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg, ...@@ -1989,6 +1992,16 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ cmp(scratch1, Immediate(0)); __ cmp(scratch1, Immediate(0));
__ j(not_equal, &done, Label::kNear); __ j(not_equal, &done, Label::kNear);
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
Immediate(Smi::FromInt(StackFrame::STUB)));
__ j(not_equal, &no_interpreter_frame, Label::kNear);
__ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_interpreter_frame);
}
// Check if next frame is an arguments adaptor frame. // Check if next frame is an arguments adaptor frame.
Label no_arguments_adaptor, formal_parameter_count_loaded; Label no_arguments_adaptor, formal_parameter_count_loaded;
__ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
......
...@@ -1062,20 +1062,21 @@ void BytecodeArrayBuilder::EnsureReturn(FunctionLiteral* literal) { ...@@ -1062,20 +1062,21 @@ void BytecodeArrayBuilder::EnsureReturn(FunctionLiteral* literal) {
BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
Register receiver_args, Register receiver_args,
size_t receiver_args_count, size_t receiver_args_count,
int feedback_slot) { int feedback_slot,
TailCallMode tail_call_mode) {
Bytecode bytecode = BytecodeForCall(tail_call_mode);
if (FitsInReg8Operand(callable) && FitsInReg8Operand(receiver_args) && if (FitsInReg8Operand(callable) && FitsInReg8Operand(receiver_args) &&
FitsInIdx8Operand(receiver_args_count) && FitsInIdx8Operand(receiver_args_count) &&
FitsInIdx8Operand(feedback_slot)) { FitsInIdx8Operand(feedback_slot)) {
Output(Bytecode::kCall, callable.ToRawOperand(), Output(bytecode, callable.ToRawOperand(), receiver_args.ToRawOperand(),
receiver_args.ToRawOperand(),
static_cast<uint8_t>(receiver_args_count), static_cast<uint8_t>(receiver_args_count),
static_cast<uint8_t>(feedback_slot)); static_cast<uint8_t>(feedback_slot));
} else if (FitsInReg16Operand(callable) && } else if (FitsInReg16Operand(callable) &&
FitsInReg16Operand(receiver_args) && FitsInReg16Operand(receiver_args) &&
FitsInIdx16Operand(receiver_args_count) && FitsInIdx16Operand(receiver_args_count) &&
FitsInIdx16Operand(feedback_slot)) { FitsInIdx16Operand(feedback_slot)) {
Output(Bytecode::kCallWide, callable.ToRawOperand(), bytecode = BytecodeForWideOperands(bytecode);
receiver_args.ToRawOperand(), Output(bytecode, callable.ToRawOperand(), receiver_args.ToRawOperand(),
static_cast<uint16_t>(receiver_args_count), static_cast<uint16_t>(receiver_args_count),
static_cast<uint16_t>(feedback_slot)); static_cast<uint16_t>(feedback_slot));
} else { } else {
...@@ -1425,6 +1426,10 @@ Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) { ...@@ -1425,6 +1426,10 @@ Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
// static // static
Bytecode BytecodeArrayBuilder::BytecodeForWideOperands(Bytecode bytecode) { Bytecode BytecodeArrayBuilder::BytecodeForWideOperands(Bytecode bytecode) {
switch (bytecode) { switch (bytecode) {
case Bytecode::kCall:
return Bytecode::kCallWide;
case Bytecode::kTailCall:
return Bytecode::kTailCallWide;
case Bytecode::kLoadIC: case Bytecode::kLoadIC:
return Bytecode::kLoadICWide; return Bytecode::kLoadICWide;
case Bytecode::kKeyedLoadIC: case Bytecode::kKeyedLoadIC:
...@@ -1564,6 +1569,18 @@ Bytecode BytecodeArrayBuilder::BytecodeForDelete(LanguageMode language_mode) { ...@@ -1564,6 +1569,18 @@ Bytecode BytecodeArrayBuilder::BytecodeForDelete(LanguageMode language_mode) {
return static_cast<Bytecode>(-1); return static_cast<Bytecode>(-1);
} }
// static
Bytecode BytecodeArrayBuilder::BytecodeForCall(TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
return Bytecode::kCall;
case TailCallMode::kAllow:
return Bytecode::kTailCall;
default:
UNREACHABLE();
}
return static_cast<Bytecode>(-1);
}
// static // static
bool BytecodeArrayBuilder::FitsInIdx8Operand(int value) { bool BytecodeArrayBuilder::FitsInIdx8Operand(int value) {
......
...@@ -161,8 +161,15 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { ...@@ -161,8 +161,15 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
// |callable|, the receiver should be in |receiver_args| and all subsequent // |callable|, the receiver should be in |receiver_args| and all subsequent
// arguments should be in registers <receiver_args + 1> to // arguments should be in registers <receiver_args + 1> to
// <receiver_args + receiver_arg_count - 1>. // <receiver_args + receiver_arg_count - 1>.
BytecodeArrayBuilder& Call(Register callable, Register receiver_args, BytecodeArrayBuilder& Call(
size_t receiver_arg_count, int feedback_slot); Register callable, Register receiver_args, size_t receiver_arg_count,
int feedback_slot, 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,
TailCallMode::kAllow);
}
// Call the new operator. The accumulator holds the |new_target|. // Call the new operator. The accumulator holds the |new_target|.
// The |constructor| is in a register followed by |arg_count| // The |constructor| is in a register followed by |arg_count|
...@@ -280,6 +287,7 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { ...@@ -280,6 +287,7 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
static Bytecode BytecodeForStoreLookupSlot(LanguageMode language_mode); static Bytecode BytecodeForStoreLookupSlot(LanguageMode language_mode);
static Bytecode BytecodeForCreateArguments(CreateArgumentsType type); static Bytecode BytecodeForCreateArguments(CreateArgumentsType type);
static Bytecode BytecodeForDelete(LanguageMode language_mode); static Bytecode BytecodeForDelete(LanguageMode language_mode);
static Bytecode BytecodeForCall(TailCallMode tail_call_mode);
static bool FitsInIdx8Operand(int value); static bool FitsInIdx8Operand(int value);
static bool FitsInIdx8Operand(size_t value); static bool FitsInIdx8Operand(size_t value);
......
...@@ -2462,7 +2462,8 @@ void BytecodeGenerator::VisitCall(Call* expr) { ...@@ -2462,7 +2462,8 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()->SetExpressionPosition(expr); builder()->SetExpressionPosition(expr);
builder()->Call(callee, receiver, 1 + args->length(), builder()->Call(callee, receiver, 1 + args->length(),
feedback_index(expr->CallFeedbackICSlot())); feedback_index(expr->CallFeedbackICSlot()),
expr->tail_call_mode());
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
......
...@@ -262,8 +262,9 @@ bool Bytecodes::IsJump(Bytecode bytecode) { ...@@ -262,8 +262,9 @@ bool Bytecodes::IsJump(Bytecode bytecode) {
// static // static
bool Bytecodes::IsCallOrNew(Bytecode bytecode) { bool Bytecodes::IsCallOrNew(Bytecode bytecode) {
return bytecode == Bytecode::kCall || bytecode == Bytecode::kNew || return bytecode == Bytecode::kCall || bytecode == Bytecode::kTailCall ||
bytecode == Bytecode::kCallWide || bytecode == Bytecode::kNewWide; bytecode == Bytecode::kNew || bytecode == Bytecode::kCallWide ||
bytecode == Bytecode::kTailCallWide || bytecode == Bytecode::kNewWide;
} }
// static // static
......
...@@ -158,6 +158,10 @@ namespace interpreter { ...@@ -158,6 +158,10 @@ namespace interpreter {
OperandType::kIdx8) \ OperandType::kIdx8) \
V(CallWide, OperandType::kReg16, OperandType::kReg16, \ V(CallWide, OperandType::kReg16, OperandType::kReg16, \
OperandType::kRegCount16, OperandType::kIdx16) \ OperandType::kRegCount16, OperandType::kIdx16) \
V(TailCall, OperandType::kReg8, OperandType::kReg8, OperandType::kRegCount8, \
OperandType::kIdx8) \
V(TailCallWide, OperandType::kReg16, OperandType::kReg16, \
OperandType::kRegCount16, OperandType::kIdx16) \
V(CallRuntime, OperandType::kIdx16, OperandType::kMaybeReg8, \ V(CallRuntime, OperandType::kIdx16, OperandType::kMaybeReg8, \
OperandType::kRegCount8) \ OperandType::kRegCount8) \
V(CallRuntimeWide, OperandType::kIdx16, OperandType::kMaybeReg16, \ V(CallRuntimeWide, OperandType::kIdx16, OperandType::kMaybeReg16, \
......
...@@ -335,8 +335,10 @@ void InterpreterAssembler::CallEpilogue() { ...@@ -335,8 +335,10 @@ void InterpreterAssembler::CallEpilogue() {
} }
Node* InterpreterAssembler::CallJS(Node* function, Node* context, Node* InterpreterAssembler::CallJS(Node* function, Node* context,
Node* first_arg, Node* arg_count) { Node* first_arg, Node* arg_count,
Callable callable = CodeFactory::InterpreterPushArgsAndCall(isolate()); TailCallMode tail_call_mode) {
Callable callable =
CodeFactory::InterpreterPushArgsAndCall(isolate(), tail_call_mode);
Node* code_target = HeapConstant(callable.code()); Node* code_target = HeapConstant(callable.code());
return CallStub(callable.descriptor(), code_target, context, arg_count, return CallStub(callable.descriptor(), code_target, context, arg_count,
first_arg, function); first_arg, function);
......
...@@ -84,7 +84,8 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { ...@@ -84,7 +84,8 @@ class InterpreterAssembler : public compiler::CodeStubAssembler {
// arguments (not including receiver) and the first argument // arguments (not including receiver) and the first argument
// located at |first_arg|. // located at |first_arg|.
compiler::Node* CallJS(compiler::Node* function, compiler::Node* context, compiler::Node* CallJS(compiler::Node* function, compiler::Node* context,
compiler::Node* first_arg, compiler::Node* arg_count); compiler::Node* first_arg, compiler::Node* arg_count,
TailCallMode tail_call_mode);
// Call constructor |constructor| with |arg_count| arguments (not // Call constructor |constructor| with |arg_count| arguments (not
// including receiver) and the first argument located at // including receiver) and the first argument located at
......
...@@ -922,8 +922,8 @@ void Interpreter::DoDeletePropertySloppy(InterpreterAssembler* assembler) { ...@@ -922,8 +922,8 @@ void Interpreter::DoDeletePropertySloppy(InterpreterAssembler* assembler) {
DoDelete(Runtime::kDeleteProperty_Sloppy, assembler); DoDelete(Runtime::kDeleteProperty_Sloppy, assembler);
} }
void Interpreter::DoJSCall(InterpreterAssembler* assembler,
void Interpreter::DoJSCall(InterpreterAssembler* assembler) { TailCallMode tail_call_mode) {
Node* function_reg = __ BytecodeOperandReg(0); Node* function_reg = __ BytecodeOperandReg(0);
Node* function = __ LoadRegister(function_reg); Node* function = __ LoadRegister(function_reg);
Node* receiver_reg = __ BytecodeOperandReg(1); Node* receiver_reg = __ BytecodeOperandReg(1);
...@@ -933,7 +933,8 @@ void Interpreter::DoJSCall(InterpreterAssembler* assembler) { ...@@ -933,7 +933,8 @@ void Interpreter::DoJSCall(InterpreterAssembler* assembler) {
Node* args_count = __ Int32Sub(receiver_args_count, receiver_count); Node* args_count = __ Int32Sub(receiver_args_count, receiver_count);
Node* context = __ GetContext(); Node* context = __ GetContext();
// TODO(rmcilroy): Use the call type feedback slot to call via CallStub. // TODO(rmcilroy): Use the call type feedback slot to call via CallStub.
Node* result = __ CallJS(function, context, receiver_arg, args_count); Node* result =
__ CallJS(function, context, receiver_arg, args_count, tail_call_mode);
__ SetAccumulator(result); __ SetAccumulator(result);
__ Dispatch(); __ Dispatch();
} }
...@@ -944,7 +945,7 @@ void Interpreter::DoJSCall(InterpreterAssembler* assembler) { ...@@ -944,7 +945,7 @@ void Interpreter::DoJSCall(InterpreterAssembler* assembler) {
// Call a JSfunction or Callable in |callable| with the |receiver| and // Call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers. // |arg_count| arguments in subsequent registers.
void Interpreter::DoCall(InterpreterAssembler* assembler) { void Interpreter::DoCall(InterpreterAssembler* assembler) {
DoJSCall(assembler); DoJSCall(assembler, TailCallMode::kDisallow);
} }
...@@ -953,7 +954,23 @@ void Interpreter::DoCall(InterpreterAssembler* assembler) { ...@@ -953,7 +954,23 @@ void Interpreter::DoCall(InterpreterAssembler* assembler) {
// Call a JSfunction or Callable in |callable| with the |receiver| and // Call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers. // |arg_count| arguments in subsequent registers.
void Interpreter::DoCallWide(InterpreterAssembler* assembler) { void Interpreter::DoCallWide(InterpreterAssembler* assembler) {
DoJSCall(assembler); DoJSCall(assembler, TailCallMode::kDisallow);
}
// TailCall <callable> <receiver> <arg_count>
//
// Tail call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers.
void Interpreter::DoTailCall(InterpreterAssembler* assembler) {
DoJSCall(assembler, TailCallMode::kAllow);
}
// TailCallWide <callable> <receiver> <arg_count>
//
// Tail call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers.
void Interpreter::DoTailCallWide(InterpreterAssembler* assembler) {
DoJSCall(assembler, TailCallMode::kAllow);
} }
void Interpreter::DoCallRuntimeCommon(InterpreterAssembler* assembler) { void Interpreter::DoCallRuntimeCommon(InterpreterAssembler* assembler) {
...@@ -1044,7 +1061,8 @@ void Interpreter::DoCallJSRuntimeCommon(InterpreterAssembler* assembler) { ...@@ -1044,7 +1061,8 @@ void Interpreter::DoCallJSRuntimeCommon(InterpreterAssembler* assembler) {
Node* function = __ LoadContextSlot(native_context, context_index); Node* function = __ LoadContextSlot(native_context, context_index);
// Call the function. // Call the function.
Node* result = __ CallJS(function, context, first_arg, args_count); Node* result = __ CallJS(function, context, first_arg, args_count,
TailCallMode::kDisallow);
__ SetAccumulator(result); __ SetAccumulator(result);
__ Dispatch(); __ Dispatch();
} }
......
...@@ -86,7 +86,7 @@ class Interpreter { ...@@ -86,7 +86,7 @@ class Interpreter {
void DoKeyedStoreIC(Callable ic, InterpreterAssembler* assembler); void DoKeyedStoreIC(Callable ic, InterpreterAssembler* assembler);
// Generates code to perform a JS call. // Generates code to perform a JS call.
void DoJSCall(InterpreterAssembler* assembler); void DoJSCall(InterpreterAssembler* assembler, TailCallMode tail_call_mode);
// Generates code to perform a runtime call. // Generates code to perform a runtime call.
void DoCallRuntimeCommon(InterpreterAssembler* assembler); void DoCallRuntimeCommon(InterpreterAssembler* assembler);
......
...@@ -1075,7 +1075,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { ...@@ -1075,7 +1075,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
// static // static
void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver) // -- a0 : the number of arguments (not including the receiver)
// -- a2 : the address of the first argument to be pushed. Subsequent // -- a2 : the address of the first argument to be pushed. Subsequent
...@@ -1100,7 +1101,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { ...@@ -1100,7 +1101,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
__ Branch(&loop_header, gt, a2, Operand(a3)); __ Branch(&loop_header, gt, a2, Operand(a3));
// Call the target. // Call the target.
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} }
...@@ -2079,6 +2082,16 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg, ...@@ -2079,6 +2082,16 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ lb(scratch1, MemOperand(at)); __ lb(scratch1, MemOperand(at));
__ Branch(&done, ne, scratch1, Operand(zero_reg)); __ Branch(&done, ne, scratch1, Operand(zero_reg));
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ lw(scratch3, MemOperand(fp, StandardFrameConstants::kMarkerOffset));
__ Branch(&no_interpreter_frame, ne, scratch3,
Operand(Smi::FromInt(StackFrame::STUB)));
__ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_interpreter_frame);
}
// Check if next frame is an arguments adaptor frame. // Check if next frame is an arguments adaptor frame.
Label no_arguments_adaptor, formal_parameter_count_loaded; Label no_arguments_adaptor, formal_parameter_count_loaded;
__ lw(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); __ lw(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
......
...@@ -1067,7 +1067,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { ...@@ -1067,7 +1067,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
// static // static
void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver) // -- a0 : the number of arguments (not including the receiver)
// -- a2 : the address of the first argument to be pushed. Subsequent // -- a2 : the address of the first argument to be pushed. Subsequent
...@@ -1092,7 +1093,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { ...@@ -1092,7 +1093,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
__ Branch(&loop_header, gt, a2, Operand(a3)); __ Branch(&loop_header, gt, a2, Operand(a3));
// Call the target. // Call the target.
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} }
...@@ -2074,6 +2077,16 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg, ...@@ -2074,6 +2077,16 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
__ lb(scratch1, MemOperand(at)); __ lb(scratch1, MemOperand(at));
__ Branch(&done, ne, scratch1, Operand(zero_reg)); __ Branch(&done, ne, scratch1, Operand(zero_reg));
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ ld(scratch3, MemOperand(fp, StandardFrameConstants::kMarkerOffset));
__ Branch(&no_interpreter_frame, ne, scratch3,
Operand(Smi::FromInt(StackFrame::STUB)));
__ ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_interpreter_frame);
}
// Check if next frame is an arguments adaptor frame. // Check if next frame is an arguments adaptor frame.
Label no_arguments_adaptor, formal_parameter_count_loaded; Label no_arguments_adaptor, formal_parameter_count_loaded;
__ ld(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); __ ld(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
......
...@@ -755,7 +755,8 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, ...@@ -755,7 +755,8 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static // static
void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver) // -- rax : the number of arguments (not including the receiver)
// -- rbx : the address of the first argument to be pushed. Subsequent // -- rbx : the address of the first argument to be pushed. Subsequent
...@@ -771,7 +772,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { ...@@ -771,7 +772,9 @@ void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
// Call the target. // Call the target.
__ PushReturnAddressFrom(kScratchRegister); // Re-push return address. __ PushReturnAddressFrom(kScratchRegister); // Re-push return address.
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} }
...@@ -2187,7 +2190,17 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg, ...@@ -2187,7 +2190,17 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
ExternalReference::debug_is_active_address(masm->isolate()); ExternalReference::debug_is_active_address(masm->isolate());
__ Move(kScratchRegister, debug_is_active); __ Move(kScratchRegister, debug_is_active);
__ cmpb(Operand(kScratchRegister, 0), Immediate(0)); __ cmpb(Operand(kScratchRegister, 0), Immediate(0));
__ j(not_equal, &done, Label::kNear); __ j(not_equal, &done);
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ Cmp(Operand(rbp, StandardFrameConstants::kMarkerOffset),
Smi::FromInt(StackFrame::STUB));
__ j(not_equal, &no_interpreter_frame, Label::kNear);
__ movp(rbp, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_interpreter_frame);
}
// Check if next frame is an arguments adaptor frame. // Check if next frame is an arguments adaptor frame.
Label no_arguments_adaptor, formal_parameter_count_loaded; Label no_arguments_adaptor, formal_parameter_count_loaded;
......
...@@ -928,8 +928,7 @@ TEST(InterpreterStoreKeyedProperty) { ...@@ -928,8 +928,7 @@ TEST(InterpreterStoreKeyedProperty) {
CHECK_EQ(Smi::cast(*result), Smi::FromInt(999)); CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
} }
static void TestInterpreterCall(TailCallMode tail_call_mode) {
TEST(InterpreterCall) {
HandleAndZoneScope handles; HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate(); i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory(); i::Factory* factory = isolate->factory();
...@@ -951,7 +950,7 @@ TEST(InterpreterCall) { ...@@ -951,7 +950,7 @@ TEST(InterpreterCall) {
0, 1); 0, 1);
builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
.StoreAccumulatorInRegister(Register(0)) .StoreAccumulatorInRegister(Register(0))
.Call(Register(0), builder.Parameter(0), 1, 0) .Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode)
.Return(); .Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
...@@ -970,7 +969,7 @@ TEST(InterpreterCall) { ...@@ -970,7 +969,7 @@ TEST(InterpreterCall) {
0, 1); 0, 1);
builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
.StoreAccumulatorInRegister(Register(0)) .StoreAccumulatorInRegister(Register(0))
.Call(Register(0), builder.Parameter(0), 1, 0) .Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode)
.Return(); .Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
...@@ -998,7 +997,7 @@ TEST(InterpreterCall) { ...@@ -998,7 +997,7 @@ TEST(InterpreterCall) {
.StoreAccumulatorInRegister(Register(2)) .StoreAccumulatorInRegister(Register(2))
.LoadLiteral(Smi::FromInt(11)) .LoadLiteral(Smi::FromInt(11))
.StoreAccumulatorInRegister(Register(3)) .StoreAccumulatorInRegister(Register(3))
.Call(Register(0), Register(1), 3, 0) .Call(Register(0), Register(1), 3, 0, tail_call_mode)
.Return(); .Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
...@@ -1041,7 +1040,7 @@ TEST(InterpreterCall) { ...@@ -1041,7 +1040,7 @@ TEST(InterpreterCall) {
.StoreAccumulatorInRegister(Register(10)) .StoreAccumulatorInRegister(Register(10))
.LoadLiteral(factory->NewStringFromAsciiChecked("j")) .LoadLiteral(factory->NewStringFromAsciiChecked("j"))
.StoreAccumulatorInRegister(Register(11)) .StoreAccumulatorInRegister(Register(11))
.Call(Register(0), Register(1), 11, 0) .Call(Register(0), Register(1), 11, 0, tail_call_mode)
.Return(); .Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
...@@ -1062,6 +1061,9 @@ TEST(InterpreterCall) { ...@@ -1062,6 +1061,9 @@ TEST(InterpreterCall) {
} }
} }
TEST(InterpreterCall) { TestInterpreterCall(TailCallMode::kDisallow); }
TEST(InterpreterTailCall) { TestInterpreterCall(TailCallMode::kAllow); }
static BytecodeArrayBuilder& SetRegister(BytecodeArrayBuilder& builder, static BytecodeArrayBuilder& SetRegister(BytecodeArrayBuilder& builder,
Register reg, int value, Register reg, int value,
......
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
} }
return f(n - 1); return f(n - 1);
} }
assertThrows(()=>{ f(1e6) }); assertThrows(()=>{ f(1e5) });
%OptimizeFunctionOnNextCall(f); %OptimizeFunctionOnNextCall(f);
assertThrows(()=>{ f(1e6) }); assertThrows(()=>{ f(1e5) });
})(); })();
...@@ -31,9 +31,9 @@ ...@@ -31,9 +31,9 @@
} }
return f(n - 1); return f(n - 1);
} }
assertEquals("foo", f(1e6)); assertEquals("foo", f(1e5));
%OptimizeFunctionOnNextCall(f); %OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e6)); assertEquals("foo", f(1e5));
})(); })();
...@@ -51,11 +51,11 @@ ...@@ -51,11 +51,11 @@
} }
return f(n - 1); return f(n - 1);
} }
assertEquals("foo", f(1e6)); assertEquals("foo", f(1e5));
assertEquals("bar", f(1e6 + 1)); assertEquals("bar", f(1e5 + 1));
%OptimizeFunctionOnNextCall(f); %OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e6)); assertEquals("foo", f(1e5));
assertEquals("bar", f(1e6 + 1)); assertEquals("bar", f(1e5 + 1));
})(); })();
...@@ -74,9 +74,9 @@ ...@@ -74,9 +74,9 @@
function f(n) { function f(n) {
return f_bound(n); return f_bound(n);
} }
assertEquals("foo", f(1e6)); assertEquals("foo", f(1e5));
%OptimizeFunctionOnNextCall(f); %OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e6)); assertEquals("foo", f(1e5));
})(); })();
...@@ -99,9 +99,9 @@ ...@@ -99,9 +99,9 @@
function f(n) { function f(n) {
return f_bound(n); return f_bound(n);
} }
assertEquals("foo", f(1e6)); assertEquals("foo", f(1e5));
assertEquals("bar", f(1e6 + 1)); assertEquals("bar", f(1e5 + 1));
%OptimizeFunctionOnNextCall(f); %OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e6)); assertEquals("foo", f(1e5));
assertEquals("bar", f(1e6 + 1)); assertEquals("bar", f(1e5 + 1));
})(); })();
...@@ -44,7 +44,6 @@ ...@@ -44,7 +44,6 @@
'regress/regress-crbug-160010': [SKIP], 'regress/regress-crbug-160010': [SKIP],
# Issue 4698: not fully supported by Turbofan yet # Issue 4698: not fully supported by Turbofan yet
'es6/tail-call-simple': [SKIP],
'es6/tail-call': [PASS, NO_VARIANTS], 'es6/tail-call': [PASS, NO_VARIANTS],
# Issue 3389: deopt_every_n_garbage_collections is unsafe # Issue 3389: deopt_every_n_garbage_collections is unsafe
...@@ -850,9 +849,6 @@ ...@@ -850,9 +849,6 @@
'debug-liveedit-2': [FAIL], 'debug-liveedit-2': [FAIL],
'compiler/deopt-tonumber-compare': [FAIL], 'compiler/deopt-tonumber-compare': [FAIL],
'es6/string-search': [FAIL], 'es6/string-search': [FAIL],
'es6/tail-call-proxies': [FAIL],
'es6/tail-call': [FAIL],
'es6/tail-call-simple': [FAIL],
'es6/mirror-collections': [FAIL], 'es6/mirror-collections': [FAIL],
'es6/regress/regress-468661': [FAIL], 'es6/regress/regress-468661': [FAIL],
'harmony/string-replace': [FAIL], 'harmony/string-replace': [FAIL],
......
...@@ -96,6 +96,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -96,6 +96,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Call operations. // Call operations.
builder.Call(reg, other, 1, 0) builder.Call(reg, other, 1, 0)
.Call(reg, wide, 1, 0) .Call(reg, wide, 1, 0)
.TailCall(reg, other, 1, 0)
.TailCall(reg, wide, 1, 0)
.CallRuntime(Runtime::kIsArray, reg, 1) .CallRuntime(Runtime::kIsArray, reg, 1)
.CallRuntime(Runtime::kIsArray, wide, 1) .CallRuntime(Runtime::kIsArray, wide, 1)
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg, 1, other) .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg, 1, other)
......
...@@ -643,21 +643,27 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) { ...@@ -643,21 +643,27 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) {
} }
TARGET_TEST_F(InterpreterAssemblerTest, CallJS) { TARGET_TEST_F(InterpreterAssemblerTest, CallJS) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { TailCallMode tail_call_modes[] = {TailCallMode::kDisallow,
InterpreterAssemblerForTest m(this, bytecode); TailCallMode::kAllow};
Callable builtin = CodeFactory::InterpreterPushArgsAndCall(isolate()); TRACED_FOREACH(TailCallMode, tail_call_mode, tail_call_modes) {
Node* function = m.Int32Constant(0); TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
Node* first_arg = m.Int32Constant(1); InterpreterAssemblerForTest m(this, bytecode);
Node* arg_count = m.Int32Constant(2); Callable builtin =
Node* context = CodeFactory::InterpreterPushArgsAndCall(isolate(), tail_call_mode);
m.Parameter(InterpreterDispatchDescriptor::kContextParameter); Node* function = m.Int32Constant(0);
Node* call_js = m.CallJS(function, context, first_arg, arg_count); Node* first_arg = m.Int32Constant(1);
EXPECT_THAT( Node* arg_count = m.Int32Constant(2);
call_js, Node* context =
IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg, m.Parameter(InterpreterDispatchDescriptor::kContextParameter);
function, Node* call_js =
IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, m.CallJS(function, context, first_arg, arg_count, tail_call_mode);
_)); EXPECT_THAT(
call_js,
IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg,
function,
IsParameter(InterpreterDispatchDescriptor::kContextParameter),
_, _));
}
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment