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, |
+ ¶meter_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); |
} |