[cleanup] Remove always-off support for tail calls

The tail call implementation is hidden behind the --harmony-tailcalls
flag, which is off-by-default (and has been unstaged since February).
It is known to be broken in a variety of cases, including clusterfuzz
security issues (see sample Chromium issues below). To avoid letting
the implementation bitrot further on trunk, this patch removes it.

Bug: v8:4698, chromium:636914, chromium:724746
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng;master.tryserver.v8:v8_linux_noi18n_rel_ng
Change-Id: I9cb547101456a582374fdf7b1a3f044a9ef33e5c
Reviewed-on: https://chromium-review.googlesource.com/569069
Commit-Queue: Adam Klein <adamk@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46651}
This commit is contained in:
Adam Klein 2017-07-13 11:06:15 -07:00 committed by Commit Bot
parent 415fd8d8d1
commit 1769f892ce
105 changed files with 284 additions and 3395 deletions

View File

@ -9287,14 +9287,9 @@ void Debug::SetLiveEditEnabled(Isolate* isolate, bool enable) {
debug::SetLiveEditEnabled(isolate, enable);
}
bool Debug::IsTailCallEliminationEnabled(Isolate* isolate) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
return internal_isolate->is_tail_call_elimination_enabled();
}
bool Debug::IsTailCallEliminationEnabled(Isolate* isolate) { return false; }
void Debug::SetTailCallEliminationEnabled(Isolate* isolate, bool enabled) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
internal_isolate->SetTailCallEliminationEnabled(enabled);
}
MaybeLocal<Array> Debug::GetInternalProperties(Isolate* v8_isolate,

View File

@ -1573,11 +1573,6 @@ ExternalReference ExternalReference::cpu_features() {
return ExternalReference(&CpuFeatures::supported_);
}
ExternalReference ExternalReference::is_tail_call_elimination_enabled_address(
Isolate* isolate) {
return ExternalReference(isolate->is_tail_call_elimination_enabled_address());
}
ExternalReference ExternalReference::promise_hook_or_debug_is_active_address(
Isolate* isolate) {
return ExternalReference(isolate->promise_hook_or_debug_is_active_address());

View File

@ -431,7 +431,7 @@ class RelocInfo {
}
static inline bool IsDebugBreakSlot(Mode mode) {
return IsDebugBreakSlotAtPosition(mode) || IsDebugBreakSlotAtReturn(mode) ||
IsDebugBreakSlotAtCall(mode) || IsDebugBreakSlotAtTailCall(mode);
IsDebugBreakSlotAtCall(mode);
}
static inline bool IsDebugBreakSlotAtPosition(Mode mode) {
return mode == DEBUG_BREAK_SLOT_AT_POSITION;
@ -442,9 +442,6 @@ class RelocInfo {
static inline bool IsDebugBreakSlotAtCall(Mode mode) {
return mode == DEBUG_BREAK_SLOT_AT_CALL;
}
static inline bool IsDebugBreakSlotAtTailCall(Mode mode) {
return mode == DEBUG_BREAK_SLOT_AT_TAIL_CALL;
}
static inline bool IsNone(Mode mode) {
return mode == NONE32 || mode == NONE64;
}
@ -1007,9 +1004,6 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference cpu_features();
static ExternalReference is_tail_call_elimination_enabled_address(
Isolate* isolate);
static ExternalReference debug_is_active_address(Isolate* isolate);
static ExternalReference debug_hook_on_function_call_address(
Isolate* isolate);

View File

@ -159,16 +159,6 @@ bool Expression::IsAccessorFunctionDefinition() const {
return IsFunctionLiteral() && IsAccessorFunction(AsFunctionLiteral()->kind());
}
void Expression::MarkTail() {
if (IsConditional()) {
AsConditional()->MarkTail();
} else if (IsCall()) {
AsCall()->MarkTail();
} else if (IsBinaryOperation()) {
AsBinaryOperation()->MarkTail();
}
}
bool Statement::IsJump() const {
switch (node_type()) {
#define JUMP_NODE_LIST(V) \

View File

@ -282,9 +282,6 @@ class Expression : public AstNode {
kTest
};
// Mark this expression as being in tail position.
void MarkTail();
// True iff the expression is a valid reference expression.
bool IsValidReferenceExpression() const;
@ -1757,12 +1754,6 @@ class Call final : public Expression {
return IsPossiblyEvalField::decode(bit_field_);
}
TailCallMode tail_call_mode() const {
return IsTailField::decode(bit_field_) ? TailCallMode::kAllow
: TailCallMode::kDisallow;
}
void MarkTail() { bit_field_ = IsTailField::update(bit_field_, true); }
bool only_last_arg_is_spread() {
return !arguments_->is_empty() && arguments_->last()->IsSpread();
}
@ -1805,8 +1796,8 @@ class Call final : public Expression {
class IsUninitializedField
: public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
class IsTailField : public BitField<bool, IsUninitializedField::kNext, 1> {};
class IsPossiblyEvalField : public BitField<bool, IsTailField::kNext, 1> {};
class IsPossiblyEvalField
: public BitField<bool, IsUninitializedField::kNext, 1> {};
FeedbackSlot ic_slot_;
Expression* expression_;
@ -1945,17 +1936,6 @@ class BinaryOperation final : public Expression {
Expression* right() const { return right_; }
void set_right(Expression* e) { right_ = e; }
void MarkTail() {
switch (op()) {
case Token::COMMA:
case Token::AND:
case Token::OR:
right_->MarkTail();
default:
break;
}
}
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
@ -2110,11 +2090,6 @@ class Conditional final : public Expression {
void set_then_expression(Expression* e) { then_expression_ = e; }
void set_else_expression(Expression* e) { else_expression_ = e; }
void MarkTail() {
then_expression_->MarkTail();
else_expression_->MarkTail();
}
private:
friend class AstNodeFactory;

View File

@ -1147,9 +1147,7 @@ void AstPrinter::VisitProperty(Property* node) {
void AstPrinter::VisitCall(Call* node) {
EmbeddedVector<char, 128> buf;
const char* name =
node->tail_call_mode() == TailCallMode::kAllow ? "TAIL CALL" : "CALL";
FormatSlotNode(&buf, node, name, node->CallFeedbackICSlot());
FormatSlotNode(&buf, node, "CALL", node->CallFeedbackICSlot());
IndentedScope indent(this, buf.start());
Visit(node->expression());

View File

@ -4055,7 +4055,6 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_lookbehind)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_named_captures)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_property)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_sent)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tailcalls)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrictive_generators)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_tostring)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_class_fields)

View File

@ -1306,7 +1306,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r2 : the address of the first argument to be pushed. Subsequent
@ -1336,15 +1336,14 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl(
// Call the target.
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
__ Jump(
masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny),
RelocInfo::CODE_TARGET);
} else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
__ Jump(masm->isolate()->builtins()->CallWithSpread(),
RelocInfo::CODE_TARGET);
} else {
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny),
RelocInfo::CODE_TARGET);
}
@ -2213,102 +2212,9 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ Jump(code, RelocInfo::CODE_TARGET);
}
namespace {
// Drops top JavaScript frame and an arguments adaptor frame below it (if
// present) preserving all the arguments prepared for current call.
// Does nothing if debugger is currently active.
// ES6 14.6.3. PrepareForTailCall
//
// Stack structure for the function g() tail calling f():
//
// ------- Caller frame: -------
// | ...
// | g()'s arg M
// | ...
// | g()'s arg 1
// | g()'s receiver arg
// | g()'s caller pc
// ------- g()'s frame: -------
// | g()'s caller fp <- fp
// | g()'s context
// | function pointer: g
// | -------------------------
// | ...
// | ...
// | f()'s arg N
// | ...
// | f()'s arg 1
// | f()'s receiver arg <- sp (f()'s caller pc is not on the stack yet!)
// ----------------------
//
void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
Register scratch1, Register scratch2,
Register scratch3) {
DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
Comment cmnt(masm, "[ PrepareForTailCall");
// Prepare for tail call only if ES2015 tail call elimination is enabled.
Label done;
ExternalReference is_tail_call_elimination_enabled =
ExternalReference::is_tail_call_elimination_enabled_address(
masm->isolate());
__ mov(scratch1, Operand(is_tail_call_elimination_enabled));
__ ldrb(scratch1, MemOperand(scratch1));
__ cmp(scratch1, Operand(0));
__ b(eq, &done);
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ ldr(scratch3,
MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset));
__ cmp(scratch3, Operand(StackFrame::TypeToMarker(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.
Register caller_args_count_reg = scratch1;
Label no_arguments_adaptor, formal_parameter_count_loaded;
__ ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ ldr(scratch3,
MemOperand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset));
__ cmp(scratch3,
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
__ b(ne, &no_arguments_adaptor);
// Drop current frame and load arguments count from arguments adaptor frame.
__ mov(fp, scratch2);
__ ldr(caller_args_count_reg,
MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ SmiUntag(caller_args_count_reg);
__ b(&formal_parameter_count_loaded);
__ bind(&no_arguments_adaptor);
// Load caller's formal parameter count
__ ldr(scratch1,
MemOperand(fp, ArgumentsAdaptorFrameConstants::kFunctionOffset));
__ ldr(scratch1,
FieldMemOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
__ ldr(caller_args_count_reg,
FieldMemOperand(scratch1,
SharedFunctionInfo::kFormalParameterCountOffset));
__ bind(&formal_parameter_count_loaded);
ParameterCount callee_args_count(args_reg);
__ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
scratch3);
__ bind(&done);
}
} // namespace
// static
void Builtins::Generate_CallFunction(MacroAssembler* masm,
ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r1 : the function to call (checked to be a JSFunction)
@ -2394,10 +2300,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
// -- cp : the function context.
// -----------------------------------
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, r0, r3, r4, r5);
}
__ ldr(r2,
FieldMemOperand(r2, SharedFunctionInfo::kFormalParameterCountOffset));
ParameterCount actual(r0);
@ -2495,18 +2397,13 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
} // namespace
// static
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
TailCallMode tail_call_mode) {
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r1 : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(r1);
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, r0, r3, r4, r5);
}
// Patch the receiver to [[BoundThis]].
__ ldr(r3, FieldMemOperand(r1, JSBoundFunction::kBoundThisOffset));
__ str(r3, MemOperand(sp, r0, LSL, kPointerSizeLog2));
@ -2524,8 +2421,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r1 : the target to call (can be any Object).
@ -2535,10 +2431,10 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ JumpIfSmi(r1, &non_callable);
__ bind(&non_smi);
__ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, eq);
__ cmp(r5, Operand(JS_BOUND_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
__ Jump(masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET, eq);
// Check if target has a [[Call]] internal method.
@ -2549,11 +2445,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ cmp(r5, Operand(JS_PROXY_TYPE));
__ b(ne, &non_function);
// 0. Prepare for tail call if necessary.
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, r0, r3, r4, r5);
}
// 1. Runtime fallback for Proxy [[Call]].
__ Push(r1);
// Increase the arguments size to include the pushed function and the
@ -2571,7 +2462,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
// Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, r1);
__ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.

View File

@ -1329,7 +1329,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x2 : the address of the first argument to be pushed. Subsequent
@ -1361,15 +1361,14 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl(
// Call the target.
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
__ Jump(
masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny),
RelocInfo::CODE_TARGET);
} else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
__ Jump(masm->isolate()->builtins()->CallWithSpread(),
RelocInfo::CODE_TARGET);
} else {
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny),
RelocInfo::CODE_TARGET);
}
@ -2309,100 +2308,9 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ Jump(code, RelocInfo::CODE_TARGET);
}
namespace {
// Drops top JavaScript frame and an arguments adaptor frame below it (if
// present) preserving all the arguments prepared for current call.
// Does nothing if debugger is currently active.
// ES6 14.6.3. PrepareForTailCall
//
// Stack structure for the function g() tail calling f():
//
// ------- Caller frame: -------
// | ...
// | g()'s arg M
// | ...
// | g()'s arg 1
// | g()'s receiver arg
// | g()'s caller pc
// ------- g()'s frame: -------
// | g()'s caller fp <- fp
// | g()'s context
// | function pointer: g
// | -------------------------
// | ...
// | ...
// | f()'s arg N
// | ...
// | f()'s arg 1
// | f()'s receiver arg <- sp (f()'s caller pc is not on the stack yet!)
// ----------------------
//
void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
Register scratch1, Register scratch2,
Register scratch3) {
DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
Comment cmnt(masm, "[ PrepareForTailCall");
// Prepare for tail call only if ES2015 tail call elimination is enabled.
Label done;
ExternalReference is_tail_call_elimination_enabled =
ExternalReference::is_tail_call_elimination_enabled_address(
masm->isolate());
__ Mov(scratch1, Operand(is_tail_call_elimination_enabled));
__ Ldrb(scratch1, MemOperand(scratch1));
__ Cmp(scratch1, Operand(0));
__ B(eq, &done);
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ Ldr(scratch3,
MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Cmp(scratch3, Operand(StackFrame::TypeToMarker(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.
Register caller_args_count_reg = scratch1;
Label no_arguments_adaptor, formal_parameter_count_loaded;
__ Ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ Ldr(scratch3,
MemOperand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Cmp(scratch3,
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
__ B(ne, &no_arguments_adaptor);
// Drop current frame and load arguments count from arguments adaptor frame.
__ mov(fp, scratch2);
__ Ldr(caller_args_count_reg,
MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ SmiUntag(caller_args_count_reg);
__ B(&formal_parameter_count_loaded);
__ bind(&no_arguments_adaptor);
// Load caller's formal parameter count
__ Ldr(scratch1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ Ldr(scratch1,
FieldMemOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
__ Ldrsw(caller_args_count_reg,
FieldMemOperand(scratch1,
SharedFunctionInfo::kFormalParameterCountOffset));
__ bind(&formal_parameter_count_loaded);
ParameterCount callee_args_count(args_reg);
__ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
scratch3);
__ bind(&done);
}
} // namespace
// static
void Builtins::Generate_CallFunction(MacroAssembler* masm,
ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
ConvertReceiverMode mode) {
ASM_LOCATION("Builtins::Generate_CallFunction");
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
@ -2489,10 +2397,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
// -- cp : the function context.
// -----------------------------------
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, x0, x3, x4, x5);
}
__ Ldrsw(
x2, FieldMemOperand(x2, SharedFunctionInfo::kFormalParameterCountOffset));
ParameterCount actual(x0);
@ -2587,18 +2491,13 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
} // namespace
// static
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
TailCallMode tail_call_mode) {
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x1 : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(x1);
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, x0, x3, x4, x5);
}
// Patch the receiver to [[BoundThis]].
__ Ldr(x10, FieldMemOperand(x1, JSBoundFunction::kBoundThisOffset));
__ Poke(x10, Operand(x0, LSL, kPointerSizeLog2));
@ -2616,8 +2515,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x1 : the target to call (can be any Object).
@ -2627,10 +2525,10 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ JumpIfSmi(x1, &non_callable);
__ Bind(&non_smi);
__ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, eq);
__ Cmp(x5, JS_BOUND_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
__ Jump(masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET, eq);
// Check if target has a [[Call]] internal method.
@ -2640,11 +2538,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ Cmp(x5, JS_PROXY_TYPE);
__ B(ne, &non_function);
// 0. Prepare for tail call if necessary.
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, x0, x3, x4, x5);
}
// 1. Runtime fallback for Proxy [[Call]].
__ Push(x1);
// Increase the arguments size to include the pushed function and the
@ -2662,7 +2555,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
// Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, x1);
__ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.

View File

@ -15,74 +15,33 @@ namespace internal {
void Builtins::Generate_CallFunction_ReceiverIsNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kDisallow);
Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined);
}
void Builtins::Generate_CallFunction_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kDisallow);
Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined);
}
void Builtins::Generate_CallFunction_ReceiverIsAny(MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kAny,
TailCallMode::kDisallow);
}
void Builtins::Generate_TailCallFunction_ReceiverIsNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCallFunction_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCallFunction_ReceiverIsAny(MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kAny, TailCallMode::kAllow);
Generate_CallFunction(masm, ConvertReceiverMode::kAny);
}
void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
Generate_CallBoundFunctionImpl(masm, TailCallMode::kDisallow);
}
void Builtins::Generate_TailCallBoundFunction(MacroAssembler* masm) {
Generate_CallBoundFunctionImpl(masm, TailCallMode::kAllow);
Generate_CallBoundFunctionImpl(masm);
}
void Builtins::Generate_Call_ReceiverIsNullOrUndefined(MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kDisallow);
Generate_Call(masm, ConvertReceiverMode::kNullOrUndefined);
}
void Builtins::Generate_Call_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kDisallow);
Generate_Call(masm, ConvertReceiverMode::kNotNullOrUndefined);
}
void Builtins::Generate_Call_ReceiverIsAny(MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kAny, TailCallMode::kDisallow);
}
void Builtins::Generate_TailCall_ReceiverIsNullOrUndefined(
MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCall_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCall_ReceiverIsAny(MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kAny, TailCallMode::kAllow);
Generate_Call(masm, ConvertReceiverMode::kAny);
}
void Builtins::Generate_CallVarargs(MacroAssembler* masm) {

View File

@ -11,66 +11,26 @@
namespace v8 {
namespace internal {
Handle<Code> Builtins::CallFunction(ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return CallFunction_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return CallFunction_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return CallFunction_ReceiverIsAny();
}
break;
case TailCallMode::kAllow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return TailCallFunction_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return TailCallFunction_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return TailCallFunction_ReceiverIsAny();
}
break;
Handle<Code> Builtins::CallFunction(ConvertReceiverMode mode) {
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return CallFunction_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return CallFunction_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return CallFunction_ReceiverIsAny();
}
UNREACHABLE();
}
Handle<Code> Builtins::Call(ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return Call_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return Call_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return Call_ReceiverIsAny();
}
break;
case TailCallMode::kAllow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return TailCall_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return TailCall_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return TailCall_ReceiverIsAny();
}
break;
}
UNREACHABLE();
}
Handle<Code> Builtins::CallBoundFunction(TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
return CallBoundFunction();
case TailCallMode::kAllow:
return TailCallBoundFunction();
Handle<Code> Builtins::Call(ConvertReceiverMode mode) {
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return Call_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return Call_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return Call_ReceiverIsAny();
}
UNREACHABLE();
}

View File

@ -62,19 +62,12 @@ namespace internal {
ASM(CallFunction_ReceiverIsNullOrUndefined) \
ASM(CallFunction_ReceiverIsNotNullOrUndefined) \
ASM(CallFunction_ReceiverIsAny) \
ASM(TailCallFunction_ReceiverIsNullOrUndefined) \
ASM(TailCallFunction_ReceiverIsNotNullOrUndefined) \
ASM(TailCallFunction_ReceiverIsAny) \
/* ES6 section 9.4.1.1 [[Call]] ( thisArgument, argumentsList) */ \
ASM(CallBoundFunction) \
ASM(TailCallBoundFunction) \
/* ES6 section 7.3.12 Call(F, V, [argumentsList]) */ \
ASM(Call_ReceiverIsNullOrUndefined) \
ASM(Call_ReceiverIsNotNullOrUndefined) \
ASM(Call_ReceiverIsAny) \
ASM(TailCall_ReceiverIsNullOrUndefined) \
ASM(TailCall_ReceiverIsNotNullOrUndefined) \
ASM(TailCall_ReceiverIsAny) \
ASM(CallVarargs) \
TFC(CallWithSpread, CallWithSpread, 1) \
TFC(CallWithArrayLike, CallWithArrayLike, 1) \
@ -138,8 +131,6 @@ namespace internal {
ASM(InterpreterPushArgsThenCallFunction) \
ASM(InterpreterPushUndefinedAndArgsThenCallFunction) \
ASM(InterpreterPushArgsThenCallWithFinalSpread) \
ASM(InterpreterPushArgsThenTailCall) \
ASM(InterpreterPushArgsThenTailCallFunction) \
ASM(InterpreterPushArgsThenConstruct) \
ASM(InterpreterPushArgsThenConstructFunction) \
ASM(InterpreterPushArgsThenConstructArray) \

View File

@ -11,51 +11,36 @@ namespace internal {
void Builtins::Generate_InterpreterPushArgsThenCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kAny, TailCallMode::kDisallow,
InterpreterPushArgsMode::kOther);
masm, ConvertReceiverMode::kAny, InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushArgsThenCallFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kAny, TailCallMode::kDisallow,
InterpreterPushArgsMode::kJSFunction);
masm, ConvertReceiverMode::kAny, InterpreterPushArgsMode::kJSFunction);
}
void Builtins::Generate_InterpreterPushUndefinedAndArgsThenCall(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kNullOrUndefined, TailCallMode::kDisallow,
masm, ConvertReceiverMode::kNullOrUndefined,
InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushUndefinedAndArgsThenCallFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kNullOrUndefined, TailCallMode::kDisallow,
masm, ConvertReceiverMode::kNullOrUndefined,
InterpreterPushArgsMode::kJSFunction);
}
void Builtins::Generate_InterpreterPushArgsThenCallWithFinalSpread(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kAny, TailCallMode::kDisallow,
masm, ConvertReceiverMode::kAny,
InterpreterPushArgsMode::kWithFinalSpread);
}
void Builtins::Generate_InterpreterPushArgsThenTailCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kAny, TailCallMode::kAllow,
InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushArgsThenTailCallFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kAny, TailCallMode::kAllow,
InterpreterPushArgsMode::kJSFunction);
}
void Builtins::Generate_InterpreterPushArgsThenConstruct(MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenConstructImpl(
masm, InterpreterPushArgsMode::kOther);

View File

@ -12,37 +12,25 @@ namespace v8 {
namespace internal {
Handle<Code> Builtins::InterpreterPushArgsThenCall(
ConvertReceiverMode receiver_mode, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
ConvertReceiverMode receiver_mode, InterpreterPushArgsMode mode) {
switch (mode) {
case InterpreterPushArgsMode::kJSFunction:
if (tail_call_mode == TailCallMode::kDisallow) {
switch (receiver_mode) {
case ConvertReceiverMode::kNullOrUndefined:
return InterpreterPushUndefinedAndArgsThenCallFunction();
case ConvertReceiverMode::kNotNullOrUndefined:
case ConvertReceiverMode::kAny:
return InterpreterPushArgsThenCallFunction();
}
} else {
CHECK_EQ(receiver_mode, ConvertReceiverMode::kAny);
return InterpreterPushArgsThenTailCallFunction();
switch (receiver_mode) {
case ConvertReceiverMode::kNullOrUndefined:
return InterpreterPushUndefinedAndArgsThenCallFunction();
case ConvertReceiverMode::kNotNullOrUndefined:
case ConvertReceiverMode::kAny:
return InterpreterPushArgsThenCallFunction();
}
case InterpreterPushArgsMode::kWithFinalSpread:
CHECK(tail_call_mode == TailCallMode::kDisallow);
return InterpreterPushArgsThenCallWithFinalSpread();
case InterpreterPushArgsMode::kOther:
if (tail_call_mode == TailCallMode::kDisallow) {
switch (receiver_mode) {
case ConvertReceiverMode::kNullOrUndefined:
return InterpreterPushUndefinedAndArgsThenCall();
case ConvertReceiverMode::kNotNullOrUndefined:
case ConvertReceiverMode::kAny:
return InterpreterPushArgsThenCall();
}
} else {
CHECK_EQ(receiver_mode, ConvertReceiverMode::kAny);
return InterpreterPushArgsThenTailCall();
switch (receiver_mode) {
case ConvertReceiverMode::kNullOrUndefined:
return InterpreterPushUndefinedAndArgsThenCall();
case ConvertReceiverMode::kNotNullOrUndefined:
case ConvertReceiverMode::kAny:
return InterpreterPushArgsThenCall();
}
}
UNREACHABLE();

View File

@ -53,17 +53,12 @@ class Builtins {
#undef DECLARE_BUILTIN_ACCESSOR
// Convenience wrappers.
Handle<Code> CallFunction(
ConvertReceiverMode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
Handle<Code> Call(ConvertReceiverMode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
Handle<Code> CallBoundFunction(TailCallMode tail_call_mode);
Handle<Code> CallFunction(ConvertReceiverMode = ConvertReceiverMode::kAny);
Handle<Code> Call(ConvertReceiverMode = ConvertReceiverMode::kAny);
Handle<Code> NonPrimitiveToPrimitive(
ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
Handle<Code> OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint);
Handle<Code> InterpreterPushArgsThenCall(ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode,
InterpreterPushArgsMode mode);
Handle<Code> InterpreterPushArgsThenConstruct(InterpreterPushArgsMode mode);
Handle<Code> NewFunctionContext(ScopeType scope_type);
@ -123,14 +118,11 @@ class Builtins {
Builtins();
static void Generate_CallFunction(MacroAssembler* masm,
ConvertReceiverMode mode,
TailCallMode tail_call_mode);
ConvertReceiverMode mode);
static void Generate_CallBoundFunctionImpl(MacroAssembler* masm,
TailCallMode tail_call_mode);
static void Generate_CallBoundFunctionImpl(MacroAssembler* masm);
static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
TailCallMode tail_call_mode);
static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode);
static void Generate_CallOrConstructVarargs(MacroAssembler* masm,
Handle<Code> code);
@ -139,7 +131,7 @@ class Builtins {
static void Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode);
InterpreterPushArgsMode mode);
static void Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode);

View File

@ -978,7 +978,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
InterpreterPushArgsMode 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
@ -1022,15 +1022,14 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl(
__ Push(edx); // Re-push return address.
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
__ Jump(
masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny),
RelocInfo::CODE_TARGET);
} else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
__ Jump(masm->isolate()->builtins()->CallWithSpread(),
RelocInfo::CODE_TARGET);
} else {
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny),
RelocInfo::CODE_TARGET);
}
@ -2381,99 +2380,9 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ Jump(code, RelocInfo::CODE_TARGET);
}
namespace {
// Drops top JavaScript frame and an arguments adaptor frame below it (if
// present) preserving all the arguments prepared for current call.
// Does nothing if debugger is currently active.
// ES6 14.6.3. PrepareForTailCall
//
// Stack structure for the function g() tail calling f():
//
// ------- Caller frame: -------
// | ...
// | g()'s arg M
// | ...
// | g()'s arg 1
// | g()'s receiver arg
// | g()'s caller pc
// ------- g()'s frame: -------
// | g()'s caller fp <- fp
// | g()'s context
// | function pointer: g
// | -------------------------
// | ...
// | ...
// | f()'s arg N
// | ...
// | f()'s arg 1
// | f()'s receiver arg
// | f()'s caller pc <- sp
// ----------------------
//
void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
Register scratch1, Register scratch2,
Register scratch3) {
DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
Comment cmnt(masm, "[ PrepareForTailCall");
// Prepare for tail call only if ES2015 tail call elimination is enabled.
Label done;
ExternalReference is_tail_call_elimination_enabled =
ExternalReference::is_tail_call_elimination_enabled_address(
masm->isolate());
__ movzx_b(scratch1,
Operand::StaticVariable(is_tail_call_elimination_enabled));
__ cmp(scratch1, Immediate(0));
__ j(equal, &done, Label::kNear);
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
Immediate(StackFrame::TypeToMarker(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.
Register caller_args_count_reg = scratch1;
Label no_arguments_adaptor, formal_parameter_count_loaded;
__ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ cmp(Operand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset),
Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(not_equal, &no_arguments_adaptor, Label::kNear);
// Drop current frame and load arguments count from arguments adaptor frame.
__ mov(ebp, scratch2);
__ mov(caller_args_count_reg,
Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ SmiUntag(caller_args_count_reg);
__ jmp(&formal_parameter_count_loaded, Label::kNear);
__ bind(&no_arguments_adaptor);
// Load caller's formal parameter count
__ mov(scratch1, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ mov(scratch1,
FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
__ mov(
caller_args_count_reg,
FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset));
__ bind(&formal_parameter_count_loaded);
ParameterCount callee_args_count(args_reg);
__ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
scratch3, ReturnAddressState::kOnStack, 0);
__ bind(&done);
}
} // namespace
// static
void Builtins::Generate_CallFunction(MacroAssembler* masm,
ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edi : the function to call (checked to be a JSFunction)
@ -2562,12 +2471,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
// -- esi : the function context.
// -----------------------------------
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, eax, ebx, ecx, edx);
// Reload shared function info.
__ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
}
__ mov(ebx,
FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
ParameterCount actual(eax);
@ -2670,18 +2573,13 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
} // namespace
// static
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
TailCallMode tail_call_mode) {
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edi : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(edi);
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, eax, ebx, ecx, edx);
}
// Patch the receiver to [[BoundThis]].
__ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
__ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
@ -2698,8 +2596,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edi : the target to call (can be any Object).
@ -2709,10 +2606,10 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ JumpIfSmi(edi, &non_callable);
__ bind(&non_smi);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
__ j(equal, masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
__ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
__ j(equal, masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET);
// Check if target has a [[Call]] internal method.
@ -2723,11 +2620,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ CmpInstanceType(ecx, JS_PROXY_TYPE);
__ j(not_equal, &non_function);
// 0. Prepare for tail call if necessary.
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, eax, ebx, ecx, edx);
}
// 1. Runtime fallback for Proxy [[Call]].
__ PopReturnAddressTo(ecx);
__ Push(edi);
@ -2747,7 +2639,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
// Let the "call_as_function_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
__ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.

View File

@ -1293,7 +1293,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a2 : the address of the first argument to be pushed. Subsequent
@ -1323,15 +1323,14 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl(
// Call the target.
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
__ Jump(
masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny),
RelocInfo::CODE_TARGET);
} else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
__ Jump(masm->isolate()->builtins()->CallWithSpread(),
RelocInfo::CODE_TARGET);
} else {
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny),
RelocInfo::CODE_TARGET);
}
@ -2212,100 +2211,9 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ Jump(code, RelocInfo::CODE_TARGET);
}
namespace {
// Drops top JavaScript frame and an arguments adaptor frame below it (if
// present) preserving all the arguments prepared for current call.
// Does nothing if debugger is currently active.
// ES6 14.6.3. PrepareForTailCall
//
// Stack structure for the function g() tail calling f():
//
// ------- Caller frame: -------
// | ...
// | g()'s arg M
// | ...
// | g()'s arg 1
// | g()'s receiver arg
// | g()'s caller pc
// ------- g()'s frame: -------
// | g()'s caller fp <- fp
// | g()'s context
// | function pointer: g
// | -------------------------
// | ...
// | ...
// | f()'s arg N
// | ...
// | f()'s arg 1
// | f()'s receiver arg <- sp (f()'s caller pc is not on the stack yet!)
// ----------------------
//
void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
Register scratch1, Register scratch2,
Register scratch3) {
DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
Comment cmnt(masm, "[ PrepareForTailCall");
// Prepare for tail call only if ES2015 tail call elimination is enabled.
Label done;
ExternalReference is_tail_call_elimination_enabled =
ExternalReference::is_tail_call_elimination_enabled_address(
masm->isolate());
__ li(at, Operand(is_tail_call_elimination_enabled));
__ lb(scratch1, MemOperand(at));
__ Branch(&done, eq, scratch1, Operand(zero_reg));
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ lw(scratch3,
MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&no_interpreter_frame, ne, scratch3,
Operand(StackFrame::TypeToMarker(StackFrame::STUB)));
__ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_interpreter_frame);
}
// Check if next frame is an arguments adaptor frame.
Register caller_args_count_reg = scratch1;
Label no_arguments_adaptor, formal_parameter_count_loaded;
__ lw(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ lw(scratch3,
MemOperand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&no_arguments_adaptor, ne, scratch3,
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
// Drop current frame and load arguments count from arguments adaptor frame.
__ mov(fp, scratch2);
__ lw(caller_args_count_reg,
MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ SmiUntag(caller_args_count_reg);
__ Branch(&formal_parameter_count_loaded);
__ bind(&no_arguments_adaptor);
// Load caller's formal parameter count
__ lw(scratch1,
MemOperand(fp, ArgumentsAdaptorFrameConstants::kFunctionOffset));
__ lw(scratch1,
FieldMemOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
__ lw(caller_args_count_reg,
FieldMemOperand(scratch1,
SharedFunctionInfo::kFormalParameterCountOffset));
__ bind(&formal_parameter_count_loaded);
ParameterCount callee_args_count(args_reg);
__ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
scratch3);
__ bind(&done);
}
} // namespace
// static
void Builtins::Generate_CallFunction(MacroAssembler* masm,
ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSFunction)
@ -2394,10 +2302,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
// -- cp : the function context.
// -----------------------------------
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, a0, t0, t1, t2);
}
__ lw(a2,
FieldMemOperand(a2, SharedFunctionInfo::kFormalParameterCountOffset));
ParameterCount actual(a0);
@ -2415,18 +2319,13 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
}
// static
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
TailCallMode tail_call_mode) {
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(a1);
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, a0, t0, t1, t2);
}
// Patch the receiver to [[BoundThis]].
{
__ lw(at, FieldMemOperand(a1, JSBoundFunction::kBoundThisOffset));
@ -2508,8 +2407,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the target to call (can be any Object).
@ -2519,9 +2417,9 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ JumpIfSmi(a1, &non_callable);
__ bind(&non_smi);
__ GetObjectType(a1, t1, t2);
__ Jump(masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
__ Jump(masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
// Check if target has a [[Call]] internal method.
@ -2531,11 +2429,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ Branch(&non_function, ne, t2, Operand(JS_PROXY_TYPE));
// 0. Prepare for tail call if necessary.
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, a0, t0, t1, t2);
}
// 1. Runtime fallback for Proxy [[Call]].
__ Push(a1);
// Increase the arguments size to include the pushed function and the
@ -2554,7 +2447,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
// Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, a1);
__ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.

View File

@ -1294,7 +1294,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a2 : the address of the first argument to be pushed. Subsequent
@ -1324,15 +1324,14 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl(
// Call the target.
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
__ Jump(
masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny),
RelocInfo::CODE_TARGET);
} else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
__ Jump(masm->isolate()->builtins()->CallWithSpread(),
RelocInfo::CODE_TARGET);
} else {
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny),
RelocInfo::CODE_TARGET);
}
@ -2237,99 +2236,9 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ Jump(code, RelocInfo::CODE_TARGET);
}
namespace {
// Drops top JavaScript frame and an arguments adaptor frame below it (if
// present) preserving all the arguments prepared for current call.
// Does nothing if debugger is currently active.
// ES6 14.6.3. PrepareForTailCall
//
// Stack structure for the function g() tail calling f():
//
// ------- Caller frame: -------
// | ...
// | g()'s arg M
// | ...
// | g()'s arg 1
// | g()'s receiver arg
// | g()'s caller pc
// ------- g()'s frame: -------
// | g()'s caller fp <- fp
// | g()'s context
// | function pointer: g
// | -------------------------
// | ...
// | ...
// | f()'s arg N
// | ...
// | f()'s arg 1
// | f()'s receiver arg <- sp (f()'s caller pc is not on the stack yet!)
// ----------------------
//
void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
Register scratch1, Register scratch2,
Register scratch3) {
DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
Comment cmnt(masm, "[ PrepareForTailCall");
// Prepare for tail call only if ES2015 tail call elimination is enabled.
Label done;
ExternalReference is_tail_call_elimination_enabled =
ExternalReference::is_tail_call_elimination_enabled_address(
masm->isolate());
__ li(at, Operand(is_tail_call_elimination_enabled));
__ Lb(scratch1, MemOperand(at));
__ Branch(&done, eq, scratch1, Operand(zero_reg));
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ Ld(scratch3,
MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&no_interpreter_frame, ne, scratch3,
Operand(StackFrame::TypeToMarker(StackFrame::STUB)));
__ Ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ bind(&no_interpreter_frame);
}
// Check if next frame is an arguments adaptor frame.
Register caller_args_count_reg = scratch1;
Label no_arguments_adaptor, formal_parameter_count_loaded;
__ Ld(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ Ld(scratch3,
MemOperand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&no_arguments_adaptor, ne, scratch3,
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
// Drop current frame and load arguments count from arguments adaptor frame.
__ mov(fp, scratch2);
__ Lw(caller_args_count_reg,
UntagSmiMemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ Branch(&formal_parameter_count_loaded);
__ bind(&no_arguments_adaptor);
// Load caller's formal parameter count
__ Ld(scratch1,
MemOperand(fp, ArgumentsAdaptorFrameConstants::kFunctionOffset));
__ Ld(scratch1,
FieldMemOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
__ Lw(caller_args_count_reg,
FieldMemOperand(scratch1,
SharedFunctionInfo::kFormalParameterCountOffset));
__ bind(&formal_parameter_count_loaded);
ParameterCount callee_args_count(args_reg);
__ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
scratch3);
__ bind(&done);
}
} // namespace
// static
void Builtins::Generate_CallFunction(MacroAssembler* masm,
ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSFunction)
@ -2418,10 +2327,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
// -- cp : the function context.
// -----------------------------------
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, a0, t0, t1, t2);
}
__ Lw(a2,
FieldMemOperand(a2, SharedFunctionInfo::kFormalParameterCountOffset));
ParameterCount actual(a0);
@ -2439,18 +2344,13 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
}
// static
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
TailCallMode tail_call_mode) {
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(a1);
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, a0, t0, t1, t2);
}
// Patch the receiver to [[BoundThis]].
{
__ Ld(at, FieldMemOperand(a1, JSBoundFunction::kBoundThisOffset));
@ -2531,8 +2431,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the target to call (can be any Object).
@ -2542,9 +2441,9 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ JumpIfSmi(a1, &non_callable);
__ bind(&non_smi);
__ GetObjectType(a1, t1, t2);
__ Jump(masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
__ Jump(masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
// Check if target has a [[Call]] internal method.
@ -2554,11 +2453,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ Branch(&non_function, ne, t2, Operand(JS_PROXY_TYPE));
// 0. Prepare for tail call if necessary.
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, a0, t0, t1, t2);
}
// 1. Runtime fallback for Proxy [[Call]].
__ Push(a1);
// Increase the arguments size to include the pushed function and the
@ -2577,7 +2471,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
// Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, a1);
__ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.

View File

@ -1047,7 +1047,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
InterpreterPushArgsMode 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
@ -1085,14 +1085,13 @@ void Builtins::Generate_InterpreterPushArgsThenCallImpl(
__ PushReturnAddressFrom(kScratchRegister); // Re-push return address.
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(receiver_mode,
tail_call_mode),
__ Jump(masm->isolate()->builtins()->CallFunction(receiver_mode),
RelocInfo::CODE_TARGET);
} else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
__ Jump(masm->isolate()->builtins()->CallWithSpread(),
RelocInfo::CODE_TARGET);
} else {
__ Jump(masm->isolate()->builtins()->Call(receiver_mode, tail_call_mode),
__ Jump(masm->isolate()->builtins()->Call(receiver_mode),
RelocInfo::CODE_TARGET);
}
@ -2467,98 +2466,9 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ Jump(code, RelocInfo::CODE_TARGET);
}
namespace {
// Drops top JavaScript frame and an arguments adaptor frame below it (if
// present) preserving all the arguments prepared for current call.
// Does nothing if debugger is currently active.
// ES6 14.6.3. PrepareForTailCall
//
// Stack structure for the function g() tail calling f():
//
// ------- Caller frame: -------
// | ...
// | g()'s arg M
// | ...
// | g()'s arg 1
// | g()'s receiver arg
// | g()'s caller pc
// ------- g()'s frame: -------
// | g()'s caller fp <- fp
// | g()'s context
// | function pointer: g
// | -------------------------
// | ...
// | ...
// | f()'s arg N
// | ...
// | f()'s arg 1
// | f()'s receiver arg
// | f()'s caller pc <- sp
// ----------------------
//
void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
Register scratch1, Register scratch2,
Register scratch3) {
DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
Comment cmnt(masm, "[ PrepareForTailCall");
// Prepare for tail call only if ES2015 tail call elimination is active.
Label done;
ExternalReference is_tail_call_elimination_enabled =
ExternalReference::is_tail_call_elimination_enabled_address(
masm->isolate());
__ Move(kScratchRegister, is_tail_call_elimination_enabled);
__ cmpb(Operand(kScratchRegister, 0), Immediate(0));
__ j(equal, &done);
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ cmpp(Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset),
Immediate(StackFrame::TypeToMarker(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.
Register caller_args_count_reg = scratch1;
Label no_arguments_adaptor, formal_parameter_count_loaded;
__ movp(scratch2, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
__ cmpp(Operand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset),
Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(not_equal, &no_arguments_adaptor, Label::kNear);
// Drop current frame and load arguments count from arguments adaptor frame.
__ movp(rbp, scratch2);
__ SmiToInteger32(
caller_args_count_reg,
Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ jmp(&formal_parameter_count_loaded, Label::kNear);
__ bind(&no_arguments_adaptor);
// Load caller's formal parameter count
__ movp(scratch1, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ movp(scratch1,
FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
__ movsxlq(
caller_args_count_reg,
FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset));
__ bind(&formal_parameter_count_loaded);
ParameterCount callee_args_count(args_reg);
__ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
scratch3, ReturnAddressState::kOnStack);
__ bind(&done);
}
} // namespace
// static
void Builtins::Generate_CallFunction(MacroAssembler* masm,
ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdi : the function to call (checked to be a JSFunction)
@ -2654,10 +2564,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
// -- rsi : the function context.
// -----------------------------------
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, rax, rbx, rcx, r8);
}
__ movsxlq(
rbx, FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
ParameterCount actual(rax);
@ -2760,18 +2666,13 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
} // namespace
// static
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
TailCallMode tail_call_mode) {
void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdi : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(rdi);
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, rax, rbx, rcx, r8);
}
// Patch the receiver to [[BoundThis]].
StackArgumentsAccessor args(rsp, rax);
__ movp(rbx, FieldOperand(rdi, JSBoundFunction::kBoundThisOffset));
@ -2789,8 +2690,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdi : the target to call (can be any Object)
@ -2801,10 +2701,10 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ JumpIfSmi(rdi, &non_callable);
__ bind(&non_smi);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
__ j(equal, masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(rcx, JS_BOUND_FUNCTION_TYPE);
__ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
__ j(equal, masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET);
// Check if target has a [[Call]] internal method.
@ -2815,11 +2715,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
__ CmpInstanceType(rcx, JS_PROXY_TYPE);
__ j(not_equal, &non_function);
// 0. Prepare for tail call if necessary.
if (tail_call_mode == TailCallMode::kAllow) {
PrepareForTailCall(masm, rax, rbx, rcx, r8);
}
// 1. Runtime fallback for Proxy [[Call]].
__ PopReturnAddressTo(kScratchRegister);
__ Push(rdi);
@ -2839,7 +2734,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
// Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, rdi);
__ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.

View File

@ -64,17 +64,15 @@ Callable CodeFactory::LoadGlobalICInOptimizedCode(Isolate* isolate,
}
// static
Callable CodeFactory::CallIC(Isolate* isolate, ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
CallICStub stub(isolate, mode, tail_call_mode);
Callable CodeFactory::CallIC(Isolate* isolate, ConvertReceiverMode mode) {
CallICStub stub(isolate, mode);
return make_callable(stub);
}
// static
Callable CodeFactory::CallICTrampoline(Isolate* isolate,
ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
CallICTrampolineStub stub(isolate, mode, tail_call_mode);
ConvertReceiverMode mode) {
CallICTrampolineStub stub(isolate, mode);
return make_callable(stub);
}
@ -305,9 +303,8 @@ Callable CodeFactory::ArgumentAdaptor(Isolate* isolate) {
}
// static
Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
return Callable(isolate->builtins()->Call(mode, tail_call_mode),
Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode) {
return Callable(isolate->builtins()->Call(mode),
CallTrampolineDescriptor(isolate));
}
@ -324,9 +321,8 @@ Callable CodeFactory::CallWithSpread(Isolate* isolate) {
}
// static
Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
return Callable(isolate->builtins()->CallFunction(mode, tail_call_mode),
Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) {
return Callable(isolate->builtins()->CallFunction(mode),
CallTrampolineDescriptor(isolate));
}
@ -387,10 +383,10 @@ Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) {
// static
Callable CodeFactory::InterpreterPushArgsThenCall(
Isolate* isolate, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
return Callable(isolate->builtins()->InterpreterPushArgsThenCall(
receiver_mode, tail_call_mode, mode),
InterpreterPushArgsThenCallDescriptor(isolate));
InterpreterPushArgsMode mode) {
return Callable(
isolate->builtins()->InterpreterPushArgsThenCall(receiver_mode, mode),
InterpreterPushArgsThenCallDescriptor(isolate));
}
// static

View File

@ -29,11 +29,9 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable LoadGlobalICInOptimizedCode(Isolate* isolate,
TypeofMode typeof_mode);
static Callable CallIC(Isolate* isolate,
ConvertReceiverMode mode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
ConvertReceiverMode mode = ConvertReceiverMode::kAny);
static Callable CallICTrampoline(
Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny);
static Callable StoreGlobalIC(Isolate* isolate, LanguageMode mode);
static Callable StoreGlobalICInOptimizedCode(Isolate* isolate,
LanguageMode mode);
@ -85,13 +83,11 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable ArgumentAdaptor(Isolate* isolate);
static Callable Call(Isolate* isolate,
ConvertReceiverMode mode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
ConvertReceiverMode mode = ConvertReceiverMode::kAny);
static Callable CallWithArrayLike(Isolate* isolate);
static Callable CallWithSpread(Isolate* isolate);
static Callable CallFunction(
Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny);
static Callable CallVarargs(Isolate* isolate);
static Callable CallForwardVarargs(Isolate* isolate);
static Callable CallFunctionForwardVarargs(Isolate* isolate);
@ -104,7 +100,6 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable InterpreterPushArgsThenCall(Isolate* isolate,
ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode,
InterpreterPushArgsMode mode);
static Callable InterpreterPushArgsThenConstruct(
Isolate* isolate, InterpreterPushArgsMode mode);

View File

@ -572,7 +572,7 @@ TF_STUB(LoadIndexedInterceptorStub, CodeStubAssembler) {
}
void CallICStub::PrintState(std::ostream& os) const { // NOLINT
os << convert_mode() << ", " << tail_call_mode();
os << convert_mode();
}
// TODO(ishell): Move to CallICAssembler.
@ -626,8 +626,8 @@ TF_STUB(CallICStub, CodeStubAssembler) {
BIND(&call_function);
{
// Call using CallFunction builtin.
Callable callable = CodeFactory::CallFunction(
isolate(), stub->convert_mode(), stub->tail_call_mode());
Callable callable =
CodeFactory::CallFunction(isolate(), stub->convert_mode());
TailCallStub(callable, context, target, argc);
}
@ -729,8 +729,7 @@ TF_STUB(CallICStub, CodeStubAssembler) {
{
// Call using call builtin.
Comment("call using Call builtin");
Callable callable_call = CodeFactory::Call(isolate(), stub->convert_mode(),
stub->tail_call_mode());
Callable callable_call = CodeFactory::Call(isolate(), stub->convert_mode());
TailCallStub(callable_call, context, target, argc);
}
}
@ -742,8 +741,7 @@ TF_STUB(CallICTrampolineStub, CodeStubAssembler) {
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = LoadFeedbackVectorForStub();
Callable callable = CodeFactory::CallIC(isolate(), stub->convert_mode(),
stub->tail_call_mode());
Callable callable = CodeFactory::CallIC(isolate(), stub->convert_mode());
TailCallStub(callable, context, target, argc, slot, vector);
}

View File

@ -732,23 +732,17 @@ class MathPowStub: public PlatformCodeStub {
class CallICStub : public TurboFanCodeStub {
public:
CallICStub(Isolate* isolate, ConvertReceiverMode convert_mode,
TailCallMode tail_call_mode)
CallICStub(Isolate* isolate, ConvertReceiverMode convert_mode)
: TurboFanCodeStub(isolate) {
minor_key_ = ConvertModeBits::encode(convert_mode) |
TailCallModeBits::encode(tail_call_mode);
minor_key_ = ConvertModeBits::encode(convert_mode);
}
ConvertReceiverMode convert_mode() const {
return ConvertModeBits::decode(minor_key_);
}
TailCallMode tail_call_mode() const {
return TailCallModeBits::decode(minor_key_);
}
protected:
typedef BitField<ConvertReceiverMode, 0, 2> ConvertModeBits;
typedef BitField<TailCallMode, ConvertModeBits::kNext, 1> TailCallModeBits;
private:
void PrintState(std::ostream& os) const final; // NOLINT
@ -1090,9 +1084,8 @@ class StringCharCodeAtGenerator {
class CallICTrampolineStub : public CallICStub {
public:
CallICTrampolineStub(Isolate* isolate, ConvertReceiverMode convert_mode,
TailCallMode tail_call_mode)
: CallICStub(isolate, convert_mode, tail_call_mode) {}
CallICTrampolineStub(Isolate* isolate, ConvertReceiverMode convert_mode)
: CallICStub(isolate, convert_mode) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(CallICTrampoline);
DEFINE_TURBOFAN_CODE_STUB(CallICTrampoline, CallICStub);

View File

@ -1490,9 +1490,8 @@ void AstGraphBuilder::VisitCall(Call* expr) {
// Create node to perform the function call.
CallFrequency frequency = ComputeCallFrequency(expr->CallFeedbackICSlot());
VectorSlotPair feedback = CreateVectorSlotPair(expr->CallFeedbackICSlot());
const Operator* call =
javascript()->Call(args->length() + 2, frequency, feedback, receiver_hint,
expr->tail_call_mode());
const Operator* call = javascript()->Call(args->length() + 2, frequency,
feedback, receiver_hint);
Node* value = ProcessArguments(call, args->length() + 2);
ast_context()->ProduceValue(expr, value);
}

View File

@ -1357,8 +1357,7 @@ Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
return ProcessCallArguments(call_op, call_args, 2 + arg_count);
}
void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode,
ConvertReceiverMode receiver_mode,
void BytecodeGraphBuilder::BuildCall(ConvertReceiverMode receiver_mode,
Node* const* args, size_t arg_count,
int slot_id) {
DCHECK_EQ(interpreter::Bytecodes::GetReceiverMode(
@ -1372,8 +1371,8 @@ void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode,
VectorSlotPair feedback = CreateVectorSlotPair(slot_id);
CallFrequency frequency = ComputeCallFrequency(slot_id);
const Operator* op = javascript()->Call(arg_count, frequency, feedback,
receiver_mode, tail_call_mode);
const Operator* op =
javascript()->Call(arg_count, frequency, feedback, receiver_mode);
Node* node = nullptr;
if (Node* simplified = TryBuildSimplifiedCall(
op, args, static_cast<int>(arg_count), feedback.slot())) {
@ -1385,8 +1384,7 @@ void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode,
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::BuildCallVarArgs(TailCallMode tail_call_mode,
ConvertReceiverMode receiver_mode) {
void BytecodeGraphBuilder::BuildCallVarArgs(ConvertReceiverMode receiver_mode) {
DCHECK_EQ(interpreter::Bytecodes::GetReceiverMode(
bytecode_iterator().current_bytecode()),
receiver_mode);
@ -1417,17 +1415,16 @@ void BytecodeGraphBuilder::BuildCallVarArgs(TailCallMode tail_call_mode,
Node* const* call_args =
GetCallArgumentsFromRegister(callee, receiver_node, first_arg, arg_count);
BuildCall(tail_call_mode, receiver_mode, call_args,
static_cast<size_t>(2 + arg_count), slot_id);
BuildCall(receiver_mode, call_args, static_cast<size_t>(2 + arg_count),
slot_id);
}
void BytecodeGraphBuilder::VisitCallAnyReceiver() {
BuildCallVarArgs(TailCallMode::kDisallow, ConvertReceiverMode::kAny);
BuildCallVarArgs(ConvertReceiverMode::kAny);
}
void BytecodeGraphBuilder::VisitCallProperty() {
BuildCallVarArgs(TailCallMode::kDisallow,
ConvertReceiverMode::kNotNullOrUndefined);
BuildCallVarArgs(ConvertReceiverMode::kNotNullOrUndefined);
}
void BytecodeGraphBuilder::VisitCallProperty0() {
@ -1436,8 +1433,8 @@ void BytecodeGraphBuilder::VisitCallProperty0() {
Node* receiver =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
int const slot_id = bytecode_iterator().GetIndexOperand(2);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNotNullOrUndefined,
{callee, receiver}, slot_id);
BuildCall(ConvertReceiverMode::kNotNullOrUndefined, {callee, receiver},
slot_id);
}
void BytecodeGraphBuilder::VisitCallProperty1() {
@ -1448,8 +1445,8 @@ void BytecodeGraphBuilder::VisitCallProperty1() {
Node* arg0 =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(2));
int const slot_id = bytecode_iterator().GetIndexOperand(3);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNotNullOrUndefined,
{callee, receiver, arg0}, slot_id);
BuildCall(ConvertReceiverMode::kNotNullOrUndefined, {callee, receiver, arg0},
slot_id);
}
void BytecodeGraphBuilder::VisitCallProperty2() {
@ -1462,13 +1459,12 @@ void BytecodeGraphBuilder::VisitCallProperty2() {
Node* arg1 =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(3));
int const slot_id = bytecode_iterator().GetIndexOperand(4);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNotNullOrUndefined,
BuildCall(ConvertReceiverMode::kNotNullOrUndefined,
{callee, receiver, arg0, arg1}, slot_id);
}
void BytecodeGraphBuilder::VisitCallUndefinedReceiver() {
BuildCallVarArgs(TailCallMode::kDisallow,
ConvertReceiverMode::kNullOrUndefined);
BuildCallVarArgs(ConvertReceiverMode::kNullOrUndefined);
}
void BytecodeGraphBuilder::VisitCallUndefinedReceiver0() {
@ -1476,8 +1472,7 @@ void BytecodeGraphBuilder::VisitCallUndefinedReceiver0() {
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* receiver = jsgraph()->UndefinedConstant();
int const slot_id = bytecode_iterator().GetIndexOperand(1);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNullOrUndefined,
{callee, receiver}, slot_id);
BuildCall(ConvertReceiverMode::kNullOrUndefined, {callee, receiver}, slot_id);
}
void BytecodeGraphBuilder::VisitCallUndefinedReceiver1() {
@ -1487,8 +1482,8 @@ void BytecodeGraphBuilder::VisitCallUndefinedReceiver1() {
Node* arg0 =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
int const slot_id = bytecode_iterator().GetIndexOperand(2);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNullOrUndefined,
{callee, receiver, arg0}, slot_id);
BuildCall(ConvertReceiverMode::kNullOrUndefined, {callee, receiver, arg0},
slot_id);
}
void BytecodeGraphBuilder::VisitCallUndefinedReceiver2() {
@ -1500,7 +1495,7 @@ void BytecodeGraphBuilder::VisitCallUndefinedReceiver2() {
Node* arg1 =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(2));
int const slot_id = bytecode_iterator().GetIndexOperand(3);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNullOrUndefined,
BuildCall(ConvertReceiverMode::kNullOrUndefined,
{callee, receiver, arg0, arg1}, slot_id);
}
@ -1517,14 +1512,6 @@ void BytecodeGraphBuilder::VisitCallWithSpread() {
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitTailCall() {
TailCallMode tail_call_mode =
bytecode_array_->GetIsolate()->is_tail_call_elimination_enabled()
? TailCallMode::kAllow
: TailCallMode::kDisallow;
BuildCallVarArgs(tail_call_mode, ConvertReceiverMode::kAny);
}
void BytecodeGraphBuilder::VisitCallJSRuntime() {
PrepareEagerCheckpoint();
Node* callee =

View File

@ -159,14 +159,12 @@ class BytecodeGraphBuilder {
void BuildLdaLookupSlot(TypeofMode typeof_mode);
void BuildLdaLookupContextSlot(TypeofMode typeof_mode);
void BuildLdaLookupGlobalSlot(TypeofMode typeof_mode);
void BuildCallVarArgs(TailCallMode tail_call_mode,
ConvertReceiverMode receiver_mode);
void BuildCall(TailCallMode tail_call_mode, ConvertReceiverMode receiver_mode,
Node* const* args, size_t arg_count, int slot_id);
void BuildCall(TailCallMode tail_call_mode, ConvertReceiverMode receiver_mode,
void BuildCallVarArgs(ConvertReceiverMode receiver_mode);
void BuildCall(ConvertReceiverMode receiver_mode, Node* const* args,
size_t arg_count, int slot_id);
void BuildCall(ConvertReceiverMode receiver_mode,
std::initializer_list<Node*> args, int slot_id) {
BuildCall(tail_call_mode, receiver_mode, args.begin(), args.size(),
slot_id);
BuildCall(receiver_mode, args.begin(), args.size(), slot_id);
}
void BuildBinaryOp(const Operator* op);
void BuildBinaryOpWithImmediate(const Operator* op);

View File

@ -806,9 +806,6 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
shared_info_id,
static_cast<unsigned int>(descriptor->parameters_count()));
break;
case FrameStateType::kTailCallerFunction:
translation->BeginTailCallerFrame(shared_info_id);
break;
case FrameStateType::kConstructStub:
DCHECK(descriptor->bailout_id().IsValidForConstructStub());
translation->BeginConstructStubFrame(

View File

@ -54,9 +54,6 @@ std::ostream& operator<<(std::ostream& os, FrameStateType type) {
case FrameStateType::kArgumentsAdaptor:
os << "ARGUMENTS_ADAPTOR";
break;
case FrameStateType::kTailCallerFunction:
os << "TAIL_CALLER_FRAME";
break;
case FrameStateType::kConstructStub:
os << "CONSTRUCT_STUB";
break;

View File

@ -62,7 +62,6 @@ class OutputFrameStateCombine {
enum class FrameStateType {
kInterpretedFunction, // Represents an InterpretedFrame.
kArgumentsAdaptor, // Represents an ArgumentsAdaptorFrame.
kTailCallerFunction, // Represents a frame removed by tail call elimination.
kConstructStub, // Represents a ConstructStubFrame.
kGetterStub, // Represents a GetterStubFrame.
kSetterStub, // Represents a SetterStubFrame.

View File

@ -765,10 +765,8 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
buffer->frame_state_descriptor =
buffer->frame_state_descriptor->outer_state();
while (buffer->frame_state_descriptor != nullptr &&
(buffer->frame_state_descriptor->type() ==
FrameStateType::kArgumentsAdaptor ||
buffer->frame_state_descriptor->type() ==
FrameStateType::kTailCallerFunction)) {
buffer->frame_state_descriptor->type() ==
FrameStateType::kArgumentsAdaptor) {
frame_state = NodeProperties::GetFrameStateInput(frame_state);
buffer->frame_state_descriptor =
buffer->frame_state_descriptor->outer_state();

View File

@ -158,10 +158,6 @@ bool CanBeNullOrUndefined(Node* node) {
Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
// Tail calls to Function.prototype.apply are not properly supported
// down the pipeline, so we disable this optimization completely for
// tail calls (for now).
if (p.tail_call_mode() == TailCallMode::kAllow) return NoChange();
size_t arity = p.arity();
DCHECK_LE(2u, arity);
ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny;
@ -268,8 +264,7 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
// Change {node} to the new {JSCall} operator.
NodeProperties::ChangeOp(
node,
javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode,
p.tail_call_mode()));
javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode));
// Try to further reduce the JSCall {node}.
Reduction const reduction = ReduceJSCall(node);
return reduction.Changed() ? reduction : Changed(node);
@ -305,8 +300,7 @@ Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
}
NodeProperties::ChangeOp(
node,
javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode,
p.tail_call_mode()));
javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode));
// Try to further reduce the JSCall {node}.
Reduction const reduction = ReduceJSCall(node);
return reduction.Changed() ? reduction : Changed(node);
@ -1131,8 +1125,7 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
Operator const* op =
(node->opcode() == IrOpcode::kJSCallWithArrayLike ||
node->opcode() == IrOpcode::kJSCallWithSpread)
? javascript()->CallForwardVarargs(arity + 1, start_index,
TailCallMode::kDisallow)
? javascript()->CallForwardVarargs(arity + 1, start_index)
: javascript()->ConstructForwardVarargs(arity + 2, start_index);
NodeProperties::ChangeOp(node, op);
return Changed(node);
@ -1293,9 +1286,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
arity++;
}
NodeProperties::ChangeOp(
node,
javascript()->Call(arity, p.frequency(), VectorSlotPair(),
convert_mode, p.tail_call_mode()));
node, javascript()->Call(arity, p.frequency(), VectorSlotPair(),
convert_mode));
// Try to further reduce the JSCall {node}.
Reduction const reduction = ReduceJSCall(node);
return reduction.Changed() ? reduction : Changed(node);

View File

@ -637,9 +637,6 @@ void JSGenericLowering::LowerJSCallForwardVarargs(Node* node) {
int const arg_count = static_cast<int>(p.arity() - 2);
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
Callable callable = CodeFactory::CallForwardVarargs(isolate());
if (p.tail_call_mode() == TailCallMode::kAllow) {
flags |= CallDescriptor::kSupportsTailCalls;
}
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
@ -657,9 +654,6 @@ void JSGenericLowering::LowerJSCall(Node* node) {
ConvertReceiverMode const mode = p.convert_mode();
Callable callable = CodeFactory::Call(isolate(), mode);
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
if (p.tail_call_mode() == TailCallMode::kAllow) {
flags |= CallDescriptor::kSupportsTailCalls;
}
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
Node* stub_code = jsgraph()->HeapConstant(callable.code());

View File

@ -250,36 +250,6 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
outer_frame_state);
}
Node* JSInliner::CreateTailCallerFrameState(Node* node, Node* frame_state) {
FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
Handle<SharedFunctionInfo> shared;
frame_info.shared_info().ToHandle(&shared);
Node* function = frame_state->InputAt(kFrameStateFunctionInput);
// If we are inlining a tail call drop caller's frame state and an
// arguments adaptor if it exists.
frame_state = NodeProperties::GetFrameStateInput(frame_state);
if (frame_state->opcode() == IrOpcode::kFrameState) {
FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
if (frame_info.type() == FrameStateType::kArgumentsAdaptor) {
frame_state = NodeProperties::GetFrameStateInput(frame_state);
}
}
const FrameStateFunctionInfo* state_info =
common()->CreateFrameStateFunctionInfo(
FrameStateType::kTailCallerFunction, 0, 0, shared);
const Operator* op = common()->FrameState(
BailoutId(-1), OutputFrameStateCombine::Ignore(), state_info);
const Operator* op0 = common()->StateValues(0, SparseInputMask::Dense());
Node* node0 = graph()->NewNode(op0);
return graph()->NewNode(op, node0, node0, node0,
jsgraph()->UndefinedConstant(), function,
frame_state);
}
namespace {
// TODO(bmeurer): Unify this with the witness helper functions in the
@ -752,20 +722,6 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
}
}
// If we are inlining a JS call at tail position then we have to pop current
// frame state and its potential arguments adaptor frame state in order to
// make the call stack be consistent with non-inlining case.
// After that we add a tail caller frame state which lets deoptimizer handle
// the case when the outermost function inlines a tail call (it should remove
// potential arguments adaptor frame that belongs to outermost function when
// deopt happens).
if (node->opcode() == IrOpcode::kJSCall) {
const CallParameters& p = CallParametersOf(node->op());
if (p.tail_call_mode() == TailCallMode::kAllow) {
frame_state = CreateTailCallerFrameState(node, frame_state);
}
}
// Insert argument adaptor frame if required. The callees formal parameter
// count (i.e. value outputs of start node minus target, receiver, new target,
// arguments count and context) have to match the number of arguments passed

View File

@ -62,8 +62,6 @@ class JSInliner final : public AdvancedReducer {
FrameStateType frame_state_type,
Handle<SharedFunctionInfo> shared);
Node* CreateTailCallerFrameState(Node* node, Node* outer_frame_state);
Reduction InlineCall(Node* call, Node* new_target, Node* context,
Node* frame_state, Node* start, Node* end,
Node* exception_target,

View File

@ -146,9 +146,7 @@ StringConcatParameter const& StringConcatParameterOf(Operator const* op) {
}
std::ostream& operator<<(std::ostream& os, CallParameters const& p) {
os << p.arity() << ", " << p.frequency() << ", " << p.convert_mode() << ", "
<< p.tail_call_mode();
return os;
return os << p.arity() << ", " << p.frequency() << ", " << p.convert_mode();
}
const CallParameters& CallParametersOf(const Operator* op) {
@ -158,8 +156,7 @@ const CallParameters& CallParametersOf(const Operator* op) {
std::ostream& operator<<(std::ostream& os,
CallForwardVarargsParameters const& p) {
return os << p.arity() << ", " << p.start_index() << ", "
<< p.tail_call_mode();
return os << p.arity() << ", " << p.start_index();
}
CallForwardVarargsParameters const& CallForwardVarargsParametersOf(
@ -804,9 +801,9 @@ const Operator* JSOperatorBuilder::ToBoolean(ToBooleanHints hints) {
hints); // parameter
}
const Operator* JSOperatorBuilder::CallForwardVarargs(
size_t arity, uint32_t start_index, TailCallMode tail_call_mode) {
CallForwardVarargsParameters parameters(arity, start_index, tail_call_mode);
const Operator* JSOperatorBuilder::CallForwardVarargs(size_t arity,
uint32_t start_index) {
CallForwardVarargsParameters parameters(arity, start_index);
return new (zone()) Operator1<CallForwardVarargsParameters>( // --
IrOpcode::kJSCallForwardVarargs, Operator::kNoProperties, // opcode
"JSCallForwardVarargs", // name
@ -816,10 +813,8 @@ const Operator* JSOperatorBuilder::CallForwardVarargs(
const Operator* JSOperatorBuilder::Call(size_t arity, CallFrequency frequency,
VectorSlotPair const& feedback,
ConvertReceiverMode convert_mode,
TailCallMode tail_call_mode) {
CallParameters parameters(arity, frequency, feedback, tail_call_mode,
convert_mode);
ConvertReceiverMode convert_mode) {
CallParameters parameters(arity, frequency, feedback, convert_mode);
return new (zone()) Operator1<CallParameters>( // --
IrOpcode::kJSCall, Operator::kNoProperties, // opcode
"JSCall", // name

View File

@ -182,17 +182,12 @@ SpreadWithArityParameter const& SpreadWithArityParameterOf(Operator const*);
// is used as parameter by JSCallForwardVarargs operators.
class CallForwardVarargsParameters final {
public:
CallForwardVarargsParameters(size_t arity, uint32_t start_index,
TailCallMode tail_call_mode)
CallForwardVarargsParameters(size_t arity, uint32_t start_index)
: bit_field_(ArityField::encode(arity) |
StartIndexField::encode(start_index) |
TailCallModeField::encode(tail_call_mode)) {}
StartIndexField::encode(start_index)) {}
size_t arity() const { return ArityField::decode(bit_field_); }
uint32_t start_index() const { return StartIndexField::decode(bit_field_); }
TailCallMode tail_call_mode() const {
return TailCallModeField::decode(bit_field_);
}
bool operator==(CallForwardVarargsParameters const& that) const {
return this->bit_field_ == that.bit_field_;
@ -208,7 +203,6 @@ class CallForwardVarargsParameters final {
typedef BitField<size_t, 0, 15> ArityField;
typedef BitField<uint32_t, 15, 15> StartIndexField;
typedef BitField<TailCallMode, 30, 1> TailCallModeField;
uint32_t const bit_field_;
};
@ -223,11 +217,10 @@ CallForwardVarargsParameters const& CallForwardVarargsParametersOf(
class CallParameters final {
public:
CallParameters(size_t arity, CallFrequency frequency,
VectorSlotPair const& feedback, TailCallMode tail_call_mode,
VectorSlotPair const& feedback,
ConvertReceiverMode convert_mode)
: bit_field_(ArityField::encode(arity) |
ConvertReceiverModeField::encode(convert_mode) |
TailCallModeField::encode(tail_call_mode)),
ConvertReceiverModeField::encode(convert_mode)),
frequency_(frequency),
feedback_(feedback) {}
@ -236,9 +229,6 @@ class CallParameters final {
ConvertReceiverMode convert_mode() const {
return ConvertReceiverModeField::decode(bit_field_);
}
TailCallMode tail_call_mode() const {
return TailCallModeField::decode(bit_field_);
}
VectorSlotPair const& feedback() const { return feedback_; }
bool operator==(CallParameters const& that) const {
@ -255,7 +245,6 @@ class CallParameters final {
typedef BitField<size_t, 0, 29> ArityField;
typedef BitField<ConvertReceiverMode, 29, 2> ConvertReceiverModeField;
typedef BitField<TailCallMode, 31, 1> TailCallModeField;
uint32_t const bit_field_;
CallFrequency const frequency_;
@ -726,13 +715,11 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* CreateLiteralRegExp(Handle<String> constant_pattern,
int literal_flags, int literal_index);
const Operator* CallForwardVarargs(size_t arity, uint32_t start_index,
TailCallMode tail_call_mode);
const Operator* CallForwardVarargs(size_t arity, uint32_t start_index);
const Operator* Call(
size_t arity, CallFrequency frequency = CallFrequency(),
VectorSlotPair const& feedback = VectorSlotPair(),
ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny);
const Operator* CallWithArrayLike(CallFrequency frequency);
const Operator* CallWithSpread(uint32_t arity);
const Operator* CallRuntime(Runtime::FunctionId id);

View File

@ -2163,10 +2163,6 @@ Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
if (target_type->Is(Type::Function())) {
// Compute flags for the call.
CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
if (p.tail_call_mode() == TailCallMode::kAllow) {
flags |= CallDescriptor::kSupportsTailCalls;
}
// Patch {node} to an indirect call via CallFunctionForwardVarargs.
Callable callable = CodeFactory::CallFunctionForwardVarargs(isolate());
node->InsertInput(graph()->zone(), 0,
@ -2235,10 +2231,6 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
// Compute flags for the call.
CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
if (p.tail_call_mode() == TailCallMode::kAllow) {
flags |= CallDescriptor::kSupportsTailCalls;
}
Node* new_target = jsgraph()->UndefinedConstant();
Node* argument_count = jsgraph()->Constant(arity);
if (NeedsArgumentAdaptorFrame(shared, arity)) {
@ -2274,10 +2266,6 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
if (target_type->Is(Type::Function())) {
// Compute flags for the call.
CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
if (p.tail_call_mode() == TailCallMode::kAllow) {
flags |= CallDescriptor::kSupportsTailCalls;
}
// Patch {node} to an indirect call via the CallFunction builtin.
Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
node->InsertInput(graph()->zone(), 0,
@ -2293,9 +2281,8 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
// Maybe we did at least learn something about the {receiver}.
if (p.convert_mode() != convert_mode) {
NodeProperties::ChangeOp(
node,
javascript()->Call(p.arity(), p.frequency(), p.feedback(), convert_mode,
p.tail_call_mode()));
node, javascript()->Call(p.arity(), p.frequency(), p.feedback(),
convert_mode));
return Changed(node);
}

View File

@ -190,7 +190,6 @@ int CodeBreakIterator::GetModeMask() {
int mask = 0;
mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN);
mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL);
mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL);
mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
return mask;
}
@ -225,10 +224,6 @@ DebugBreakType CodeBreakIterator::GetDebugBreakType() {
return DEBUG_BREAK_SLOT_AT_RETURN;
} else if (RelocInfo::IsDebugBreakSlotAtCall(rmode())) {
return DEBUG_BREAK_SLOT_AT_CALL;
} else if (RelocInfo::IsDebugBreakSlotAtTailCall(rmode())) {
return isolate()->is_tail_call_elimination_enabled()
? DEBUG_BREAK_SLOT_AT_TAIL_CALL
: DEBUG_BREAK_SLOT_AT_CALL;
} else if (RelocInfo::IsDebugBreakSlot(rmode())) {
return DEBUG_BREAK_SLOT;
} else {
@ -311,10 +306,6 @@ DebugBreakType BytecodeArrayBreakIterator::GetDebugBreakType() {
return DEBUGGER_STATEMENT;
} else if (bytecode == interpreter::Bytecode::kReturn) {
return DEBUG_BREAK_SLOT_AT_RETURN;
} else if (bytecode == interpreter::Bytecode::kTailCall) {
return isolate()->is_tail_call_elimination_enabled()
? DEBUG_BREAK_SLOT_AT_TAIL_CALL
: DEBUG_BREAK_SLOT_AT_CALL;
} else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) {
return DEBUG_BREAK_SLOT_AT_CALL;
} else if (source_position_iterator_.is_statement()) {
@ -552,8 +543,6 @@ void Debug::Break(JavaScriptFrame* frame) {
case StepNext:
// Step next should not break in a deeper frame than target frame.
if (current_frame_count > target_frame_count) return;
// For step-next, a tail call is like a return and should break.
step_break = location.IsTailCall();
// Fall through.
case StepIn: {
FrameSummary summary = FrameSummary::GetTop(frame);
@ -1029,8 +1018,6 @@ void Debug::PrepareStep(StepAction step_action) {
}
UpdateHookOnFunctionCall();
// A step-next at a tail call is a step-out.
if (location.IsTailCall() && step_action == StepNext) step_action = StepOut;
// A step-next in blackboxed function is a step-out.
if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut;
@ -1664,7 +1651,7 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
DCHECK(!frame->is_optimized());
Handle<DebugInfo> debug_info(shared->GetDebugInfo());
BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
return location.IsReturn() || location.IsTailCall();
return location.IsReturn();
}
void Debug::ScheduleFrameRestart(StackFrame* frame) {

View File

@ -56,7 +56,6 @@ enum DebugBreakType {
DEBUG_BREAK_SLOT,
DEBUG_BREAK_SLOT_AT_CALL,
DEBUG_BREAK_SLOT_AT_RETURN,
DEBUG_BREAK_SLOT_AT_TAIL_CALL,
};
enum IgnoreBreakMode {
@ -75,9 +74,6 @@ class BreakLocation {
inline bool IsReturn() const { return type_ == DEBUG_BREAK_SLOT_AT_RETURN; }
inline bool IsCall() const { return type_ == DEBUG_BREAK_SLOT_AT_CALL; }
inline bool IsTailCall() const {
return type_ == DEBUG_BREAK_SLOT_AT_TAIL_CALL;
}
inline bool IsDebugBreakSlot() const { return type_ >= DEBUG_BREAK_SLOT; }
inline bool IsDebuggerStatement() const {
return type_ == DEBUGGER_STATEMENT;

View File

@ -767,12 +767,6 @@ void Deoptimizer::DoComputeOutputFrames() {
case TranslatedFrame::kArgumentsAdaptor:
DoComputeArgumentsAdaptorFrame(translated_frame, frame_index);
break;
case TranslatedFrame::kTailCallerFunction:
DoComputeTailCallerFrame(translated_frame, frame_index);
// Tail caller frame translations do not produce output frames.
frame_index--;
output_count_--;
break;
case TranslatedFrame::kConstructStub:
DoComputeConstructStubFrame(translated_frame, frame_index);
break;
@ -1206,70 +1200,6 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(
}
}
void Deoptimizer::DoComputeTailCallerFrame(TranslatedFrame* translated_frame,
int frame_index) {
SharedFunctionInfo* shared = translated_frame->raw_shared_info();
bool is_bottommost = (0 == frame_index);
// Tail caller frame can't be topmost.
CHECK_NE(output_count_ - 1, frame_index);
if (trace_scope_ != NULL) {
PrintF(trace_scope_->file(), " translating tail caller frame ");
std::unique_ptr<char[]> name = shared->DebugName()->ToCString();
PrintF(trace_scope_->file(), "%s\n", name.get());
}
if (!is_bottommost) return;
// Drop arguments adaptor frame below current frame if it exsits.
Address fp_address = input_->GetFramePointerAddress();
Address adaptor_fp_address =
Memory::Address_at(fp_address + CommonFrameConstants::kCallerFPOffset);
if (StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR) !=
Memory::intptr_at(adaptor_fp_address +
CommonFrameConstants::kContextOrFrameTypeOffset)) {
return;
}
int caller_params_count =
Smi::cast(
Memory::Object_at(adaptor_fp_address +
ArgumentsAdaptorFrameConstants::kLengthOffset))
->value();
int callee_params_count =
function_->shared()->internal_formal_parameter_count();
// Both caller and callee parameters count do not include receiver.
int offset = (caller_params_count - callee_params_count) * kPointerSize;
intptr_t new_stack_fp =
reinterpret_cast<intptr_t>(adaptor_fp_address) + offset;
intptr_t new_caller_frame_top = new_stack_fp +
(callee_params_count + 1) * kPointerSize +
CommonFrameConstants::kFixedFrameSizeAboveFp;
intptr_t adaptor_caller_pc = Memory::intptr_at(
adaptor_fp_address + CommonFrameConstants::kCallerPCOffset);
intptr_t adaptor_caller_fp = Memory::intptr_at(
adaptor_fp_address + CommonFrameConstants::kCallerFPOffset);
if (trace_scope_ != NULL) {
PrintF(trace_scope_->file(),
" dropping caller arguments adaptor frame: offset=%d, "
"fp: 0x%08" V8PRIxPTR " -> 0x%08" V8PRIxPTR
", "
"caller sp: 0x%08" V8PRIxPTR " -> 0x%08" V8PRIxPTR "\n",
offset, stack_fp_, new_stack_fp, caller_frame_top_,
new_caller_frame_top);
}
caller_frame_top_ = new_caller_frame_top;
caller_fp_ = adaptor_caller_fp;
caller_pc_ = adaptor_caller_pc;
}
void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
int frame_index) {
TranslatedFrame::iterator value_iterator = translated_frame->begin();
@ -2219,11 +2149,6 @@ void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
buffer_->Add(height);
}
void Translation::BeginTailCallerFrame(int literal_id) {
buffer_->Add(TAIL_CALLER_FRAME);
buffer_->Add(literal_id);
}
void Translation::BeginInterpretedFrame(BailoutId bytecode_offset,
int literal_id, unsigned height) {
buffer_->Add(INTERPRETED_FRAME);
@ -2354,7 +2279,6 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
case FLOAT_STACK_SLOT:
case DOUBLE_STACK_SLOT:
case LITERAL:
case TAIL_CALLER_FRAME:
return 1;
case BEGIN:
case ARGUMENTS_ADAPTOR_FRAME:
@ -2912,12 +2836,6 @@ TranslatedFrame TranslatedFrame::ArgumentsAdaptorFrame(
shared_info, height);
}
TranslatedFrame TranslatedFrame::TailCallerFrame(
SharedFunctionInfo* shared_info) {
return TranslatedFrame(kTailCallerFunction, shared_info->GetIsolate(),
shared_info, 0);
}
TranslatedFrame TranslatedFrame::ConstructStubFrame(
BailoutId bailout_id, SharedFunctionInfo* shared_info, int height) {
TranslatedFrame frame(kConstructStub, shared_info->GetIsolate(), shared_info,
@ -2963,9 +2881,6 @@ int TranslatedFrame::GetValueCount() {
case kJavaScriptBuiltinContinuation:
return 1 + height_;
case kTailCallerFunction:
return 1; // Function.
case kInvalid:
UNREACHABLE();
break;
@ -3020,17 +2935,6 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
return TranslatedFrame::ArgumentsAdaptorFrame(shared_info, height);
}
case Translation::TAIL_CALLER_FRAME: {
SharedFunctionInfo* shared_info =
SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
if (trace_file != nullptr) {
std::unique_ptr<char[]> name = shared_info->DebugName()->ToCString();
PrintF(trace_file, " reading tail caller frame marker %s\n",
name.get());
}
return TranslatedFrame::TailCallerFrame(shared_info);
}
case Translation::CONSTRUCT_STUB_FRAME: {
BailoutId bailout_id = BailoutId(iterator->Next());
SharedFunctionInfo* shared_info =
@ -3235,7 +3139,6 @@ int TranslatedState::CreateNextTranslatedValue(
case Translation::BEGIN:
case Translation::INTERPRETED_FRAME:
case Translation::ARGUMENTS_ADAPTOR_FRAME:
case Translation::TAIL_CALLER_FRAME:
case Translation::CONSTRUCT_STUB_FRAME:
case Translation::GETTER_STUB_FRAME:
case Translation::SETTER_STUB_FRAME:
@ -4159,8 +4062,7 @@ void TranslatedState::StoreMaterializedValuesAndDeopt(JavaScriptFrame* frame) {
if (new_store && value_changed) {
materialized_store->Set(stack_frame_pointer_,
previously_materialized_objects);
CHECK(frames_[0].kind() == TranslatedFrame::kInterpretedFunction ||
frames_[0].kind() == TranslatedFrame::kTailCallerFunction);
CHECK(frames_[0].kind() == TranslatedFrame::kInterpretedFunction);
CHECK_EQ(frame->function(), frames_[0].front().GetRawValue());
Deoptimizer::DeoptimizeFunction(frame->function(), frame->LookupCode());
}

View File

@ -119,7 +119,6 @@ class TranslatedFrame {
kInterpretedFunction,
kGetter,
kSetter,
kTailCallerFunction,
kArgumentsAdaptor,
kConstructStub,
kBuiltinContinuation,
@ -189,7 +188,6 @@ class TranslatedFrame {
SharedFunctionInfo* shared_info);
static TranslatedFrame ArgumentsAdaptorFrame(SharedFunctionInfo* shared_info,
int height);
static TranslatedFrame TailCallerFrame(SharedFunctionInfo* shared_info);
static TranslatedFrame ConstructStubFrame(BailoutId bailout_id,
SharedFunctionInfo* shared_info,
int height);
@ -515,8 +513,6 @@ class Deoptimizer : public Malloced {
int frame_index, bool goto_catch_handler);
void DoComputeArgumentsAdaptorFrame(TranslatedFrame* translated_frame,
int frame_index);
void DoComputeTailCallerFrame(TranslatedFrame* translated_frame,
int frame_index);
void DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
int frame_index);
void DoComputeAccessorStubFrame(TranslatedFrame* translated_frame,
@ -876,7 +872,6 @@ class TranslationIterator BASE_EMBEDDED {
V(GETTER_STUB_FRAME) \
V(SETTER_STUB_FRAME) \
V(ARGUMENTS_ADAPTOR_FRAME) \
V(TAIL_CALLER_FRAME) \
V(DUPLICATED_OBJECT) \
V(ARGUMENTS_ELEMENTS) \
V(ARGUMENTS_LENGTH) \
@ -920,7 +915,6 @@ class Translation BASE_EMBEDDED {
void BeginInterpretedFrame(BailoutId bytecode_offset, int literal_id,
unsigned height);
void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
void BeginTailCallerFrame(int literal_id);
void BeginConstructStubFrame(BailoutId bailout_id, int literal_id,
unsigned height);
void BeginBuiltinContinuationFrame(BailoutId bailout_id, int literal_id,

View File

@ -289,9 +289,6 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) {
"Isolate::stress_deopt_count_address()");
Add(ExternalReference::runtime_function_table_address(isolate).address(),
"Runtime::runtime_function_table_address()");
Add(ExternalReference::is_tail_call_elimination_enabled_address(isolate)
.address(),
"Isolate::is_tail_call_elimination_enabled_address()");
Add(ExternalReference::address_of_float_abs_constant().address(),
"float_absolute_constant");
Add(ExternalReference::address_of_float_neg_constant().address(),

View File

@ -192,7 +192,6 @@ DEFINE_IMPLICATION(es_staging, harmony)
#define HARMONY_INPROGRESS_BASE(V) \
V(harmony_array_prototype_values, "harmony Array.prototype.values") \
V(harmony_function_sent, "harmony function.sent") \
V(harmony_tailcalls, "harmony tail calls") \
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
V(harmony_do_expressions, "harmony do-expressions") \
V(harmony_class_fields, "harmony public fields in class literals") \

View File

@ -1676,18 +1676,8 @@ void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
VisitForStackValue(args->at(i));
}
SetCallPosition(expr, expr->tail_call_mode());
if (expr->tail_call_mode() == TailCallMode::kAllow) {
if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceTailCall);
}
// Update profiling counters before the tail call since we will
// not return to this function.
EmitProfilingCounterHandlingForReturnSequence(true);
}
Handle<Code> code =
CodeFactory::CallICTrampoline(isolate(), mode, expr->tail_call_mode())
.code();
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallICTrampoline(isolate(), mode).code();
__ mov(r3, Operand(IntFromSlot(expr->CallFeedbackICSlot())));
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ mov(r0, Operand(arg_count));

View File

@ -1633,18 +1633,8 @@ void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
VisitForStackValue(args->at(i));
}
SetCallPosition(expr, expr->tail_call_mode());
if (expr->tail_call_mode() == TailCallMode::kAllow) {
if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceTailCall);
}
// Update profiling counters before the tail call since we will
// not return to this function.
EmitProfilingCounterHandlingForReturnSequence(true);
}
Handle<Code> code =
CodeFactory::CallICTrampoline(isolate(), mode, expr->tail_call_mode())
.code();
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallICTrampoline(isolate(), mode).code();
__ Mov(x3, IntFromSlot(expr->CallFeedbackICSlot()));
__ Peek(x1, (arg_count + 1) * kXRegSize);
__ Mov(x0, arg_count);

View File

@ -638,16 +638,12 @@ void FullCodeGenerator::SetExpressionAsStatementPosition(Expression* expr) {
}
}
void FullCodeGenerator::SetCallPosition(Expression* expr,
TailCallMode tail_call_mode) {
void FullCodeGenerator::SetCallPosition(Expression* expr) {
if (expr->position() == kNoSourcePosition) return;
RecordPosition(expr->position());
if (info_->is_debug()) {
RelocInfo::Mode mode = (tail_call_mode == TailCallMode::kAllow)
? RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL
: RelocInfo::DEBUG_BREAK_SLOT_AT_CALL;
// Always emit a debug break slot before a call.
DebugCodegen::GenerateSlot(masm_, mode);
DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_CALL);
}
}
@ -1257,9 +1253,7 @@ void FullCodeGenerator::VisitThrow(Throw* expr) {
void FullCodeGenerator::VisitCall(Call* expr) {
Comment cmnt(masm_, (expr->tail_call_mode() == TailCallMode::kAllow)
? "[ TailCall"
: "[ Call");
Comment cmnt(masm_, "[ Call");
Expression* callee = expr->expression();
Call::CallType call_type = expr->GetCallType();

View File

@ -495,8 +495,7 @@ class FullCodeGenerator final : public AstVisitor<FullCodeGenerator> {
// This is used in loop headers where we want to break for each iteration.
void SetExpressionAsStatementPosition(Expression* expr);
void SetCallPosition(Expression* expr,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
void SetCallPosition(Expression* expr);
void SetConstructCallPosition(Expression* expr) {
// Currently call and construct calls are treated the same wrt debugging.

View File

@ -1569,18 +1569,8 @@ void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
VisitForStackValue(args->at(i));
}
SetCallPosition(expr, expr->tail_call_mode());
if (expr->tail_call_mode() == TailCallMode::kAllow) {
if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceTailCall);
}
// Update profiling counters before the tail call since we will
// not return to this function.
EmitProfilingCounterHandlingForReturnSequence(true);
}
Handle<Code> code =
CodeFactory::CallICTrampoline(isolate(), mode, expr->tail_call_mode())
.code();
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallICTrampoline(isolate(), mode).code();
__ Move(edx, Immediate(IntFromSlot(expr->CallFeedbackICSlot())));
__ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
__ Move(eax, Immediate(arg_count));

View File

@ -1679,18 +1679,8 @@ void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
}
// Record source position of the IC call.
SetCallPosition(expr, expr->tail_call_mode());
if (expr->tail_call_mode() == TailCallMode::kAllow) {
if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceTailCall);
}
// Update profiling counters before the tail call since we will
// not return to this function.
EmitProfilingCounterHandlingForReturnSequence(true);
}
Handle<Code> code =
CodeFactory::CallICTrampoline(isolate(), mode, expr->tail_call_mode())
.code();
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallICTrampoline(isolate(), mode).code();
__ li(a3, Operand(IntFromSlot(expr->CallFeedbackICSlot())));
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ li(a0, Operand(arg_count));

View File

@ -1681,18 +1681,8 @@ void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
}
// Record source position of the IC call.
SetCallPosition(expr, expr->tail_call_mode());
if (expr->tail_call_mode() == TailCallMode::kAllow) {
if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceTailCall);
}
// Update profiling counters before the tail call since we will
// not return to this function.
EmitProfilingCounterHandlingForReturnSequence(true);
}
Handle<Code> code =
CodeFactory::CallICTrampoline(isolate(), mode, expr->tail_call_mode())
.code();
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallICTrampoline(isolate(), mode).code();
__ li(a3, Operand(IntFromSlot(expr->CallFeedbackICSlot())));
__ Ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ li(a0, Operand(arg_count));

View File

@ -1590,18 +1590,8 @@ void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
VisitForStackValue(args->at(i));
}
SetCallPosition(expr, expr->tail_call_mode());
if (expr->tail_call_mode() == TailCallMode::kAllow) {
if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceTailCall);
}
// Update profiling counters before the tail call since we will
// not return to this function.
EmitProfilingCounterHandlingForReturnSequence(true);
}
Handle<Code> code =
CodeFactory::CallICTrampoline(isolate(), mode, expr->tail_call_mode())
.code();
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallICTrampoline(isolate(), mode).code();
__ Set(rdx, IntFromSlot(expr->CallFeedbackICSlot()));
__ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
__ Set(rax, arg_count);

View File

@ -855,21 +855,6 @@ inline std::ostream& operator<<(std::ostream& os, ConvertReceiverMode mode) {
UNREACHABLE();
}
// Defines whether tail call optimization is allowed.
enum class TailCallMode : unsigned { kAllow, kDisallow };
inline size_t hash_value(TailCallMode mode) { return bit_cast<unsigned>(mode); }
inline std::ostream& operator<<(std::ostream& os, TailCallMode mode) {
switch (mode) {
case TailCallMode::kAllow:
return os << "ALLOW_TAIL_CALLS";
case TailCallMode::kDisallow:
return os << "DISALLOW_TAIL_CALLS";
}
UNREACHABLE();
}
// Valid hints for the abstract operation OrdinaryToPrimitive,
// implemented according to ES6, section 7.1.1.
enum class OrdinaryToPrimitiveHint { kNumber, kString };

View File

@ -1339,13 +1339,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallAnyReceiver(Register callable,
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::TailCall(Register callable,
RegisterList args,
int feedback_slot) {
OutputTailCall(callable, args, args.register_count(), feedback_slot);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(Register callable,
RegisterList args) {
OutputCallWithSpread(callable, args, args.register_count());

View File

@ -3066,7 +3066,6 @@ void BytecodeGenerator::VisitCall(Call* expr) {
RegisterList args = register_allocator()->NewGrowableRegisterList();
bool implicit_undefined_receiver = false;
bool is_tail_call = (expr->tail_call_mode() == TailCallMode::kAllow);
// When a call contains a spread, a Call AST node is only created if there is
// exactly one spread, and it is the last argument.
bool is_spread_call = expr->only_last_arg_is_spread();
@ -3087,7 +3086,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
}
case Call::GLOBAL_CALL: {
// Receiver is undefined for global calls.
if (!is_tail_call && !is_spread_call) {
if (!is_spread_call) {
implicit_undefined_receiver = true;
} else {
// TODO(leszeks): There's no special bytecode for tail calls or spread
@ -3125,7 +3124,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
}
case Call::OTHER_CALL: {
// Receiver is undefined for other calls.
if (!is_tail_call && !is_spread_call) {
if (!is_spread_call) {
implicit_undefined_receiver = true;
} else {
// TODO(leszeks): There's no special bytecode for tail calls or spread
@ -3192,12 +3191,8 @@ void BytecodeGenerator::VisitCall(Call* expr) {
int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
if (is_spread_call) {
DCHECK(!is_tail_call);
DCHECK(!implicit_undefined_receiver);
builder()->CallWithSpread(callee, args);
} else if (is_tail_call) {
DCHECK(!implicit_undefined_receiver);
builder()->TailCall(callee, args, feedback_slot_index);
} else if (call_type == Call::NAMED_PROPERTY_CALL ||
call_type == Call::KEYED_PROPERTY_CALL) {
DCHECK(!implicit_undefined_receiver);

View File

@ -179,8 +179,6 @@ namespace interpreter {
OperandType::kReg, OperandType::kReg, OperandType::kIdx) \
V(CallWithSpread, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount) \
V(TailCall, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId, \
OperandType::kRegList, OperandType::kRegCount) \
V(CallRuntimeForPair, AccumulatorUse::kNone, OperandType::kRuntimeId, \
@ -654,7 +652,6 @@ class V8_EXPORT_PRIVATE Bytecodes final {
bytecode == Bytecode::kCallUndefinedReceiver0 ||
bytecode == Bytecode::kCallUndefinedReceiver1 ||
bytecode == Bytecode::kCallUndefinedReceiver2 ||
bytecode == Bytecode::kTailCall ||
bytecode == Bytecode::kConstruct ||
bytecode == Bytecode::kCallWithSpread ||
bytecode == Bytecode::kConstructWithSpread ||
@ -783,7 +780,6 @@ class V8_EXPORT_PRIVATE Bytecodes final {
case Bytecode::kCallUndefinedReceiver2:
return ConvertReceiverMode::kNullOrUndefined;
case Bytecode::kCallAnyReceiver:
case Bytecode::kTailCall:
case Bytecode::kConstruct:
case Bytecode::kCallWithSpread:
case Bytecode::kConstructWithSpread:

View File

@ -563,7 +563,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(
compiler::Node* function, compiler::Node* context,
compiler::Node* first_arg, compiler::Node* arg_count,
compiler::Node* slot_id, compiler::Node* feedback_vector,
ConvertReceiverMode receiver_mode, TailCallMode tail_call_mode) {
ConvertReceiverMode receiver_mode) {
// Static checks to assert it is safe to examine the type feedback element.
// We don't know that we have a weak cell. We might have a private symbol
// or an AllocationSite, but the memory is safe to examine.
@ -605,8 +605,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(
{
// Call using call function builtin.
Callable callable = CodeFactory::InterpreterPushArgsThenCall(
isolate(), receiver_mode, tail_call_mode,
InterpreterPushArgsMode::kJSFunction);
isolate(), receiver_mode, InterpreterPushArgsMode::kJSFunction);
Node* code_target = HeapConstant(callable.code());
Node* ret_value = CallStub(callable.descriptor(), code_target, context,
arg_count, first_arg, function);
@ -723,8 +722,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(
Comment("invoke using Call builtin");
// Call using call builtin.
Callable callable_call = CodeFactory::InterpreterPushArgsThenCall(
isolate(), receiver_mode, tail_call_mode,
InterpreterPushArgsMode::kOther);
isolate(), receiver_mode, InterpreterPushArgsMode::kOther);
Node* code_target_call = HeapConstant(callable_call.code());
Node* ret_value = CallStub(callable_call.descriptor(), code_target_call,
context, arg_count, first_arg, function);
@ -738,15 +736,13 @@ Node* InterpreterAssembler::CallJSWithFeedback(
Node* InterpreterAssembler::CallJS(Node* function, Node* context,
Node* first_arg, Node* arg_count,
ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode) {
ConvertReceiverMode receiver_mode) {
DCHECK(Bytecodes::MakesCallAlongCriticalPath(bytecode_));
DCHECK(Bytecodes::IsCallOrConstruct(bytecode_) ||
bytecode_ == Bytecode::kInvokeIntrinsic);
DCHECK_EQ(Bytecodes::GetReceiverMode(bytecode_), receiver_mode);
Callable callable = CodeFactory::InterpreterPushArgsThenCall(
isolate(), receiver_mode, tail_call_mode,
InterpreterPushArgsMode::kOther);
isolate(), receiver_mode, InterpreterPushArgsMode::kOther);
Node* code_target = HeapConstant(callable.code());
return CallStub(callable.descriptor(), code_target, context, arg_count,
@ -758,7 +754,7 @@ Node* InterpreterAssembler::CallJSWithSpread(Node* function, Node* context,
DCHECK(Bytecodes::MakesCallAlongCriticalPath(bytecode_));
DCHECK_EQ(Bytecodes::GetReceiverMode(bytecode_), ConvertReceiverMode::kAny);
Callable callable = CodeFactory::InterpreterPushArgsThenCall(
isolate(), ConvertReceiverMode::kAny, TailCallMode::kDisallow,
isolate(), ConvertReceiverMode::kAny,
InterpreterPushArgsMode::kWithFinalSpread);
Node* code_target = HeapConstant(callable.code());

View File

@ -124,19 +124,20 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
// If the |receiver_mode| is kNullOrUndefined, then the receiver is implicitly
// undefined and |first_arg| is the first parameter. Otherwise, |first_arg| is
// the receiver and it is converted according to |receiver_mode|.
compiler::Node* CallJSWithFeedback(
compiler::Node* function, compiler::Node* context,
compiler::Node* first_arg, compiler::Node* arg_count,
compiler::Node* slot_id, compiler::Node* feedback_vector,
ConvertReceiverMode receiver_mode, TailCallMode tail_call_mode);
compiler::Node* CallJSWithFeedback(compiler::Node* function,
compiler::Node* context,
compiler::Node* first_arg,
compiler::Node* arg_count,
compiler::Node* slot_id,
compiler::Node* feedback_vector,
ConvertReceiverMode receiver_mode);
// Call JSFunction or Callable |function| with |arg_count| arguments (not
// including receiver) and the first argument located at |first_arg|, possibly
// including the receiver depending on |receiver_mode|.
compiler::Node* CallJS(compiler::Node* function, compiler::Node* context,
compiler::Node* first_arg, compiler::Node* arg_count,
ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode);
ConvertReceiverMode receiver_mode);
// Call JSFunction or Callable |function| with |arg_count|
// arguments (not including receiver) and the first argument

View File

@ -1749,7 +1749,7 @@ class InterpreterJSCallAssembler : public InterpreterAssembler {
: InterpreterAssembler(state, bytecode, operand_scale) {}
// Generates code to perform a JS call that collects type feedback.
void JSCall(ConvertReceiverMode receiver_mode, TailCallMode tail_call_mode) {
void JSCall(ConvertReceiverMode receiver_mode) {
Node* function_reg = BytecodeOperandReg(0);
Node* function = LoadRegister(function_reg);
Node* first_arg_reg = BytecodeOperandReg(1);
@ -1767,9 +1767,8 @@ class InterpreterJSCallAssembler : public InterpreterAssembler {
Node* slot_id = BytecodeOperandIdx(3);
Node* feedback_vector = LoadFeedbackVector();
Node* context = GetContext();
Node* result =
CallJSWithFeedback(function, context, first_arg, args_count, slot_id,
feedback_vector, receiver_mode, tail_call_mode);
Node* result = CallJSWithFeedback(function, context, first_arg, args_count,
slot_id, feedback_vector, receiver_mode);
SetAccumulator(result);
Dispatch();
}
@ -1832,11 +1831,11 @@ class InterpreterJSCallAssembler : public InterpreterAssembler {
// |arg_count| arguments in subsequent registers. Collect type feedback
// into |feedback_slot_id|
IGNITION_HANDLER(CallAnyReceiver, InterpreterJSCallAssembler) {
JSCall(ConvertReceiverMode::kAny, TailCallMode::kDisallow);
JSCall(ConvertReceiverMode::kAny);
}
IGNITION_HANDLER(CallProperty, InterpreterJSCallAssembler) {
JSCall(ConvertReceiverMode::kNotNullOrUndefined, TailCallMode::kDisallow);
JSCall(ConvertReceiverMode::kNotNullOrUndefined);
}
IGNITION_HANDLER(CallProperty0, InterpreterJSCallAssembler) {
@ -1852,7 +1851,7 @@ IGNITION_HANDLER(CallProperty2, InterpreterJSCallAssembler) {
}
IGNITION_HANDLER(CallUndefinedReceiver, InterpreterJSCallAssembler) {
JSCall(ConvertReceiverMode::kNullOrUndefined, TailCallMode::kDisallow);
JSCall(ConvertReceiverMode::kNullOrUndefined);
}
IGNITION_HANDLER(CallUndefinedReceiver0, InterpreterJSCallAssembler) {
@ -1867,15 +1866,6 @@ IGNITION_HANDLER(CallUndefinedReceiver2, InterpreterJSCallAssembler) {
JSCallN(2, ConvertReceiverMode::kNullOrUndefined);
}
// TailCall <callable> <receiver> <arg_count> <feedback_slot_id>
//
// Tail call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers. Collect type feedback
// into |feedback_slot_id|
IGNITION_HANDLER(TailCall, InterpreterJSCallAssembler) {
JSCall(ConvertReceiverMode::kAny, TailCallMode::kAllow);
}
// CallRuntime <function_id> <first_arg> <arg_count>
//
// Call the runtime function |function_id| with the first argument in
@ -1952,7 +1942,7 @@ IGNITION_HANDLER(CallJSRuntime, InterpreterAssembler) {
// Call the function.
Node* result = CallJS(function, context, first_arg, args_count,
ConvertReceiverMode::kAny, TailCallMode::kDisallow);
ConvertReceiverMode::kAny);
SetAccumulator(result);
Dispatch();
}

View File

@ -335,7 +335,7 @@ Node* IntrinsicsGenerator::Call(Node* args_reg, Node* arg_count,
}
Node* result = __ CallJS(function, context, receiver_arg, target_args_count,
ConvertReceiverMode::kAny, TailCallMode::kDisallow);
ConvertReceiverMode::kAny);
return result;
}

View File

@ -3646,15 +3646,6 @@ std::string Isolate::GetTurboCfgFileName() {
}
}
void Isolate::SetTailCallEliminationEnabled(bool enabled) {
if (is_tail_call_elimination_enabled_ == enabled) return;
is_tail_call_elimination_enabled_ = enabled;
// TODO(ishell): Introduce DependencyGroup::kTailCallChangedGroup to
// deoptimize only those functions that are affected by the change of this
// flag.
internal::Deoptimizer::DeoptimizeAll(this);
}
// Heap::detached_contexts tracks detached contexts as pairs
// (number of GC since the context was detached, the context).
void Isolate::AddDetachedContext(Handle<Context> context) {

View File

@ -1174,15 +1174,6 @@ class Isolate {
void RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise,
Handle<Object> parent);
// Support for dynamically disabling tail call elimination.
Address is_tail_call_elimination_enabled_address() {
return reinterpret_cast<Address>(&is_tail_call_elimination_enabled_);
}
bool is_tail_call_elimination_enabled() const {
return is_tail_call_elimination_enabled_;
}
void SetTailCallEliminationEnabled(bool enabled);
void AddDetachedContext(Handle<Context> context);
void CheckDetachedContextsAfterGC();

View File

@ -14582,15 +14582,6 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
break;
}
case Translation::TAIL_CALLER_FRAME: {
int shared_info_id = iterator.Next();
Object* shared_info = LiteralArray()->get(shared_info_id);
os << "{function="
<< Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
<< "}";
break;
}
case Translation::GETTER_STUB_FRAME:
case Translation::SETTER_STUB_FRAME: {
int shared_info_id = iterator.Next();

View File

@ -160,8 +160,6 @@ void ParseInfo::InitFromIsolate(Isolate* isolate) {
set_hash_seed(isolate->heap()->HashSeed());
set_stack_limit(isolate->stack_guard()->real_climit());
set_unicode_cache(isolate->unicode_cache());
set_tail_call_elimination_enabled(
isolate->is_tail_call_elimination_enabled());
set_runtime_call_stats(isolate->counters()->runtime_call_stats());
set_ast_string_constants(isolate->ast_string_constants());
if (FLAG_block_coverage && isolate->is_block_code_coverage()) {

View File

@ -80,8 +80,6 @@ class V8_EXPORT_PRIVATE ParseInfo : public CompileJobFinishCallback {
set_is_named_expression)
FLAG_ACCESSOR(kDebug, is_debug, set_is_debug)
FLAG_ACCESSOR(kSerializing, will_serialize, set_will_serialize)
FLAG_ACCESSOR(kTailCallEliminationEnabled, is_tail_call_elimination_enabled,
set_tail_call_elimination_enabled)
#undef FLAG_ACCESSOR
@ -280,8 +278,7 @@ class V8_EXPORT_PRIVATE ParseInfo : public CompileJobFinishCallback {
kIsNamedExpression = 1 << 8,
kDebug = 1 << 9,
kSerializing = 1 << 10,
kTailCallEliminationEnabled = 1 << 11,
kAstValueFactoryOwned = 1 << 12,
kAstValueFactoryOwned = 1 << 11,
};
//------------- Inputs to parsing and scope analysis -----------------------

View File

@ -270,7 +270,6 @@ class ParserBase {
default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile),
function_literal_id_(0),
allow_natives_(false),
allow_tailcalls_(false),
allow_harmony_do_expressions_(false),
allow_harmony_function_sent_(false),
allow_harmony_restrictive_generators_(false),
@ -285,7 +284,6 @@ class ParserBase {
void set_allow_##name(bool allow) { allow_##name##_ = allow; }
ALLOW_ACCESSORS(natives);
ALLOW_ACCESSORS(tailcalls);
ALLOW_ACCESSORS(harmony_do_expressions);
ALLOW_ACCESSORS(harmony_function_sent);
ALLOW_ACCESSORS(harmony_restrictive_generators);
@ -376,56 +374,6 @@ class ParserBase {
Scope* scope;
};
class TailCallExpressionList {
public:
explicit TailCallExpressionList(Zone* zone)
: zone_(zone), expressions_(0, zone), has_explicit_tail_calls_(false) {}
const ZoneList<ExpressionT>& expressions() const { return expressions_; }
const Scanner::Location& location() const { return loc_; }
bool has_explicit_tail_calls() const { return has_explicit_tail_calls_; }
void Swap(TailCallExpressionList& other) {
expressions_.Swap(&other.expressions_);
std::swap(loc_, other.loc_);
std::swap(has_explicit_tail_calls_, other.has_explicit_tail_calls_);
}
void AddImplicitTailCall(ExpressionT expr) {
expressions_.Add(expr, zone_);
}
void Append(const TailCallExpressionList& other) {
if (!has_explicit_tail_calls()) {
loc_ = other.loc_;
has_explicit_tail_calls_ = other.has_explicit_tail_calls_;
}
expressions_.AddAll(other.expressions_, zone_);
}
private:
Zone* zone_;
ZoneList<ExpressionT> expressions_;
Scanner::Location loc_;
bool has_explicit_tail_calls_;
};
// Defines whether tail call expressions are allowed or not.
enum class ReturnExprContext {
// We are inside return statement which is allowed to contain tail call
// expressions. Tail call expressions are allowed.
kInsideValidReturnStatement,
// We are inside a block in which tail call expressions are allowed but
// not yet inside a return statement.
kInsideValidBlock,
// Tail call expressions are not allowed in the following blocks.
kInsideTryBlock,
kInsideForInOfBody,
};
class FunctionState final : public BlockState {
public:
FunctionState(FunctionState** function_state_stack, Scope** scope_stack,
@ -456,27 +404,10 @@ class ParserBase {
return destructuring_assignments_to_rewrite_;
}
TailCallExpressionList& tail_call_expressions() {
return tail_call_expressions_;
}
void AddImplicitTailCallExpression(ExpressionT expression) {
if (return_expr_context() ==
ReturnExprContext::kInsideValidReturnStatement) {
tail_call_expressions_.AddImplicitTailCall(expression);
}
}
ZoneList<typename ExpressionClassifier::Error>* GetReportedErrorList() {
return &reported_errors_;
}
ReturnExprContext return_expr_context() const {
return return_expr_context_;
}
void set_return_expr_context(ReturnExprContext context) {
return_expr_context_ = context;
}
ZoneList<ExpressionT>* non_patterns_to_rewrite() {
return &non_patterns_to_rewrite_;
}
@ -537,8 +468,6 @@ class ParserBase {
DeclarationScope* scope_;
ZoneList<DestructuringAssignment> destructuring_assignments_to_rewrite_;
TailCallExpressionList tail_call_expressions_;
ReturnExprContext return_expr_context_;
ZoneList<ExpressionT> non_patterns_to_rewrite_;
ZoneList<typename ExpressionClassifier::Error> reported_errors_;
@ -557,48 +486,6 @@ class ParserBase {
friend Impl;
};
// This scope sets current ReturnExprContext to given value.
class ReturnExprScope {
public:
explicit ReturnExprScope(FunctionState* function_state,
ReturnExprContext return_expr_context)
: function_state_(function_state),
sav_return_expr_context_(function_state->return_expr_context()) {
// Don't update context if we are requested to enable tail call
// expressions but current block does not allow them.
if (return_expr_context !=
ReturnExprContext::kInsideValidReturnStatement ||
sav_return_expr_context_ == ReturnExprContext::kInsideValidBlock) {
function_state->set_return_expr_context(return_expr_context);
}
}
~ReturnExprScope() {
function_state_->set_return_expr_context(sav_return_expr_context_);
}
private:
FunctionState* function_state_;
ReturnExprContext sav_return_expr_context_;
};
// Collects all return expressions at tail call position in this scope
// to a separate list.
class CollectExpressionsInTailPositionToListScope {
public:
CollectExpressionsInTailPositionToListScope(FunctionState* function_state,
TailCallExpressionList* list)
: function_state_(function_state), list_(list) {
function_state->tail_call_expressions().Swap(*list_);
}
~CollectExpressionsInTailPositionToListScope() {
function_state_->tail_call_expressions().Swap(*list_);
}
private:
FunctionState* function_state_;
TailCallExpressionList* list_;
};
struct DeclarationDescriptor {
enum Kind { NORMAL, PARAMETER };
Scope* scope;
@ -641,15 +528,13 @@ class ParserBase {
scope(nullptr),
init_block(parser->impl()->NullBlock()),
inner_block(parser->impl()->NullBlock()),
bound_names(1, parser->zone()),
tail_call_expressions(parser->zone()) {}
bound_names(1, parser->zone()) {}
IdentifierT name;
ExpressionT pattern;
Scope* scope;
BlockT init_block;
BlockT inner_block;
ZoneList<const AstRawString*> bound_names;
TailCallExpressionList tail_call_expressions;
};
struct ForInfo {
@ -1574,7 +1459,6 @@ class ParserBase {
int function_literal_id_;
bool allow_natives_;
bool allow_tailcalls_;
bool allow_harmony_do_expressions_;
bool allow_harmony_function_sent_;
bool allow_harmony_restrictive_generators_;
@ -1597,8 +1481,6 @@ ParserBase<Impl>::FunctionState::FunctionState(
outer_function_state_(*function_state_stack),
scope_(scope),
destructuring_assignments_to_rewrite_(16, scope->zone()),
tail_call_expressions_(scope->zone()),
return_expr_context_(ReturnExprContext::kInsideValidBlock),
non_patterns_to_rewrite_(0, scope->zone()),
reported_errors_(16, scope->zone()),
next_function_is_likely_called_(false),
@ -4198,7 +4080,6 @@ void ParserBase<Impl>::ParseFunctionBody(
impl()->CreateFunctionNameAssignment(function_name, pos, function_type,
function_scope, result,
kFunctionNameAssignmentIndex);
impl()->MarkCollectedTailCallExpressions();
}
template <typename Impl>
@ -4353,10 +4234,6 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
// Single-expression body
has_braces = false;
int pos = position();
DCHECK(ReturnExprContext::kInsideValidBlock ==
function_state_->return_expr_context());
ReturnExprScope allow_tail_calls(
function_state_, ReturnExprContext::kInsideValidReturnStatement);
body = impl()->NewStatementList(1);
impl()->AddParameterInitializationBlock(
formal_parameters, body, kind == kAsyncArrowFunction, CHECK_OK);
@ -4371,13 +4248,8 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
impl()->RewriteNonPattern(CHECK_OK);
body->Add(BuildReturnStatement(expression, expression->position()),
zone());
if (allow_tailcalls() && !is_sloppy(language_mode())) {
// ES6 14.6.1 Static Semantics: IsInTailPosition
impl()->MarkTailPosition(expression);
}
}
expected_property_count = function_state.expected_property_count();
impl()->MarkCollectedTailCallExpressions();
}
formal_parameters.scope->set_end_position(scanner()->location().end_pos);
@ -5317,21 +5189,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
return_value = impl()->GetLiteralUndefined(position());
}
} else {
if (IsDerivedConstructor(function_state_->kind())) {
// Because of the return code rewriting that happens in case of a subclass
// constructor we don't want to accept tail calls, therefore we don't set
// ReturnExprScope to kInsideValidReturnStatement here.
return_value = ParseExpression(true, CHECK_OK);
} else {
ReturnExprScope maybe_allow_tail_calls(
function_state_, ReturnExprContext::kInsideValidReturnStatement);
return_value = ParseExpression(true, CHECK_OK);
if (allow_tailcalls() && !is_sloppy(language_mode()) && !is_resumable()) {
// ES6 14.6.1 Static Semantics: IsInTailPosition
function_state_->AddImplicitTailCallExpression(return_value);
}
}
return_value = ParseExpression(true, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
return_value = impl()->RewriteReturn(return_value, loc.beg_pos);
@ -5536,12 +5394,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
Expect(Token::TRY, CHECK_OK);
int pos = position();
BlockT try_block = impl()->NullBlock();
{
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideTryBlock);
try_block = ParseBlock(nullptr, CHECK_OK);
}
BlockT try_block = ParseBlock(nullptr, CHECK_OK);
CatchInfo catch_info(this);
@ -5560,9 +5413,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
catch_info.scope->set_start_position(scanner()->location().beg_pos);
{
CollectExpressionsInTailPositionToListScope
collect_tail_call_expressions_scope(
function_state_, &catch_info.tail_call_expressions);
BlockState catch_block_state(&scope_, catch_info.scope);
catch_block = factory()->NewBlock(nullptr, 16, false, kNoSourcePosition);
@ -5728,8 +5578,6 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
StatementT final_loop = impl()->NullStatement();
{
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideForInOfBody);
BlockState block_state(zone(), &scope_);
scope()->set_start_position(scanner()->location().beg_pos);
@ -5791,8 +5639,6 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
Scope* for_scope = scope();
{
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideForInOfBody);
BlockState block_state(zone(), &scope_);
scope()->set_start_position(scanner()->location().beg_pos);
@ -5998,8 +5844,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
StatementT final_loop = impl()->NullStatement();
Scope* for_scope = scope();
{
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideForInOfBody);
BlockState block_state(zone(), &scope_);
scope()->set_start_position(scanner()->location().beg_pos);

View File

@ -421,10 +421,6 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) {
return NULL;
}
void Parser::MarkTailPosition(Expression* expression) {
expression->MarkTail();
}
Expression* Parser::NewV8Intrinsic(const AstRawString* name,
ZoneList<Expression*>* args, int pos,
bool* ok) {
@ -521,8 +517,6 @@ Parser::Parser(ParseInfo* info)
allow_lazy_ = FLAG_lazy && info->allow_lazy_parsing() && !info->is_native() &&
info->extension() == nullptr && can_compile_lazily;
set_allow_natives(FLAG_allow_natives_syntax || info->is_native());
set_allow_tailcalls(FLAG_harmony_tailcalls && !info->is_native() &&
info->is_tail_call_elimination_enabled());
set_allow_harmony_do_expressions(FLAG_harmony_do_expressions);
set_allow_harmony_function_sent(FLAG_harmony_function_sent);
set_allow_harmony_restrictive_generators(FLAG_harmony_restrictive_generators);
@ -1760,11 +1754,6 @@ Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
}
if (catch_block != nullptr) {
// For a try-catch construct append return expressions from the catch block
// to the list of return expressions.
function_state_->tail_call_expressions().Append(
catch_info.tail_call_expressions);
DCHECK_NULL(finally_block);
DCHECK_NOT_NULL(catch_info.scope);
TryCatchStatement* stmt = factory()->NewTryCatchStatement(
@ -3757,10 +3746,8 @@ ZoneList<Expression*>* Parser::PrepareSpreadArguments(
Expression* Parser::SpreadCall(Expression* function,
ZoneList<Expression*>* args, int pos,
Call::PossiblyEval is_possibly_eval) {
// Handle these cases in BytecodeGenerator.
// [Call,New]WithSpread bytecodes aren't used with tailcalls - see
// https://crbug.com/v8/5867
if (!allow_tailcalls() && OnlyLastArgIsSpread(args)) {
// Handle this case in BytecodeGenerator.
if (OnlyLastArgIsSpread(args)) {
return factory()->NewCall(function, args, pos);
}
@ -3841,14 +3828,6 @@ void Parser::SetAsmModule() {
scope()->AsDeclarationScope()->set_asm_module();
}
void Parser::MarkCollectedTailCallExpressions() {
const ZoneList<Expression*>& tail_call_expressions =
function_state_->tail_call_expressions().expressions();
for (int i = 0; i < tail_call_expressions.length(); ++i) {
MarkTailPosition(tail_call_expressions[i]);
}
}
Expression* Parser::ExpressionListToExpression(ZoneList<Expression*>* args) {
Expression* expr = args->at(0);
for (int i = 1; i < args->length(); ++i) {

View File

@ -293,7 +293,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
parsing_on_main_thread_);
#define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name());
SET_ALLOW(natives);
SET_ALLOW(tailcalls);
SET_ALLOW(harmony_do_expressions);
SET_ALLOW(harmony_function_sent);
SET_ALLOW(harmony_class_fields);
@ -635,9 +634,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
void SetLanguageMode(Scope* scope, LanguageMode mode);
void SetAsmModule();
V8_INLINE void MarkCollectedTailCallExpressions();
V8_INLINE void MarkTailPosition(Expression* expression);
// Rewrite all DestructuringAssignments in the current FunctionState.
V8_INLINE void RewriteDestructuringAssignments();

View File

@ -738,14 +738,6 @@ RUNTIME_FUNCTION(Runtime_TraceExit) {
return obj; // return TOS
}
RUNTIME_FUNCTION(Runtime_TraceTailCall) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
PrintIndentation(isolate);
PrintF("} -> tail call ->\n");
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetExceptionDetails) {
HandleScope shs(isolate);
DCHECK_EQ(1, args.length());

View File

@ -584,7 +584,6 @@ namespace internal {
F(DisassembleFunction, 1, 1) \
F(TraceEnter, 0, 1) \
F(TraceExit, 1, 1) \
F(TraceTailCall, 0, 1) \
F(HaveSameMap, 2, 1) \
F(InNewSpace, 1, 1) \
F(HasSmiElements, 1, 1) \

View File

@ -1246,7 +1246,7 @@ TEST(InterpreterStoreKeyedProperty) {
CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
}
static void TestInterpreterCall(TailCallMode tail_call_mode) {
TEST(InterpreterCall) {
HandleAndZoneScope handles;
Isolate* isolate = handles.main_isolate();
Zone* zone = handles.main_zone();
@ -1275,11 +1275,7 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.StoreAccumulatorInRegister(reg)
.MoveRegister(builder.Receiver(), args[0]);
if (tail_call_mode == TailCallMode::kAllow) {
builder.TailCall(reg, args, call_slot_index);
} else {
builder.CallProperty(reg, args, call_slot_index);
}
builder.CallProperty(reg, args, call_slot_index);
builder.Return();
ast_factory.Internalize(isolate);
@ -1302,11 +1298,7 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
builder.LoadNamedProperty(builder.Receiver(), name, slot_index)
.StoreAccumulatorInRegister(reg)
.MoveRegister(builder.Receiver(), args[0]);
if (tail_call_mode == TailCallMode::kAllow) {
builder.TailCall(reg, args, call_slot_index);
} else {
builder.CallProperty(reg, args, call_slot_index);
}
builder.CallProperty(reg, args, call_slot_index);
builder.Return();
ast_factory.Internalize(isolate);
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
@ -1338,11 +1330,7 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.LoadLiteral(Smi::FromInt(11))
.StoreAccumulatorInRegister(args[2]);
if (tail_call_mode == TailCallMode::kAllow) {
builder.TailCall(reg, args, call_slot_index);
} else {
builder.CallProperty(reg, args, call_slot_index);
}
builder.CallProperty(reg, args, call_slot_index);
builder.Return();
@ -1391,11 +1379,7 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.LoadLiteral(ast_factory.NewString(ast_factory.GetOneByteString("j")))
.StoreAccumulatorInRegister(args[10]);
if (tail_call_mode == TailCallMode::kAllow) {
builder.TailCall(reg, args, call_slot_index);
} else {
builder.CallProperty(reg, args, call_slot_index);
}
builder.CallProperty(reg, args, call_slot_index);
builder.Return();
@ -1419,10 +1403,6 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
}
}
TEST(InterpreterCall) { TestInterpreterCall(TailCallMode::kDisallow); }
TEST(InterpreterTailCall) { TestInterpreterCall(TailCallMode::kAllow); }
static BytecodeArrayBuilder& SetRegister(BytecodeArrayBuilder& builder,
Register reg, int value,
Register scratch) {

View File

@ -6431,123 +6431,6 @@ TEST(BreakLocationIterator) {
DisableDebugger(isolate);
}
TEST(DisableTailCallElimination) {
i::FLAG_allow_natives_syntax = true;
i::FLAG_harmony_tailcalls = true;
// TODO(ishell, 4698): Investigate why TurboFan in --always-opt mode makes
// stack[2].getFunctionName() return null.
i::FLAG_turbo_inlining = false;
DebugLocalContext env;
v8::Isolate* isolate = env->GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
v8::HandleScope scope(isolate);
CHECK(i_isolate->is_tail_call_elimination_enabled());
CompileRun(
"'use strict'; \n"
"Error.prepareStackTrace = (error,stack) => { \n"
" error.strace = stack; \n"
" return error.message + \"\\n at \" + stack.join(\"\\n at \"); \n"
"} \n"
" \n"
"function getCaller() { \n"
" var e = new Error(); \n"
" e.stack; // prepare stack trace \n"
" var stack = e.strace; \n"
" %GlobalPrint('caller: '); \n"
" %GlobalPrint(stack[2].getFunctionName()); \n"
" %GlobalPrint('\\n'); \n"
" return stack[2].getFunctionName(); \n"
"} \n"
"function f() { \n"
" var caller = getCaller(); \n"
" if (caller === 'g') return 1; \n"
" if (caller === 'h') return 2; \n"
" return 0; \n"
"} \n"
"function g() { \n"
" return f(); \n"
"} \n"
"function h() { \n"
" var result = g(); \n"
" return result; \n"
"} \n"
"%NeverOptimizeFunction(getCaller); \n"
"%NeverOptimizeFunction(f); \n"
"%NeverOptimizeFunction(h); \n"
"");
ExpectInt32("h();", 2);
ExpectInt32("h(); %OptimizeFunctionOnNextCall(g); h();", 2);
i_isolate->SetTailCallEliminationEnabled(false);
CHECK(!i_isolate->is_tail_call_elimination_enabled());
ExpectInt32("h();", 1);
ExpectInt32("h(); %OptimizeFunctionOnNextCall(g); h();", 1);
i_isolate->SetTailCallEliminationEnabled(true);
CHECK(i_isolate->is_tail_call_elimination_enabled());
ExpectInt32("h();", 2);
ExpectInt32("h(); %OptimizeFunctionOnNextCall(g); h();", 2);
}
TEST(DebugStepNextTailCallEliminiation) {
i::FLAG_allow_natives_syntax = true;
i::FLAG_harmony_tailcalls = true;
// TODO(ishell, 4698): Investigate why TurboFan in --always-opt mode makes
// stack[2].getFunctionName() return null.
i::FLAG_turbo_inlining = false;
DebugLocalContext env;
env.ExposeDebug();
v8::Isolate* isolate = env->GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
v8::HandleScope scope(isolate);
CHECK(i_isolate->is_tail_call_elimination_enabled());
const char* source =
"'use strict'; \n"
"var Debug = debug.Debug; \n"
"var exception = null; \n"
"var breaks = 0; \n"
"var log = []; \n"
"function f(x) { \n"
" if (x == 2) { \n"
" debugger; // Break a \n"
" } \n"
" if (x-- > 0) { // Break b \n"
" return f(x); // Break c \n"
" } \n"
"} // Break e \n"
"function listener(event, exec_state, event_data, data) {\n"
" if (event != Debug.DebugEvent.Break) return; \n"
" try { \n"
" var line = exec_state.frame(0).sourceLineText(); \n"
" var col = exec_state.frame(0).sourceColumn(); \n"
" var match = line.match(/\\/\\/ Break (\\w)/); \n"
" log.push(match[1] + col); \n"
" exec_state.prepareStep(Debug.StepAction.StepNext); \n"
" } catch (e) { \n"
" exception = e; \n"
" }; \n"
"}; \n"
"Debug.setListener(listener); \n"
"f(4); \n"
"Debug.setListener(null); // Break d \n";
CompileRun(source);
ExpectNull("exception");
ExpectString("JSON.stringify(log)", "[\"a4\",\"b2\",\"c4\",\"c11\",\"d0\"]");
i_isolate->SetTailCallEliminationEnabled(false);
CompileRun(
"log = []; \n"
"Debug.setListener(listener); \n"
"f(5); \n"
"Debug.setListener(null); // Break f \n");
ExpectNull("exception");
ExpectString("JSON.stringify(log)",
"[\"a4\",\"b2\",\"c4\",\"e0\",\"e0\",\"e0\",\"e0\",\"f0\"]");
}
size_t current_action = 0;
StepAction actions[] = {StepNext, StepNext};
static void DebugStepOverFunctionWithCaughtExceptionListener(

View File

@ -1,46 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-tailcalls
"use strict";
var Debug = debug.Debug
var exception = null;
var breaks = 0;
function f(x) {
if (x > 0) { // B3 B5 B7 B9
return f(x - 1); // B4 B6 B8
}
} // B10
function g(x) {
return f(x); // B2
}
function h(x) {
debugger; // B0
g(x); // B1
} // B11
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
print(event_data.sourceLineText());
assertTrue(event_data.sourceLineText().indexOf(`B${breaks++}`) > 0);
exec_state.prepareStep(Debug.StepAction.StepIn);
} catch (e) {
exception = e;
};
};
Debug.setListener(listener);
h(3);
Debug.setListener(null); // B12
assertNull(exception);
assertEquals(13, breaks);

View File

@ -1,45 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-tailcalls
"use strict";
var Debug = debug.Debug
var exception = null;
var breaks = 0;
function f(x) {
if (x > 0) {
return f(x - 1); // Tail call
}
debugger; // Break 0
}
function g(x) {
return f(x); // Tail call
}
function h(x) {
g(x); // Not tail call
} // Break 1
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
assertTrue(event_data.sourceLineText().indexOf(`Break ${breaks++}`) > 0);
exec_state.prepareStep(Debug.StepAction.StepOut);
} catch (e) {
exception = e;
};
};
Debug.setListener(listener);
h(3);
Debug.setListener(null); // Break 2
assertNull(exception);
assertEquals(3, breaks);

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// Flags: --allow-natives-syntax
"use strict";

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// Flags: --allow-natives-syntax
"use strict";

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-tailcalls
"use strict";
function foo() {

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
try {
load("mjsunit/es6/tail-call-megatest.js");
} catch(e) {
load("test/mjsunit/es6/tail-call-megatest.js");
}
run_tests(0);

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
try {
load("mjsunit/es6/tail-call-megatest.js");
} catch(e) {
load("test/mjsunit/es6/tail-call-megatest.js");
}
run_tests(1);

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
try {
load("mjsunit/es6/tail-call-megatest.js");
} catch(e) {
load("test/mjsunit/es6/tail-call-megatest.js");
}
run_tests(2);

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
try {
load("mjsunit/es6/tail-call-megatest.js");
} catch(e) {
load("test/mjsunit/es6/tail-call-megatest.js");
}
run_tests(3);

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
try {
load("mjsunit/es6/tail-call-megatest.js");
} catch(e) {
load("test/mjsunit/es6/tail-call-megatest.js");
}
run_tests(4);

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
try {
load("mjsunit/es6/tail-call-megatest.js");
} catch(e) {
load("test/mjsunit/es6/tail-call-megatest.js");
}
run_tests(5);

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
try {
load("mjsunit/es6/tail-call-megatest.js");
} catch(e) {
load("test/mjsunit/es6/tail-call-megatest.js");
}
run_tests(6);

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
try {
load("mjsunit/es6/tail-call-megatest.js");
} catch(e) {
load("test/mjsunit/es6/tail-call-megatest.js");
}
run_tests(7);

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
try {
load("mjsunit/es6/tail-call-megatest.js");
} catch(e) {
load("test/mjsunit/es6/tail-call-megatest.js");
}
run_tests(8);

View File

@ -1,13 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
try {
load("mjsunit/es6/tail-call-megatest.js");
} catch(e) {
load("test/mjsunit/es6/tail-call-megatest.js");
}
run_tests(9);

View File

@ -1,423 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
Error.prepareStackTrace = (error,stack) => {
error.strace = stack;
return error.message + "\n at " + stack.join("\n at ");
}
var verbose = typeof(arguments) !== "undefined" && arguments.indexOf("-v") >= 0;
function checkStackTrace(expected) {
var e = new Error();
e.stack; // prepare stack trace
var stack = e.strace;
assertEquals("checkStackTrace", stack[0].getFunctionName());
for (var i = 0; i < expected.length; i++) {
assertEquals(expected[i].name, stack[i + 1].getFunctionName());
}
}
var CAN_INLINE_COMMENT = "// Let it be inlined.";
var DONT_INLINE_COMMENT = (function() {
var line = "1";
for (var i = 0; i < 200; ++i) {
line += "," + i;
}
line += ";\n";
return line;
})();
function ident_source(source, ident) {
ident = " ".repeat(ident);
return ident + source.replace(/\n/gi, "\n" + ident);
}
var SHARDS_COUNT = 10;
function run_tests(shard) {
function inlinable_comment(inlinable) {
return inlinable ? CAN_INLINE_COMMENT : DONT_INLINE_COMMENT;
}
// Check arguments manually to avoid bailing out with reason "bad value
// context for arguments value".
function check_arguments_template(expected_name) {
var lines = [
` assertEquals_(${expected_name}.length, arguments.length);`,
` for (var i = 0; i < ${expected_name}.length; i++) {`,
` assertEquals_(${expected_name}[i], arguments[i]);`,
` }`,
];
return lines.join("\n");
}
var check_arguments = check_arguments_template("expected_args");
function deopt_template(deopt_mode) {
switch(deopt_mode) {
case "none":
return " // Don't deoptimize";
case "f":
case "g":
case "test":
return ` %DeoptimizeFunction(${deopt_mode});`;
default:
assertUnreachable();
}
}
var f_cfg_sloppy = {
func_name: 'f',
source_template: function(cfg) {
var receiver = cfg.f_receiver != undefined ? cfg.f_receiver
: "global";
var do_checks = [
` assertEquals_(${receiver}, this);`,
` ${!cfg.check_new_target ? "// " : ""}assertEquals_(undefined, new.target);`,
check_arguments,
` checkStackTrace_([f, test]);`,
].join("\n");
var lines = [
`function f(a) {`,
` ${inlinable_comment(cfg.f_inlinable)}`,
` counter++;`,
` var expected_args = [${cfg.f_args}];`,
do_checks,
deopt_template(cfg.deopt_mode),
do_checks,
` return 42;`,
`}`,
];
return lines.join("\n");
},
};
var f_cfg_strict = {
func_name: 'f',
source_template: function(cfg) {
var receiver = cfg.f_receiver != undefined ? cfg.f_receiver
: "undefined";
var do_checks = [
` assertEquals_(${receiver}, this);`,
` ${!cfg.check_new_target ? "// " : ""}assertEquals_(undefined, new.target);`,
check_arguments,
` checkStackTrace_([f, test]);`,
].join("\n");
var lines = [
`function f(a) {`,
` "use strict";`,
` ${inlinable_comment(cfg.f_inlinable)}`,
` counter++;`,
` var expected_args = [${cfg.f_args}];`,
do_checks,
deopt_template(cfg.deopt_mode),
do_checks,
` return 42;`,
`}`,
];
return lines.join("\n");
},
};
var f_cfg_possibly_eval = {
func_name: 'eval',
source_template: function(cfg) {
var receiver = cfg.f_receiver != undefined ? cfg.f_receiver
: "global";
var do_checks = [
` assertEquals_(${receiver}, this);`,
` ${!cfg.check_new_target ? "// " : ""}assertEquals_(undefined, new.target);`,
check_arguments,
` checkStackTrace_([f, test]);`,
].join("\n");
var lines = [
`function f(a) {`,
` ${inlinable_comment(cfg.f_inlinable)}`,
` counter++;`,
` var expected_args = [${cfg.f_args}];`,
do_checks,
deopt_template(cfg.deopt_mode),
do_checks,
` return 42;`,
`}`,
`var eval = f;`,
];
return lines.join("\n");
},
};
var f_cfg_bound = {
func_name: 'bound',
source_template: function(cfg) {
var do_checks = [
` assertEquals_(receiver, this);`,
` ${!cfg.check_new_target ? "// " : ""}assertEquals_(undefined, new.target);`,
check_arguments,
` checkStackTrace_([f, test]);`,
].join("\n");
var lines = [
`function f(a) {`,
` "use strict";`,
` ${inlinable_comment(cfg.f_inlinable)}`,
` counter++;`,
` var expected_args = [${cfg.f_args}];`,
do_checks,
deopt_template(cfg.deopt_mode),
do_checks,
` return 42;`,
`}`,
`var receiver = {a: 153};`,
`var bound = f.bind(receiver);`,
];
return lines.join("\n");
},
};
var f_cfg_proxy = {
func_name: 'p',
source_template: function(cfg) {
var receiver = cfg.f_receiver != undefined ? cfg.f_receiver
: "global";
var do_checks = [
` assertEquals_(${receiver}, this);`,
` ${!cfg.check_new_target ? "// " : ""}assertEquals_(undefined, new.target);`,
check_arguments,
` checkStackTrace_([f, test]);`,
].join("\n");
var lines = [
`function f(a) {`,
` ${inlinable_comment(cfg.f_inlinable)}`,
` counter++;`,
` var expected_args = [${cfg.f_args}];`,
do_checks,
deopt_template(cfg.deopt_mode),
do_checks,
` return 42;`,
`}`,
`var p = new Proxy(f, {});`,
];
return lines.join("\n");
},
};
var g_cfg_normal = {
receiver: undefined,
source_template: function(cfg) {
var lines = [
`function g(a) {`,
` "use strict";`,
` ${inlinable_comment(cfg.g_inlinable)}`,
` var expected_args = [${cfg.g_args}];`,
check_arguments,
` return ${cfg.f_name}(${cfg.f_args});`,
`}`,
];
return lines.join("\n");
},
};
var g_cfg_reflect_apply = {
receiver: "the_receiver",
source_template: function(cfg) {
var lines = [
`function g(a) {`,
` "use strict";`,
` ${inlinable_comment(cfg.g_inlinable)}`,
` var expected_args = [${cfg.g_args}];`,
check_arguments,
` return Reflect.apply(${cfg.f_name}, the_receiver, [${cfg.f_args}]);`,
`}`,
];
return lines.join("\n");
},
};
var g_cfg_function_apply = {
receiver: "the_receiver",
source_template: function(cfg) {
var lines = [
`function g(a) {`,
` "use strict";`,
` ${inlinable_comment(cfg.g_inlinable)}`,
` var expected_args = [${cfg.g_args}];`,
check_arguments,
` return ${cfg.f_name}.apply(the_receiver, [${cfg.f_args}]);`,
`}`,
];
return lines.join("\n");
},
};
var g_cfg_function_apply_arguments_object = {
receiver: "the_receiver",
source_template: function(cfg) {
cfg.f_args = cfg.g_args;
var lines = [
`function g(a) {`,
` "use strict";`,
` ${inlinable_comment(cfg.g_inlinable)}`,
` var expected_args = [${cfg.g_args}];`,
check_arguments,
` return ${cfg.f_name}.apply(the_receiver, arguments);`,
`}`,
];
return lines.join("\n");
},
};
var g_cfg_function_call = {
receiver: "the_receiver",
source_template: function(cfg) {
var f_args = "the_receiver";
if (cfg.f_args !== "") f_args += ", ";
f_args += cfg.f_args;
var lines = [
`function g(a) {`,
` "use strict";`,
` ${inlinable_comment(cfg.g_inlinable)}`,
` var expected_args = [${cfg.g_args}];`,
check_arguments,
` return ${cfg.f_name}.call(${f_args});`,
`}`,
];
return lines.join("\n");
},
};
function test_template(cfg) {
// Note: g_source_template modifies cfg.f_args in some cases.
var g_source = cfg.g_source_template(cfg);
g_source = ident_source(g_source, 2);
var f_source = cfg.f_source_template(cfg);
f_source = ident_source(f_source, 2);
var lines = [
`(function() {`,
` // Avoid bailing out because of "Reference to a variable which requires dynamic lookup".`,
` var assertEquals_ = assertEquals;`,
` var checkStackTrace_ = checkStackTrace;`,
` var undefined = void 0;`,
` var global = Function('return this')();`,
` var the_receiver = {receiver: 1};`,
` var counter = 0;`,
``,
` // Don't inline helper functions`,
` %NeverOptimizeFunction(assertEquals);`,
` %NeverOptimizeFunction(checkStackTrace);`,
``,
f_source,
g_source,
` function test() {`,
` "use strict";`,
` assertEquals_(42, g(${cfg.g_args}));`,
` }`,
` ${"test();".repeat(cfg.test_warmup_count)}`,
` ${cfg.f_inlinable ? "%SetForceInlineFlag(f)" : "%OptimizeFunctionOnNextCall(f)"};`,
` ${cfg.g_inlinable ? "%SetForceInlineFlag(g)" : "%OptimizeFunctionOnNextCall(g)"};`,
` %OptimizeFunctionOnNextCall(test);`,
` test();`,
` assertEquals(${1 + cfg.test_warmup_count}, counter);`,
`})();`,
``,
];
var source = lines.join("\n");
return source;
}
var f_args_variants = [/*"", "1",*/ "1, 2"];
var g_args_variants = [/*"", "10",*/ "10, 20"];
var f_inlinable_variants = [true, false];
var g_inlinable_variants = [true, false];
// This is to avoid bailing out because of referencing new.target.
var check_new_target_variants = [/*true,*/ false];
var deopt_mode_variants = ["none", "f", "g", "test"];
var f_variants = [
f_cfg_sloppy,
f_cfg_strict,
f_cfg_bound,
f_cfg_proxy,
// f_cfg_possibly_eval,
];
var g_variants = [
g_cfg_normal,
// g_cfg_reflect_apply,
g_cfg_function_apply,
// g_cfg_function_apply_arguments_object,
g_cfg_function_call,
];
var test_warmup_counts = [0, 1, 2];
var iter = 0;
var tests_executed = 0;
if (verbose && shard !== undefined) {
print("Running shard #" + shard);
}
f_variants.forEach((f_cfg) => {
check_new_target_variants.forEach((check_new_target) => {
deopt_mode_variants.forEach((deopt_mode) => {
g_variants.forEach((g_cfg) => {
f_args_variants.forEach((f_args) => {
g_args_variants.forEach((g_args) => {
f_inlinable_variants.forEach((f_inlinable) => {
g_inlinable_variants.forEach((g_inlinable) => {
test_warmup_counts.forEach((test_warmup_count) => {
if (shard !== undefined && (iter++) % SHARDS_COUNT != shard) {
if (verbose) {
print("skipping...");
}
return;
}
tests_executed++;
var cfg = {
f_source_template: f_cfg.source_template,
f_inlinable,
f_args,
f_name: f_cfg.func_name,
f_receiver: g_cfg.receiver,
g_source_template: g_cfg.source_template,
g_inlinable,
g_args,
test_warmup_count,
check_new_target,
deopt_mode,
};
var source = test_template(cfg);
if (verbose) {
// print("====================");
// print(source);
}
eval(source);
});
});
});
});
});
});
});
});
});
if (verbose) {
print("Number of tests executed: " + tests_executed);
}
}
// Uncomment to run all the tests at once or use shard runners.
//run_tests();

View File

@ -1,97 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
"use strict";
Error.prepareStackTrace = (e,s) => s;
function CheckStackTrace(expected) {
var stack = (new Error()).stack;
assertEquals("CheckStackTrace", stack[0].getFunctionName());
for (var i = 0; i < expected.length; i++) {
assertEquals(expected[i].name, stack[i + 1].getFunctionName());
}
}
// Tail call proxy function when caller does not have an arguments
// adaptor frame.
(function test() {
// Caller and callee have same number of arguments.
function f1(a) {
CheckStackTrace([f1, test]);
return 10 + a;
}
var p1 = new Proxy(f1, {});
function g1(a) { return p1(2); }
assertEquals(12, g1(1));
// Caller has more arguments than callee.
function f2(a) {
CheckStackTrace([f2, test]);
return 10 + a;
}
var p2 = new Proxy(f2, {});
function g2(a, b, c) { return p2(2); }
assertEquals(12, g2(1, 2, 3));
// Caller has less arguments than callee.
function f3(a, b, c) {
CheckStackTrace([f3, test]);
return 10 + a + b + c;
}
var p3 = new Proxy(f3, {});
function g3(a) { return p3(2, 3, 4); }
assertEquals(19, g3(1));
// Callee has arguments adaptor frame.
function f4(a, b, c) {
CheckStackTrace([f4, test]);
return 10 + a;
}
var p4 = new Proxy(f4, {});
function g4(a) { return p4(2); }
assertEquals(12, g4(1));
})();
// Tail call proxy function when caller has an arguments adaptor frame.
(function test() {
// Caller and callee have same number of arguments.
function f1(a) {
CheckStackTrace([f1, test]);
return 10 + a;
}
var p1 = new Proxy(f1, {});
function g1(a) { return p1(2); }
assertEquals(12, g1());
// Caller has more arguments than callee.
function f2(a) {
CheckStackTrace([f2, test]);
return 10 + a;
}
var p2 = new Proxy(f2, {});
function g2(a, b, c) { return p2(2); }
assertEquals(12, g2());
// Caller has less arguments than callee.
function f3(a, b, c) {
CheckStackTrace([f3, test]);
return 10 + a + b + c;
}
var p3 = new Proxy(f3, {});
function g3(a) { return p3(2, 3, 4); }
assertEquals(19, g3());
// Callee has arguments adaptor frame.
function f4(a, b, c) {
CheckStackTrace([f4, test]);
return 10 + a;
}
var p4 = new Proxy(f4, {});
function g4(a) { return p4(2); }
assertEquals(12, g4());
})();

View File

@ -1,143 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls --stack-size=100
//
// Tail calls work only in strict mode.
//
(function() {
function f(n) {
if (n <= 0) {
return "foo";
}
return f(n - 1);
}
assertThrows(()=>{ f(1e5) });
%OptimizeFunctionOnNextCall(f);
assertThrows(()=>{ f(1e5) });
})();
//
// Tail call normal functions.
//
(function() {
"use strict";
function f(n) {
if (n <= 0) {
return "foo";
}
return f(n - 1);
}
assertEquals("foo", f(1e5));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
})();
(function() {
"use strict";
function f(n) {
if (n <= 0) {
return "foo";
}
return f(n - 1, 42); // Call with arguments adaptor.
}
assertEquals("foo", f(1e5));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
})();
(function() {
"use strict";
function f(n){
if (n <= 0) {
return "foo";
}
return g(n - 1);
}
function g(n){
if (n <= 0) {
return "bar";
}
return f(n - 1);
}
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
})();
(function() {
"use strict";
function f(n){
if (n <= 0) {
return "foo";
}
return g(n - 1, 42); // Call with arguments adaptor.
}
function g(n){
if (n <= 0) {
return "bar";
}
return f(n - 1, 42); // Call with arguments adaptor.
}
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
})();
//
// Tail call bound functions.
//
(function() {
"use strict";
function f0(n) {
if (n <= 0) {
return "foo";
}
return f_bound(n - 1);
}
var f_bound = f0.bind({});
function f(n) {
return f_bound(n);
}
assertEquals("foo", f(1e5));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
})();
(function() {
"use strict";
function f0(n){
if (n <= 0) {
return "foo";
}
return g_bound(n - 1);
}
function g0(n){
if (n <= 0) {
return "bar";
}
return f_bound(n - 1);
}
var f_bound = f0.bind({});
var g_bound = g0.bind({});
function f(n) {
return f_bound(n);
}
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
})();

View File

@ -1,663 +0,0 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// Flags: --harmony-do-expressions
"use strict";
Error.prepareStackTrace = (error,stack) => {
error.strace = stack;
return error.message + "\n at " + stack.join("\n at ");
}
function CheckStackTrace(expected) {
var e = new Error();
e.stack; // prepare stack trace
var stack = e.strace;
assertEquals("CheckStackTrace", stack[0].getFunctionName());
for (var i = 0; i < expected.length; i++) {
assertEquals(expected[i].name, stack[i + 1].getFunctionName());
}
}
%NeverOptimizeFunction(CheckStackTrace);
function f(expected_call_stack, a, b) {
CheckStackTrace(expected_call_stack);
return a;
}
function f_153(expected_call_stack, a) {
CheckStackTrace(expected_call_stack);
return 153;
}
// Tail call when caller does not have an arguments adaptor frame.
(function() {
// Caller and callee have same number of arguments.
function f1(a) {
CheckStackTrace([f1, test]);
return 10 + a;
}
function g1(a) { return f1(2); }
// Caller has more arguments than callee.
function f2(a) {
CheckStackTrace([f2, test]);
return 10 + a;
}
function g2(a, b, c) { return f2(2); }
// Caller has less arguments than callee.
function f3(a, b, c) {
CheckStackTrace([f3, test]);
return 10 + a + b + c;
}
function g3(a) { return f3(2, 3, 4); }
// Callee has arguments adaptor frame.
function f4(a, b, c) {
CheckStackTrace([f4, test]);
return 10 + a;
}
function g4(a) { return f4(2); }
function test() {
assertEquals(12, g1(1));
assertEquals(12, g2(1, 2, 3));
assertEquals(19, g3(1));
assertEquals(12, g4(1));
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail call when caller has an arguments adaptor frame.
(function() {
// Caller and callee have same number of arguments.
function f1(a) {
CheckStackTrace([f1, test]);
return 10 + a;
}
function g1(a) { return f1(2); }
// Caller has more arguments than callee.
function f2(a) {
CheckStackTrace([f2, test]);
return 10 + a;
}
function g2(a, b, c) { return f2(2); }
// Caller has less arguments than callee.
function f3(a, b, c) {
CheckStackTrace([f3, test]);
return 10 + a + b + c;
}
function g3(a) { return f3(2, 3, 4); }
// Callee has arguments adaptor frame.
function f4(a, b, c) {
CheckStackTrace([f4, test]);
return 10 + a;
}
function g4(a) { return f4(2); }
function test() {
assertEquals(12, g1());
assertEquals(12, g2());
assertEquals(19, g3());
assertEquals(12, g4());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail call bound function when caller does not have an arguments
// adaptor frame.
(function() {
// Caller and callee have same number of arguments.
function f1(a) {
assertEquals(153, this.a);
CheckStackTrace([f1, test]);
return 10 + a;
}
var b1 = f1.bind({a: 153});
function g1(a) { return b1(2); }
// Caller has more arguments than callee.
function f2(a) {
assertEquals(153, this.a);
CheckStackTrace([f2, test]);
return 10 + a;
}
var b2 = f2.bind({a: 153});
function g2(a, b, c) { return b2(2); }
// Caller has less arguments than callee.
function f3(a, b, c) {
assertEquals(153, this.a);
CheckStackTrace([f3, test]);
return 10 + a + b + c;
}
var b3 = f3.bind({a: 153});
function g3(a) { return b3(2, 3, 4); }
// Callee has arguments adaptor frame.
function f4(a, b, c) {
assertEquals(153, this.a);
CheckStackTrace([f4, test]);
return 10 + a;
}
var b4 = f4.bind({a: 153});
function g4(a) { return b4(2); }
function test() {
assertEquals(12, g1(1));
assertEquals(12, g2(1, 2, 3));
assertEquals(19, g3(1));
assertEquals(12, g4(1));
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail call bound function when caller has an arguments adaptor frame.
(function() {
// Caller and callee have same number of arguments.
function f1(a) {
assertEquals(153, this.a);
CheckStackTrace([f1, test]);
return 10 + a;
}
var b1 = f1.bind({a: 153});
function g1(a) { return b1(2); }
// Caller has more arguments than callee.
function f2(a) {
assertEquals(153, this.a);
CheckStackTrace([f2, test]);
return 10 + a;
}
var b2 = f2.bind({a: 153});
function g2(a, b, c) { return b2(2); }
// Caller has less arguments than callee.
function f3(a, b, c) {
assertEquals(153, this.a);
CheckStackTrace([f3, test]);
return 10 + a + b + c;
}
var b3 = f3.bind({a: 153});
function g3(a) { return b3(2, 3, 4); }
// Callee has arguments adaptor frame.
function f4(a, b, c) {
assertEquals(153, this.a);
CheckStackTrace([f4, test]);
return 10 + a;
}
var b4 = f4.bind({a: 153});
function g4(a) { return b4(2); }
function test() {
assertEquals(12, g1());
assertEquals(12, g2());
assertEquals(19, g3());
assertEquals(12, g4());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail calling from getter.
(function() {
function g(v) {
CheckStackTrace([g, test]);
%DeoptimizeFunction(test);
return 153;
}
%NeverOptimizeFunction(g);
function f(v) {
return g();
}
%SetForceInlineFlag(f);
function test() {
var o = {};
o.__defineGetter__('p', f);
assertEquals(153, o.p);
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail calling from setter.
(function() {
function g() {
CheckStackTrace([g, test]);
%DeoptimizeFunction(test);
return 153;
}
%NeverOptimizeFunction(g);
function f(v) {
return g();
}
%SetForceInlineFlag(f);
function test() {
var o = {};
o.__defineSetter__('q', f);
assertEquals(1, o.q = 1);
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail calling from constructor.
(function() {
function g(context) {
CheckStackTrace([g, test]);
%DeoptimizeFunction(test);
return {x: 153};
}
%NeverOptimizeFunction(g);
function A() {
this.x = 42;
return g();
}
function test() {
var o = new A();
//%DebugPrint(o);
assertEquals(153, o.x);
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail calling via various expressions.
(function() {
function g1(a) {
return f([f, g1, test], false) || f([f, test], true);
}
function g2(a) {
return f([f, g2, test], true) && f([f, test], true);
}
function g3(a) {
return f([f, g3, test], 13), f([f, test], 153);
}
function g4(a) {
return f([f, g4, test], false) ||
(f([f, g4, test], true) && f([f, test], true));
}
function g5(a) {
return f([f, g5, test], true) &&
(f([f, g5, test], false) || f([f, test], true));
}
function g6(a) {
return f([f, g6, test], 13), f([f, g6, test], 42),
f([f, test], 153);
}
function g7(a) {
return f([f, g7, test], false) ||
(f([f, g7, test], false) ? f([f, test], true)
: f([f, test], true));
}
function g8(a) {
return f([f, g8, test], false) || f([f, g8, test], true) &&
f([f, test], true);
}
function g9(a) {
return f([f, g9, test], true) && f([f, g9, test], false) ||
f([f, test], true);
}
function g10(a) {
return f([f, g10, test], true) && f([f, g10, test], false) ||
f([f, g10, test], true) ?
f([f, g10, test], true) && f([f, g10, test], false) ||
f([f, test], true) :
f([f, g10, test], true) && f([f, g10, test], false) ||
f([f, test], true);
}
function test() {
assertEquals(true, g1());
assertEquals(true, g2());
assertEquals(153, g3());
assertEquals(true, g4());
assertEquals(true, g5());
assertEquals(153, g6());
assertEquals(true, g7());
assertEquals(true, g8());
assertEquals(true, g9());
assertEquals(true, g10());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail calling from various statements.
(function() {
function g1() {
for (var v in {a:0}) {
return f_153([f_153, g1, test]);
}
}
function g1let() {
for (let v in {a:0}) {
return f_153([f_153, g1let, test]);
}
}
function g1nodecl() {
var v;
for (v in {a:0}) {
return f_153([f_153, g1nodecl, test]);
}
}
function g2() {
for (var v of [1, 2, 3]) {
return f_153([f_153, g2, test]);
}
}
function g2let() {
for (let v of [1, 2, 3]) {
return f_153([f_153, g2let, test]);
}
}
function g2nodecl() {
var v;
for (v of [1, 2, 3]) {
return f_153([f_153, g2nodecl, test]);
}
}
function g3() {
for (var i = 0; i < 10; i++) {
return f_153([f_153, test]);
}
}
function g3let() {
for (let i = 0; i < 10; i++) {
return f_153([f_153, test]);
}
}
function g3nodecl() {
var i;
for (i = 0; i < 10; i++) {
return f_153([f_153, test]);
}
}
function g4() {
while (true) {
return f_153([f_153, test]);
}
}
function g5() {
do {
return f_153([f_153, test]);
} while (true);
}
function test() {
assertEquals(153, g1());
assertEquals(153, g1let());
assertEquals(153, g1nodecl());
assertEquals(153, g2());
assertEquals(153, g2let());
assertEquals(153, g2nodecl());
assertEquals(153, g3());
assertEquals(153, g3let());
assertEquals(153, g3nodecl());
assertEquals(153, g4());
assertEquals(153, g5());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from try-catch constructs.
(function() {
function tc1(a) {
try {
f_153([f_153, tc1, test]);
return f_153([f_153, tc1, test]);
} catch(e) {
f_153([f_153, tc1, test]);
}
}
function tc2(a) {
try {
f_153([f_153, tc2, test]);
throw new Error("boom");
} catch(e) {
f_153([f_153, tc2, test]);
return f_153([f_153, test]);
}
}
function tc3(a) {
try {
f_153([f_153, tc3, test]);
throw new Error("boom");
} catch(e) {
f_153([f_153, tc3, test]);
}
f_153([f_153, tc3, test]);
return f_153([f_153, test]);
}
function test() {
assertEquals(153, tc1());
assertEquals(153, tc2());
assertEquals(153, tc3());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from try-finally constructs.
(function() {
function tf1(a) {
try {
f_153([f_153, tf1, test]);
return f_153([f_153, tf1, test]);
} finally {
f_153([f_153, tf1, test]);
}
}
function tf2(a) {
try {
f_153([f_153, tf2, test]);
throw new Error("boom");
} finally {
f_153([f_153, tf2, test]);
return f_153([f_153, test]);
}
}
function tf3(a) {
try {
f_153([f_153, tf3, test]);
} finally {
f_153([f_153, tf3, test]);
}
return f_153([f_153, test]);
}
function test() {
assertEquals(153, tf1());
assertEquals(153, tf2());
assertEquals(153, tf3());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from try-catch-finally constructs.
(function() {
function tcf1(a) {
try {
f_153([f_153, tcf1, test]);
return f_153([f_153, tcf1, test]);
} catch(e) {
} finally {
f_153([f_153, tcf1, test]);
}
}
function tcf2(a) {
try {
f_153([f_153, tcf2, test]);
throw new Error("boom");
} catch(e) {
f_153([f_153, tcf2, test]);
return f_153([f_153, tcf2, test]);
} finally {
f_153([f_153, tcf2, test]);
}
}
function tcf3(a) {
try {
f_153([f_153, tcf3, test]);
throw new Error("boom");
} catch(e) {
f_153([f_153, tcf3, test]);
} finally {
f_153([f_153, tcf3, test]);
return f_153([f_153, test]);
}
}
function tcf4(a) {
try {
f_153([f_153, tcf4, test]);
throw new Error("boom");
} catch(e) {
f_153([f_153, tcf4, test]);
} finally {
f_153([f_153, tcf4, test]);
}
return f_153([f_153, test]);
}
function test() {
assertEquals(153, tcf1());
assertEquals(153, tcf2());
assertEquals(153, tcf3());
assertEquals(153, tcf4());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from arrow functions.
(function () {
function g1(a) {
return (() => { return f_153([f_153, test]); })();
}
function g2(a) {
return (() => f_153([f_153, test]))();
}
function g3(a) {
var closure = () => f([f, closure, test], true)
? f_153([f_153, test])
: f_153([f_153, test]);
return closure();
}
function test() {
assertEquals(153, g1());
assertEquals(153, g2());
assertEquals(153, g3());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from do expressions.
(function () {
function g1(a) {
var a = do { return f_153([f_153, test]); 42; };
return a;
}
function test() {
assertEquals(153, g1());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();

View File

@ -137,7 +137,6 @@
# Slow tests.
'copy-on-write-assert': [PASS, SLOW],
'es6/tail-call-megatest*': [PASS, SLOW, FAST_VARIANTS, ['tsan', SKIP]],
'es6/typedarray-construct-offset-not-smi': [PASS, SLOW],
'harmony/regexp-property-script-extensions': [PASS, SLOW],
'numops-fuzz-part*': [PASS, ['mode == debug', SLOW]],
@ -565,9 +564,6 @@
# Deopting uses just enough memory to make this one OOM.
'regress/regress-3976': [SKIP],
# Too slow.
'es6/tail-call-megatest*': [SKIP],
# Forced optimisation path tests.
'shared-function-tier-up-turbo': [SKIP],

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-tailcalls
"use strict";
function h(global) { return global.boom(); }

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-tailcalls --allow-natives-syntax
// Flags: --allow-natives-syntax
"use strict";

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// Flags: --allow-natives-syntax
"use strict";

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// Flags: --allow-natives-syntax
"use strict";

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-tailcalls --allow-natives-syntax
// Flags: --allow-natives-syntax
"use strict";

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// Flags: --allow-natives-syntax
function h() {
var res = g.arguments[0].x;

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// Flags: --allow-natives-syntax
function h() {
var res = g.arguments;

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-tailcalls --allow-natives-syntax
// Flags: --allow-natives-syntax
"use strict";

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// Flags: --allow-natives-syntax
function f() {
"use strict";

Some files were not shown because too many files have changed in this diff Show More