Commit 5af4cd98 authored by littledan's avatar littledan Committed by Commit bot

Disallow tail calls from async functions and generators

Tail calls don't make sense from async functions and generators, as
each activation of these functions needs to make a new, distnict,
non-reused generator object. These tail calls are not required per
spec. This patch disables both syntactic and implicit tail calls
in async functions and generators.

R=neis
BUG=v8:5301,chromium:639270

Review-Url: https://codereview.chromium.org/2278413003
Cr-Commit-Position: refs/heads/master@{#38986}
parent 0f01a588
......@@ -2548,6 +2548,7 @@ ParserBase<Impl>::ParseTailCallExpression(ExpressionClassifier* classifier,
CheckNoTailCallExpressions(classifier, CHECK_OK);
Scanner::Location loc(pos, scanner()->location().end_pos);
if (!expression->IsCall()) {
Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
impl()->ReportMessageAt(sub_loc,
......@@ -2567,6 +2568,12 @@ ParserBase<Impl>::ParseTailCallExpression(ExpressionClassifier* classifier,
*ok = false;
return impl()->EmptyExpression();
}
if (is_resumable()) {
Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
impl()->ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedTailCall);
*ok = false;
return impl()->EmptyExpression();
}
ReturnExprContext return_expr_context =
function_state_->return_expr_context();
if (return_expr_context != ReturnExprContext::kInsideValidReturnStatement) {
......
......@@ -2369,7 +2369,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
function_state_, ReturnExprContext::kInsideValidReturnStatement);
return_value = ParseExpression(true, CHECK_OK);
if (allow_tailcalls() && !is_sloppy(language_mode())) {
if (allow_tailcalls() && !is_sloppy(language_mode()) && !is_resumable()) {
// ES6 14.6.1 Static Semantics: IsInTailPosition
function_state_->AddImplicitTailCallExpression(return_value);
}
......
// 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() {
'use strict';
return continue f();
}
*%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return continue f();
^^^
SyntaxError: Tail call expression is not allowed here
......@@ -3,7 +3,7 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-explicit-tailcalls
// Flags: --harmony-do-expressions
// Flags: --harmony-do-expressions --harmony-async-await
"use strict";
var SyntaxErrorTests = [
......@@ -128,7 +128,10 @@ var SyntaxErrorTests = [
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ function* G() { yield continue foo(); } }`,
err: ` ^^^^^^^^^^^^^^`,
err: ` ^^^^^`,
},
{ src: `()=>{ function* G() { return continue foo(); } }`,
err: ` ^^^^^`,
},
{ src: `()=>{ (1, 2, 3, continue f() ) => {} }`,
err: ` ^^^^^^^^^^^^`,
......@@ -235,6 +238,9 @@ var SyntaxErrorTests = [
{ src: `class A extends continue f () {}; }`,
err: ` ^^^^^^^^^^^^^`,
},
{ src: `async() => continue foo()`,
err: ` ^^^^^`,
},
],
},
{ msg: "Tail call expression in try block",
......@@ -311,7 +317,6 @@ var NoErrorTests = [
`()=>{ return a || continue f() ; }`,
`()=>{ return a && continue f() ; }`,
`()=>{ return a , continue f() ; }`,
`()=>{ function* G() { return continue foo(); } }`,
`()=>{ class A { foo() { return continue super.f() ; } } }`,
`()=>{ function B() { return continue new.target() ; } }`,
`()=>{ return continue do { x ? foo() : bar() ; }() }`,
......
// 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 --es-staging --ignition-staging --turbo
"use strict";
var g = (async () => { return JSON.stringify() });
g();
g();
%OptimizeFunctionOnNextCall(g);
g();
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