Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(571)

Unified Diff: src/parsing/parser.cc

Issue 2654423004: [async-functions] support await expressions in finally statements (Closed)
Patch Set: I'd like to build with -Wunused-variables locally, but how!? Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/parsing/parser.cc
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index 36268493e971ae185e2f88b5254cc5a88a7dde70..6e7e51c1604c93352e427da48c6e09c92e34764f 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -415,8 +415,8 @@ Expression* Parser::NewTargetExpression(int pos) {
Expression* Parser::FunctionSentExpression(int pos) {
// We desugar function.sent into %_GeneratorGetInputOrDebugPos(generator).
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
- VariableProxy* generator =
- factory()->NewVariableProxy(function_state_->generator_object_variable());
+ InternalVariable* generator =
+ factory()->NewInternalVariable(InternalVariable::kGeneratorObject);
args->Add(generator, zone());
return factory()->NewCallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos,
args, pos);
@@ -697,13 +697,7 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
DCHECK(!is_duplicate);
var->AllocateTo(VariableLocation::PARAMETER, 0);
- PrepareGeneratorVariables();
- Expression* initial_yield =
- BuildInitialYield(kNoSourcePosition, kGeneratorFunction);
- body->Add(
- factory()->NewExpressionStatement(initial_yield, kNoSourcePosition),
- zone());
-
+ scope->ForceContextAllocation();
ParseModuleItemList(body, &ok);
ok = ok &&
module()->Validate(this->scope()->AsModuleScope(),
@@ -1606,8 +1600,6 @@ Expression* Parser::RewriteReturn(Expression* return_value, int pos) {
}
if (is_generator()) {
return_value = BuildIteratorResult(return_value, true);
- } else if (is_async_function()) {
- return_value = BuildResolvePromise(return_value, return_value->position());
}
return return_value;
}
@@ -1754,67 +1746,27 @@ Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
}
}
-void Parser::ParseAndRewriteGeneratorFunctionBody(int pos, FunctionKind kind,
- ZoneList<Statement*>* body,
- bool* ok) {
- // We produce:
- //
- // try { InitialYield; ...body...; return {value: undefined, done: true} }
- // finally { %_GeneratorClose(generator) }
- //
- // - InitialYield yields the actual generator object.
- // - Any return statement inside the body will have its argument wrapped
- // in a "done" iterator result object.
- // - If the generator terminates for whatever reason, we must close it.
- // Hence the finally clause.
-
- Block* try_block = factory()->NewBlock(nullptr, 3, false, kNoSourcePosition);
- Expression* initial_yield = BuildInitialYield(pos, kind);
- try_block->statements()->Add(
- factory()->NewExpressionStatement(initial_yield, kNoSourcePosition),
- zone());
- ParseStatementList(try_block->statements(), Token::RBRACE, ok);
- if (!*ok) return;
-
- Statement* final_return = factory()->NewReturnStatement(
- BuildIteratorResult(nullptr, true), kNoSourcePosition);
- try_block->statements()->Add(final_return, zone());
-
- Block* finally_block =
- factory()->NewBlock(nullptr, 1, false, kNoSourcePosition);
- ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
- VariableProxy* call_proxy =
- factory()->NewVariableProxy(function_state_->generator_object_variable());
- args->Add(call_proxy, zone());
- Expression* call = factory()->NewCallRuntime(Runtime::kInlineGeneratorClose,
- args, kNoSourcePosition);
- finally_block->statements()->Add(
- factory()->NewExpressionStatement(call, kNoSourcePosition), zone());
-
- body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
- kNoSourcePosition),
- zone());
-}
-
-void Parser::CreateFunctionNameAssignment(
+void Parser::CreateFunctionNameVariable(
const AstRawString* function_name, int pos,
FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope, ZoneList<Statement*>* result, int index) {
+ DeclarationScope* function_scope) {
if (function_type == FunctionLiteral::kNamedExpression) {
- StatementT statement = factory()->NewEmptyStatement(kNoSourcePosition);
if (function_scope->LookupLocal(function_name) == nullptr) {
// Now that we know the language mode, we can create the const assignment
// in the previously reserved spot.
DCHECK_EQ(function_scope, scope());
Variable* fvar = function_scope->DeclareFunctionVar(function_name);
- VariableProxy* fproxy = factory()->NewVariableProxy(fvar);
- statement = factory()->NewExpressionStatement(
- factory()->NewAssignment(Token::INIT, fproxy,
- factory()->NewThisFunction(pos),
- kNoSourcePosition),
- kNoSourcePosition);
+ DCHECK_NOT_NULL(fvar);
+
+ // Ensure the variable is allocated if any inner scope _may_ use it.
+ // Otherwise, lazily parsed
+ if (function_scope->calls_eval() ||
+ function_scope->inner_scope_calls_eval() ||
+ function_scope->HasLazilyParsedInnerFunctionScope()) {
+ fvar->set_is_used();
+ return;
+ }
}
- result->Set(index, statement);
}
}
@@ -2463,21 +2415,6 @@ void Parser::DeclareArrowFunctionFormalParameters(
DCHECK_EQ(parameters->is_simple, parameters->scope->has_simple_parameters());
}
-void Parser::PrepareGeneratorVariables() {
- // For generators, allocating variables in contexts is currently a win because
- // it minimizes the work needed to suspend and resume an activation. The
- // code produced for generators relies on this forced context allocation (it
- // does not restore the frame's parameters upon resume).
- function_state_->scope()->ForceContextAllocation();
-
- // Calling a generator returns a generator object. That object is stored
- // in a temporary variable, a definition that is used by "yield"
- // expressions.
- Variable* temp =
- NewTemporary(ast_value_factory()->dot_generator_object_string());
- function_state_->set_generator_object_variable(temp);
-}
-
FunctionLiteral* Parser::ParseFunctionLiteral(
const AstRawString* function_name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
@@ -2592,6 +2529,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
use_temp_zone && FLAG_lazy_inner_functions && !is_lazy_top_level_function;
ZoneList<Statement*>* body = nullptr;
+ Block* parameter_init_block = nullptr;
int materialized_literal_count = -1;
int expected_property_count = -1;
bool should_be_used_once_hint = false;
@@ -2663,7 +2601,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
if (!is_lazy_top_level_function && !is_lazy_inner_function) {
body = ParseFunction(
function_name, pos, kind, function_type, scope, &num_parameters,
- &function_length, &has_duplicate_parameters,
+ &parameter_init_block, &function_length, &has_duplicate_parameters,
&materialized_literal_count, &expected_property_count, CHECK_OK);
}
@@ -2725,6 +2663,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
duplicate_parameters, function_type, eager_compile_hint, pos, true,
function_literal_id);
function_literal->set_function_token_position(function_token_pos);
+ function_literal->set_parameter_init_block(parameter_init_block);
if (should_be_used_once_hint)
function_literal->set_should_be_used_once_hint();
@@ -2972,145 +2911,11 @@ Block* Parser::BuildParameterInitializationBlock(
return init_block;
}
-Block* Parser::BuildRejectPromiseOnException(Block* inner_block) {
- // .promise = %AsyncFunctionPromiseCreate();
- // try {
- // <inner_block>
- // } catch (.catch) {
- // %RejectPromise(.promise, .catch);
- // return .promise;
- // } finally {
- // %AsyncFunctionPromiseRelease(.promise);
- // }
- Block* result = factory()->NewBlock(nullptr, 2, true, kNoSourcePosition);
-
- // .promise = %AsyncFunctionPromiseCreate();
- Statement* set_promise;
- {
- Expression* create_promise = factory()->NewCallRuntime(
- Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX,
- new (zone()) ZoneList<Expression*>(0, zone()), kNoSourcePosition);
- Assignment* assign_promise = factory()->NewAssignment(
- Token::INIT, factory()->NewVariableProxy(PromiseVariable()),
- create_promise, kNoSourcePosition);
- set_promise =
- factory()->NewExpressionStatement(assign_promise, kNoSourcePosition);
- }
- result->statements()->Add(set_promise, zone());
-
- // catch (.catch) { return %RejectPromise(.promise, .catch), .promise }
- Scope* catch_scope = NewScope(CATCH_SCOPE);
- catch_scope->set_is_hidden();
- Variable* catch_variable =
- catch_scope->DeclareLocal(ast_value_factory()->dot_catch_string(), VAR);
- Block* catch_block = factory()->NewBlock(nullptr, 1, true, kNoSourcePosition);
-
- Expression* promise_reject = BuildRejectPromise(
- factory()->NewVariableProxy(catch_variable), kNoSourcePosition);
- ReturnStatement* return_promise_reject =
- factory()->NewReturnStatement(promise_reject, kNoSourcePosition);
- catch_block->statements()->Add(return_promise_reject, zone());
-
- TryStatement* try_catch_statement =
- factory()->NewTryCatchStatementForAsyncAwait(inner_block, catch_scope,
- catch_variable, catch_block,
- kNoSourcePosition);
-
- // There is no TryCatchFinally node, so wrap it in an outer try/finally
- Block* outer_try_block =
- factory()->NewBlock(nullptr, 1, true, kNoSourcePosition);
- outer_try_block->statements()->Add(try_catch_statement, zone());
-
- // finally { %AsyncFunctionPromiseRelease(.promise) }
- Block* finally_block =
- factory()->NewBlock(nullptr, 1, true, kNoSourcePosition);
- {
- ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
- args->Add(factory()->NewVariableProxy(PromiseVariable()), zone());
- Expression* call_promise_release = factory()->NewCallRuntime(
- Context::ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, args, kNoSourcePosition);
- Statement* promise_release = factory()->NewExpressionStatement(
- call_promise_release, kNoSourcePosition);
- finally_block->statements()->Add(promise_release, zone());
- }
-
- Statement* try_finally_statement = factory()->NewTryFinallyStatement(
- outer_try_block, finally_block, kNoSourcePosition);
-
- result->statements()->Add(try_finally_statement, zone());
- return result;
-}
-
-Assignment* Parser::BuildCreateJSGeneratorObject(int pos, FunctionKind kind) {
- // .generator = %CreateJSGeneratorObject(...);
- DCHECK_NOT_NULL(function_state_->generator_object_variable());
- ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone());
- args->Add(factory()->NewThisFunction(pos), zone());
- args->Add(IsArrowFunction(kind) ? GetLiteralUndefined(pos)
- : ThisExpression(kNoSourcePosition),
- zone());
- Expression* allocation =
- factory()->NewCallRuntime(Runtime::kCreateJSGeneratorObject, args, pos);
- VariableProxy* proxy =
- factory()->NewVariableProxy(function_state_->generator_object_variable());
- return factory()->NewAssignment(Token::INIT, proxy, allocation,
- kNoSourcePosition);
-}
-
-Expression* Parser::BuildResolvePromise(Expression* value, int pos) {
- // %ResolvePromise(.promise, value), .promise
- ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone());
- args->Add(factory()->NewVariableProxy(PromiseVariable()), zone());
- args->Add(value, zone());
- Expression* call_runtime =
- factory()->NewCallRuntime(Context::PROMISE_RESOLVE_INDEX, args, pos);
- return factory()->NewBinaryOperation(
- Token::COMMA, call_runtime,
- factory()->NewVariableProxy(PromiseVariable()), pos);
-}
-
-Expression* Parser::BuildRejectPromise(Expression* value, int pos) {
- // %promise_internal_reject(.promise, value, false), .promise
- // Disables the additional debug event for the rejection since a debug event
- // already happened for the exception that got us here.
- ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(3, zone());
- args->Add(factory()->NewVariableProxy(PromiseVariable()), zone());
- args->Add(value, zone());
- args->Add(factory()->NewBooleanLiteral(false, pos), zone());
- Expression* call_runtime = factory()->NewCallRuntime(
- Context::PROMISE_INTERNAL_REJECT_INDEX, args, pos);
- return factory()->NewBinaryOperation(
- Token::COMMA, call_runtime,
- factory()->NewVariableProxy(PromiseVariable()), pos);
-}
-
-Variable* Parser::PromiseVariable() {
- // Based on the various compilation paths, there are many different code
- // paths which may be the first to access the Promise temporary. Whichever
- // comes first should create it and stash it in the FunctionState.
- Variable* promise = function_state_->promise_variable();
- if (function_state_->promise_variable() == nullptr) {
- promise = scope()->NewTemporary(ast_value_factory()->empty_string());
- function_state_->set_promise_variable(promise);
- }
- return promise;
-}
-
-Expression* Parser::BuildInitialYield(int pos, FunctionKind kind) {
- Assignment* assignment = BuildCreateJSGeneratorObject(pos, kind);
- VariableProxy* generator =
- factory()->NewVariableProxy(function_state_->generator_object_variable());
- // The position of the yield is important for reporting the exception
- // caused by calling the .throw method on a generator suspended at the
- // initial yield (i.e. right after generator instantiation).
- return factory()->NewYield(generator, assignment, scope()->start_position(),
- Yield::kOnExceptionThrow);
-}
-
ZoneList<Statement*>* Parser::ParseFunction(
const AstRawString* function_name, int pos, FunctionKind kind,
FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope, int* num_parameters, int* function_length,
+ DeclarationScope* function_scope, int* num_parameters,
+ Block** parameter_init_block, int* function_length,
bool* has_duplicate_parameters, int* materialized_literal_count,
int* expected_property_count, bool* ok) {
ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY);
@@ -3120,7 +2925,7 @@ ZoneList<Statement*>* Parser::ParseFunction(
DuplicateFinder duplicate_finder;
ExpressionClassifier formals_classifier(this, &duplicate_finder);
- if (IsResumableFunction(kind)) PrepareGeneratorVariables();
+ if (IsResumableFunction(kind)) function_scope->ForceContextAllocation();
ParserFormalParameters formals(function_scope);
ParseFormalParameterList(&formals, CHECK_OK);
@@ -3135,7 +2940,8 @@ ZoneList<Statement*>* Parser::ParseFunction(
Expect(Token::LBRACE, CHECK_OK);
ZoneList<Statement*>* body = new (zone()) ZoneList<Statement*>(8, zone());
- ParseFunctionBody(body, function_name, pos, formals, kind, function_type, ok);
+ ParseFunctionBody(body, parameter_init_block, function_name, pos, formals,
+ kind, function_type, ok);
// Validate parameter names. We can do this only after parsing the function,
// since the function can declare itself strict.
@@ -3756,103 +3562,6 @@ Expression* Parser::ExpressionListToExpression(ZoneList<Expression*>* args) {
return expr;
}
-// This method intoduces the line initializing the generator object
-// when desugaring the body of async_function.
-void Parser::PrepareAsyncFunctionBody(ZoneList<Statement*>* body,
- FunctionKind kind, int pos) {
- // When parsing an async arrow function, we get here without having called
- // PrepareGeneratorVariables yet, so do it now.
- if (function_state_->generator_object_variable() == nullptr) {
- PrepareGeneratorVariables();
- }
- body->Add(factory()->NewExpressionStatement(
- BuildCreateJSGeneratorObject(pos, kind), kNoSourcePosition),
- zone());
-}
-
-// This method completes the desugaring of the body of async_function.
-void Parser::RewriteAsyncFunctionBody(ZoneList<Statement*>* body, Block* block,
- Expression* return_value, bool* ok) {
- // function async_function() {
- // .generator_object = %CreateJSGeneratorObject();
- // BuildRejectPromiseOnException({
- // ... block ...
- // return %ResolvePromise(.promise, expr), .promise;
- // })
- // }
-
- return_value = BuildResolvePromise(return_value, return_value->position());
- block->statements()->Add(
- factory()->NewReturnStatement(return_value, return_value->position()),
- zone());
- block = BuildRejectPromiseOnException(block);
- body->Add(block, zone());
-}
-
-Expression* Parser::RewriteAwaitExpression(Expression* value, int await_pos) {
- // yield do {
- // tmp = <operand>;
- // %AsyncFunctionAwait(.generator_object, tmp, .promise);
- // .promise
- // }
- // The value of the expression is returned to the caller of the async
- // function for the first yield statement; for this, .promise is the
- // appropriate return value, being a Promise that will be fulfilled or
- // rejected with the appropriate value by the desugaring. Subsequent yield
- // occurrences will return to the AsyncFunctionNext call within the
- // implemementation of the intermediate throwaway Promise's then handler.
- // This handler has nothing useful to do with the value, as the Promise is
- // ignored. If we yielded the value of the throwawayPromise that
- // AsyncFunctionAwait creates as an intermediate, it would create a memory
- // leak; we must return .promise instead;
- // The operand needs to be evaluated on a separate statement in order to get
- // a break location, and the .promise needs to be read earlier so that it
- // doesn't insert a false location.
- // TODO(littledan): investigate why this ordering is needed in more detail.
- Variable* generator_object_variable =
- function_state_->generator_object_variable();
- DCHECK_NOT_NULL(generator_object_variable);
-
- const int nopos = kNoSourcePosition;
-
- Block* do_block = factory()->NewBlock(nullptr, 2, false, nopos);
-
- Variable* promise = PromiseVariable();
-
- // Wrap value evaluation to provide a break location.
- Variable* temp_var = NewTemporary(ast_value_factory()->empty_string());
- Expression* value_assignment = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(temp_var), value, nopos);
- do_block->statements()->Add(
- factory()->NewExpressionStatement(value_assignment, value->position()),
- zone());
-
- ZoneList<Expression*>* async_function_await_args =
- new (zone()) ZoneList<Expression*>(3, zone());
- Expression* generator_object =
- factory()->NewVariableProxy(generator_object_variable);
- async_function_await_args->Add(generator_object, zone());
- async_function_await_args->Add(factory()->NewVariableProxy(temp_var), zone());
- async_function_await_args->Add(factory()->NewVariableProxy(promise), zone());
-
- // The parser emits calls to AsyncFunctionAwaitCaught, but the
- // AstNumberingVisitor will rewrite this to AsyncFunctionAwaitUncaught
- // if there is no local enclosing try/catch block.
- Expression* async_function_await =
- factory()->NewCallRuntime(Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX,
- async_function_await_args, nopos);
- do_block->statements()->Add(
- factory()->NewExpressionStatement(async_function_await, await_pos),
- zone());
-
- // Wrap await to provide a break location between value evaluation and yield.
- Expression* do_expr = factory()->NewDoExpression(do_block, promise, nopos);
-
- generator_object = factory()->NewVariableProxy(generator_object_variable);
- return factory()->NewYield(generator_object, do_expr, nopos,
- Yield::kOnExceptionRethrow);
-}
-
class NonPatternRewriter : public AstExpressionRewriter {
public:
NonPatternRewriter(uintptr_t stack_limit, Parser* parser)
@@ -4205,8 +3914,7 @@ void Parser::SetFunctionName(Expression* value, const AstRawString* name) {
// output = %_Call(iteratorReturn, iterator, input);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
-Expression* Parser::RewriteYieldStar(Expression* generator,
- Expression* iterable, int pos) {
+Expression* Parser::RewriteYieldStar(Expression* iterable, int pos) {
const int nopos = kNoSourcePosition;
// Forward definition for break/continue statements.
@@ -4405,8 +4113,8 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
Statement* yield_output;
{
Expression* output_proxy = factory()->NewVariableProxy(var_output);
- Yield* yield = factory()->NewYield(generator, output_proxy, nopos,
- Yield::kOnExceptionThrow);
+ Yield* yield = factory()->NewYield(
+ output_proxy, nopos, Yield::kOnExceptionThrow, Yield::kNormal);
yield_output = factory()->NewExpressionStatement(yield, nopos);
}
« no previous file with comments | « src/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698