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