Commit 1350eb3d authored by ishell's avatar ishell Committed by Commit bot

[es8] More spec compliant syntactic tail calls implementation.

Unlike previous implementation where the 'continue' keyword was a feature of a return statement the keyword is now recognized as a part of expression. Error reporting was significantly improved.

--harmony-explicit-tailcalls option is now orthogonal to --harmony-tailcalls so we can test both modes at the same time.

This CL also adds %GetExceptionDetails(exception) that fetches hidden |start_pos| and |end_pos| values from the exception object.

BUG=v8:4915
LOG=N

Review-Url: https://codereview.chromium.org/1928203002
Cr-Commit-Position: refs/heads/master@{#36024}
parent 46907cbb
......@@ -426,10 +426,6 @@ class CallSite {
"inside a block.") \
T(StrictOctalLiteral, "Octal literals are not allowed in strict mode.") \
T(StrictWith, "Strict mode code may not include a with statement") \
T(TailCallInCatchBlock, \
"Tail call expression in catch block when finally block is also present.") \
T(TailCallInForInOf, "Tail call expression in for-in/of body.") \
T(TailCallInTryBlock, "Tail call expression in try block.") \
T(TemplateOctalLiteral, \
"Octal literals are not allowed in template strings.") \
T(ThisFormalParameter, "'this' is not a valid formal parameter name") \
......@@ -443,10 +439,16 @@ class CallSite {
T(UnexpectedEOS, "Unexpected end of input") \
T(UnexpectedFunctionSent, \
"function.sent expression is not allowed outside a generator") \
T(UnexpectedInsideTailCall, "Unexpected expression inside tail call") \
T(UnexpectedReserved, "Unexpected reserved word") \
T(UnexpectedStrictReserved, "Unexpected strict mode reserved word") \
T(UnexpectedSuper, "'super' keyword unexpected here") \
T(UnexpectedNewTarget, "new.target expression is not allowed here") \
T(UnexpectedTailCall, "Tail call expression is not allowed here") \
T(UnexpectedTailCallInCatchBlock, \
"Tail call expression in catch block when finally block is also present") \
T(UnexpectedTailCallInForInOf, "Tail call expression in for-in/of body") \
T(UnexpectedTailCallInTryBlock, "Tail call expression in try block") \
T(UnexpectedTemplateString, "Unexpected template string") \
T(UnexpectedToken, "Unexpected token %") \
T(UnexpectedTokenIdentifier, "Unexpected identifier") \
......
......@@ -39,9 +39,11 @@ class ExpressionClassifier {
ArrowFormalParametersProduction = 1 << 6,
LetPatternProduction = 1 << 7,
CoverInitializedNameProduction = 1 << 8,
TailCallExpressionProduction = 1 << 9,
ExpressionProductions =
(ExpressionProduction | FormalParameterInitializerProduction),
(ExpressionProduction | FormalParameterInitializerProduction |
TailCallExpressionProduction),
PatternProductions = (BindingPatternProduction |
AssignmentPatternProduction | LetPatternProduction),
FormalParametersProductions = (DistinctFormalParametersProduction |
......@@ -143,6 +145,13 @@ class ExpressionClassifier {
return cover_initialized_name_error_;
}
bool has_tail_call_expression() const {
return !is_valid(TailCallExpressionProduction);
}
const Error& tail_call_expression_error() const {
return tail_call_expression_error_;
}
bool is_simple_parameter_list() const {
return !(function_properties_ & NonSimpleParameter);
}
......@@ -260,6 +269,16 @@ class ExpressionClassifier {
cover_initialized_name_error_.arg = arg;
}
void RecordTailCallExpressionError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (has_tail_call_expression()) return;
invalid_productions_ |= TailCallExpressionProduction;
tail_call_expression_error_.location = loc;
tail_call_expression_error_.message = message;
tail_call_expression_error_.arg = arg;
}
void ForgiveCoverInitializedNameError() {
invalid_productions_ &= ~CoverInitializedNameProduction;
cover_initialized_name_error_ = Error();
......@@ -305,6 +324,8 @@ class ExpressionClassifier {
let_pattern_error_ = inner->let_pattern_error_;
if (errors & CoverInitializedNameProduction)
cover_initialized_name_error_ = inner->cover_initialized_name_error_;
if (errors & TailCallExpressionProduction)
tail_call_expression_error_ = inner->tail_call_expression_error_;
}
// As an exception to the above, the result continues to be a valid arrow
......@@ -340,6 +361,8 @@ class ExpressionClassifier {
int non_pattern_begin_;
unsigned invalid_productions_;
unsigned function_properties_;
// TODO(ishell): consider using Zone[Hash]Map<TargetProduction, Error>
// here to consume less stack space during parsing.
Error expression_error_;
Error formal_parameter_initializer_error_;
Error binding_pattern_error_;
......@@ -349,6 +372,7 @@ class ExpressionClassifier {
Error strict_mode_formal_parameter_error_;
Error let_pattern_error_;
Error cover_initialized_name_error_;
Error tail_call_expression_error_;
DuplicateFinder* duplicate_finder_;
};
......
This diff is collapsed.
......@@ -765,6 +765,10 @@ void ParserTraits::MarkTailPosition(Expression* expression) {
expression->MarkTail();
}
void ParserTraits::MarkCollectedTailCallExpressions() {
parser_->MarkCollectedTailCallExpressions();
}
Parser::Parser(ParseInfo* info)
: ParserBase<ParserTraits>(info->zone(), &scanner_, info->stack_limit(),
info->extension(), info->ast_value_factory(),
......@@ -2588,13 +2592,6 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
function_state_->set_return_location(loc);
Token::Value tok = peek();
int tail_call_position = -1;
if (FLAG_harmony_explicit_tailcalls && tok == Token::CONTINUE) {
Consume(Token::CONTINUE);
tail_call_position = position();
tok = peek();
}
Statement* result;
Expression* return_value;
if (scanner()->HasAnyLineTerminatorBeforeNext() ||
......@@ -2608,9 +2605,13 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
}
} else {
int pos = peek_position();
return_value = ParseExpression(true, CHECK_OK);
if (IsSubclassConstructor(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);
// For subclass constructors we need to return this in case of undefined
// return a Smi (transformed into an exception in the ConstructStub)
// for a non object.
......@@ -2649,24 +2650,16 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
return_value = factory()->NewConditional(
is_undefined, ThisExpression(scope_, factory(), pos),
is_object_conditional, pos);
}
// TODO(ishell): update chapter number.
// ES8 XX.YY.ZZ
if (tail_call_position >= 0) {
ReturnExprContext return_expr_context =
function_state_->return_expr_context();
if (return_expr_context != ReturnExprContext::kNormal) {
ReportIllegalTailCallAt(tail_call_position, return_expr_context);
*ok = false;
return NULL;
} else {
ReturnExprScope maybe_allow_tail_calls(
function_state_, ReturnExprContext::kInsideValidReturnStatement);
return_value = ParseExpression(true, CHECK_OK);
if (allow_tailcalls() && !is_sloppy(language_mode())) {
// ES6 14.6.1 Static Semantics: IsInTailPosition
Scanner::Location loc(pos, pos + 1);
function_state_->AddExpressionInTailPosition(return_value, loc);
}
function_state_->AddExpressionInTailPosition(return_value,
tail_call_position);
} else if (allow_tailcalls() && !is_sloppy(language_mode())) {
// ES6 14.6.1 Static Semantics: IsInTailPosition
function_state_->AddExpressionInTailPosition(return_value, pos);
}
}
ExpectSemicolon(CHECK_OK);
......@@ -2879,7 +2872,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Scope* catch_scope = NULL;
Variable* catch_variable = NULL;
Block* catch_block = NULL;
List<TailCallExpression> expressions_in_tail_position_in_catch_block;
TailCallExpressionList tail_call_expressions_in_catch_block(zone());
if (tok == Token::CATCH) {
Consume(Token::CATCH);
......@@ -2906,8 +2899,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
{
CollectExpressionsInTailPositionToListScope
collect_expressions_in_tail_position_scope(
function_state_, &expressions_in_tail_position_in_catch_block);
collect_tail_call_expressions_scope(
function_state_, &tail_call_expressions_in_catch_block);
BlockState block_state(&scope_, catch_scope);
// TODO(adamk): Make a version of ParseBlock that takes a scope and
......@@ -2987,8 +2980,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
if (catch_block != NULL) {
// For a try-catch construct append return expressions from the catch block
// to the list of return expressions.
function_state_->expressions_in_tail_position().AddAll(
expressions_in_tail_position_in_catch_block);
function_state_->tail_call_expressions().Append(
tail_call_expressions_in_catch_block);
DCHECK(finally_block == NULL);
DCHECK(catch_scope != NULL && catch_variable != NULL);
......@@ -2996,12 +2989,11 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
catch_variable, catch_block, pos);
} else {
if (FLAG_harmony_explicit_tailcalls &&
expressions_in_tail_position_in_catch_block.length() > 0) {
!tail_call_expressions_in_catch_block.is_empty()) {
// TODO(ishell): update chapter number.
// ES8 XX.YY.ZZ
int pos = expressions_in_tail_position_in_catch_block[0].pos;
ReportMessageAt(Scanner::Location(pos, pos + 1),
MessageTemplate::kTailCallInCatchBlock);
ReportMessageAt(tail_call_expressions_in_catch_block.location(),
MessageTemplate::kUnexpectedTailCallInCatchBlock);
*ok = false;
return NULL;
}
......@@ -4585,13 +4577,7 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
RelocInfo::kNoPosition));
}
// ES6 14.6.1 Static Semantics: IsInTailPosition
// Mark collected return expressions that are in tail call position.
const List<TailCallExpression>& expressions_in_tail_position =
function_state_->expressions_in_tail_position();
for (int i = 0; i < expressions_in_tail_position.length(); ++i) {
MarkTailPosition(expressions_in_tail_position[i].expression);
}
MarkCollectedTailCallExpressions();
return result;
}
......@@ -4666,6 +4652,7 @@ ClassLiteral* Parser::ParseClassLiteral(ExpressionClassifier* classifier,
block_scope->set_start_position(scanner()->location().end_pos);
ExpressionClassifier extends_classifier(this);
extends = ParseLeftHandSideExpression(&extends_classifier, CHECK_OK);
CheckNoTailCallExpressions(&extends_classifier, CHECK_OK);
RewriteNonPattern(&extends_classifier, CHECK_OK);
if (classifier != nullptr) {
classifier->Accumulate(&extends_classifier,
......@@ -5308,6 +5295,18 @@ void Parser::RaiseLanguageMode(LanguageMode mode) {
SetLanguageMode(scope_, old > mode ? old : mode);
}
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) {
Expression* expression = tail_call_expressions[i];
// If only FLAG_harmony_explicit_tailcalls is enabled then expression
// must be a Call expression.
DCHECK(FLAG_harmony_tailcalls || !FLAG_harmony_explicit_tailcalls ||
expression->IsCall());
MarkTailPosition(expression);
}
}
void ParserTraits::RewriteDestructuringAssignments() {
parser_->RewriteDestructuringAssignments();
......
......@@ -573,6 +573,7 @@ class ParserTraits {
bool name_is_strict_reserved, int pos,
bool* ok);
V8_INLINE void MarkCollectedTailCallExpressions();
V8_INLINE void MarkTailPosition(Expression* expression);
V8_INLINE void CheckConflictingVarDeclarations(v8::internal::Scope* scope,
......@@ -1048,6 +1049,8 @@ class Parser : public ParserBase<ParserTraits> {
void SetLanguageMode(Scope* scope, LanguageMode mode);
void RaiseLanguageMode(LanguageMode mode);
V8_INLINE void MarkCollectedTailCallExpressions();
V8_INLINE void RewriteDestructuringAssignments();
V8_INLINE Expression* RewriteExponentiation(Expression* left,
......
......@@ -706,28 +706,21 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
// This is not handled during preparsing.
Token::Value tok = peek();
int tail_call_position = -1;
if (FLAG_harmony_explicit_tailcalls && tok == Token::CONTINUE) {
Consume(Token::CONTINUE);
tail_call_position = position();
tok = peek();
}
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON &&
tok != Token::RBRACE &&
tok != Token::EOS) {
// 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.
ReturnExprContext return_expr_context =
IsSubclassConstructor(function_state_->kind())
? function_state_->return_expr_context()
: ReturnExprContext::kInsideValidReturnStatement;
ReturnExprScope maybe_allow_tail_calls(function_state_,
return_expr_context);
ParseExpression(true, CHECK_OK);
if (tail_call_position >= 0) {
ReturnExprContext return_expr_context =
function_state_->return_expr_context();
if (return_expr_context != ReturnExprContext::kNormal) {
ReportIllegalTailCallAt(tail_call_position, return_expr_context);
*ok = false;
return Statement::Default();
}
function_state_->AddExpressionInTailPosition(
PreParserExpression::Default(), tail_call_position);
}
}
ExpectSemicolon(CHECK_OK);
return Statement::Jump();
......@@ -994,7 +987,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
*ok = false;
return Statement::Default();
}
List<TailCallExpression> expressions_in_tail_position_in_catch_block;
TailCallExpressionList tail_call_expressions_in_catch_block(zone());
bool catch_block_exists = false;
if (tok == Token::CATCH) {
Consume(Token::CATCH);
......@@ -1006,8 +999,8 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
Expect(Token::RPAREN, CHECK_OK);
{
CollectExpressionsInTailPositionToListScope
collect_expressions_in_tail_position_scope(
function_state_, &expressions_in_tail_position_in_catch_block);
collect_tail_call_expressions_scope(
function_state_, &tail_call_expressions_in_catch_block);
BlockState block_state(&scope_, catch_scope);
Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
{
......@@ -1022,12 +1015,11 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
Consume(Token::FINALLY);
ParseBlock(CHECK_OK);
if (FLAG_harmony_explicit_tailcalls && catch_block_exists &&
expressions_in_tail_position_in_catch_block.length() > 0) {
!tail_call_expressions_in_catch_block.is_empty()) {
// TODO(ishell): update chapter number.
// ES8 XX.YY.ZZ
int pos = expressions_in_tail_position_in_catch_block[0].pos;
ReportMessageAt(Scanner::Location(pos, pos + 1),
MessageTemplate::kTailCallInCatchBlock);
ReportMessageAt(tail_call_expressions_in_catch_block.location(),
MessageTemplate::kUnexpectedTailCallInCatchBlock);
*ok = false;
return Statement::Default();
}
......@@ -1165,6 +1157,7 @@ PreParserExpression PreParser::ParseClassLiteral(
if (has_extends) {
ExpressionClassifier extends_classifier(this);
ParseLeftHandSideExpression(&extends_classifier, CHECK_OK);
CheckNoTailCallExpressions(&extends_classifier, CHECK_OK);
ValidateExpression(&extends_classifier, CHECK_OK);
if (classifier != nullptr) {
classifier->Accumulate(&extends_classifier,
......
......@@ -897,6 +897,7 @@ class PreParserTraits {
bool name_is_strict_reserved, int pos,
bool* ok);
V8_INLINE void MarkCollectedTailCallExpressions() {}
V8_INLINE void MarkTailPosition(PreParserExpression) {}
PreParserExpressionList PrepareSpreadArguments(PreParserExpressionList list) {
......
......@@ -8,6 +8,7 @@
#include "src/deoptimizer.h"
#include "src/frames-inl.h"
#include "src/full-codegen/full-codegen.h"
#include "src/isolate-inl.h"
#include "src/snapshot/natives.h"
namespace v8 {
......@@ -481,6 +482,31 @@ RUNTIME_FUNCTION(Runtime_TraceTailCall) {
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetExceptionDetails) {
HandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, exception_obj, 0);
Factory* factory = isolate->factory();
Handle<JSMessageObject> message_obj =
isolate->CreateMessage(exception_obj, nullptr);
Handle<JSObject> message = factory->NewJSObject(isolate->object_function());
Handle<String> key;
Handle<Object> value;
key = factory->NewStringFromAsciiChecked("start_pos");
value = handle(Smi::FromInt(message_obj->start_position()), isolate);
JSObject::SetProperty(message, key, value, STRICT).Assert();
key = factory->NewStringFromAsciiChecked("end_pos");
value = handle(Smi::FromInt(message_obj->end_position()), isolate);
JSObject::SetProperty(message, key, value, STRICT).Assert();
return *message;
}
RUNTIME_FUNCTION(Runtime_HaveSameMap) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
......
......@@ -870,6 +870,7 @@ namespace internal {
F(SetAllocationTimeout, -1 /* 2 || 3 */, 1) \
F(DebugPrint, 1, 1) \
F(DebugTrace, 0, 1) \
F(GetExceptionDetails, 1, 1) \
F(GlobalPrint, 1, 1) \
F(SystemBreak, 0, 1) \
F(SetFlags, 1, 1) \
......
// 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-explicit-tailcalls
function f() {
return 1;
}
function g() {
return continue f() - a ;
}
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here
return continue f() - a ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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-explicit-tailcalls
function f() {
return 1;
}
function g() {
return b + continue f() ;
}
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here
return b + continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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-explicit-tailcalls
function f() {
return 1;
}
function g() {
return 1, 2, 3, continue f() , 4 ;
}
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here
return 1, 2, 3, continue f() , 4 ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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-explicit-tailcalls
function g() {
return class A extends continue f() {};
}
*%(basename)s:8: SyntaxError: Tail call expression is not allowed here
return class A extends continue f() {};
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
......@@ -10,6 +10,6 @@ function f() {
function g() {
for (var v in {a:0}) {
return continue f();
return continue f() ;
}
}
*%(basename)s:13: SyntaxError: Tail call expression in for-in/of body.
return continue f();
^
SyntaxError: Tail call expression in for-in/of body.
*%(basename)s:13: SyntaxError: Tail call expression in for-in/of body
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression in for-in/of body
......@@ -10,6 +10,6 @@ function f() {
function g() {
for (var v of [1, 2, 3]) {
return continue f();
return continue f() ;
}
}
*%(basename)s:13: SyntaxError: Tail call expression in for-in/of body.
return continue f();
^
SyntaxError: Tail call expression in for-in/of body.
*%(basename)s:13: SyntaxError: Tail call expression in for-in/of body
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression in for-in/of body
// 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-explicit-tailcalls
function f() {
return 1;
}
function g() {
return continue f() && a ;
}
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here
return continue f() && a ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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-explicit-tailcalls
function f() {
return 1;
}
function g() {
return continue f() || a ;
}
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here
return continue f() || a ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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-explicit-tailcalls
function g() {
class A {};
class B extends A {
constructor() {
return continue f() ;
}
}
}
*%(basename)s:11: SyntaxError: Tail call expression is not allowed here
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
......@@ -12,7 +12,7 @@ function g() {
try {
f();
} catch(e) {
return continue f();
return continue f() ;
} finally {
f();
}
......
*%(basename)s:15: SyntaxError: Tail call expression in catch block when finally block is also present.
return continue f();
^
SyntaxError: Tail call expression in catch block when finally block is also present.
*%(basename)s:15: SyntaxError: Tail call expression in catch block when finally block is also present
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression in catch block when finally block is also present
......@@ -13,7 +13,7 @@ function g() {
try {
f();
} catch(e) {
return continue f();
return continue f() ;
}
} finally {
f();
......
*%(basename)s:16: SyntaxError: Tail call expression in try block.
return continue f();
^
SyntaxError: Tail call expression in try block.
*%(basename)s:16: SyntaxError: Tail call expression in try block
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression in try block
......@@ -10,7 +10,7 @@ function f() {
function g() {
try {
return continue f();
return continue f() ;
} catch(e) {
}
}
*%(basename)s:13: SyntaxError: Tail call expression in try block.
return continue f();
^
SyntaxError: Tail call expression in try block.
*%(basename)s:13: SyntaxError: Tail call expression in try block
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression in try block
// 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-explicit-tailcalls
function f() {
return 1;
}
function g() {
return (continue f(1)) (2) ;
}
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here
return (continue f(1)) (2) ;
^^^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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-explicit-tailcalls
function g(x) {
return continue x ;
}
*%(basename)s:8: SyntaxError: Unexpected expression inside tail call
return continue x ;
^
SyntaxError: Unexpected expression inside tail call
// 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-explicit-tailcalls
function f() {
return 1;
}
function g() {
return continue new f() ;
}
*%(basename)s:12: SyntaxError: Unexpected expression inside tail call
return continue new f() ;
^^^^^^^
SyntaxError: Unexpected expression inside tail call
// 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-explicit-tailcalls
function f() {
return 1;
}
function g() {
var x = continue f() ;
}
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here
var x = continue f() ;
^^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
......@@ -3,6 +3,8 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// Flags: --harmony-do-expressions
"use strict";
Error.prepareStackTrace = (error,stack) => {
......@@ -235,10 +237,57 @@ function f_153(expected_call_stack, 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();
......@@ -450,9 +499,34 @@ function f_153(expected_call_stack, 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();
......
This diff is collapsed.
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-explicit-tailcalls
// Flags: --harmony-do-expressions
Error.prepareStackTrace = (error,stack) => {
error.strace = stack;
......@@ -223,21 +224,68 @@ function f_153(expected_call_stack, a) {
// Tail calling via various expressions.
(function() {
function g1(a) {
return continue f([f, g1, test], false) || f([f, test], true);
return f([f, g1, test], false) || continue f([f, test], true);
}
function g2(a) {
return continue f([f, g2, test], true) && f([f, test], true);
return f([f, g2, test], true) && continue f([f, test], true);
}
function g3(a) {
return continue f([f, g3, test], 13), f([f, test], 153);
return f([f, g3, test], 13), continue f([f, test], 153);
}
function g4(a) {
return f([f, g4, test], false) ||
(f([f, g4, test], true) && continue f([f, test], true));
}
function g5(a) {
return f([f, g5, test], true) &&
(f([f, g5, test], false) || continue f([f, test], true));
}
function g6(a) {
return f([f, g6, test], 13), f([f, g6, test], 42),
continue f([f, test], 153);
}
function g7(a) {
return f([f, g7, test], false) ||
(f([f, g7, test], false) ? continue f([f, test], true)
: continue f([f, test], true));
}
function g8(a) {
return f([f, g8, test], false) || f([f, g8, test], true) &&
continue f([f, test], true);
}
function g9(a) {
return f([f, g9, test], true) && f([f, g9, test], false) ||
continue 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) ||
continue f([f, test], true) :
f([f, g10, test], true) && f([f, g10, test], false) ||
continue 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();
......@@ -404,10 +452,9 @@ function f_153(expected_call_stack, a) {
}
function g3(a) {
var closure = () => continue f([f, closure, test], true)
? f_153([f_153, test])
: f_153([f_153, test]);
var closure = () => f([f, closure, test], true)
? continue f_153([f_153, test])
: continue f_153([f_153, test]);
return continue closure();
}
......@@ -421,3 +468,20 @@ function f_153(expected_call_stack, a) {
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from do expressions.
(function () {
function g1(a) {
var a = do { return continue f_153([f_153, test]); 42; };
return a;
}
function test() {
assertEquals(153, g1());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment