[parser] Only create scopes for for-loops containing lexical declarations

This patch removes unnecessary scope creation for C-style, for-in, and
for-of loops containing var declarations. Only loops with LET or CONST
declarations require additional scoping up-front.

After this patch lands, I intend to apply this simplification (as well
as that from fa15ba5a7b) to for-await loops.

Bug: v8:6724
Change-Id: I9962432d1e059d8eefb577e7b512bc2321a03140
Reviewed-on: https://chromium-review.googlesource.com/619987
Reviewed-by: Marja Hölttä <marja@chromium.org>
Commit-Queue: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47436}
This commit is contained in:
Adam Klein 2017-08-17 17:16:17 -07:00 committed by Commit Bot
parent cec289ea57
commit 38b1807a3f

View File

@ -1234,10 +1234,10 @@ class ParserBase {
ExpressionT* cond, StatementT* next, ExpressionT* cond, StatementT* next,
StatementT* body, bool* ok); StatementT* body, bool* ok);
// Same as the above, but handles those cases where <init> is a // Same as the above, but handles those cases where <init> is a
// variable declaration. // lexical variable declaration.
StatementT ParseStandardForLoopWithDeclarations( StatementT ParseStandardForLoopWithLexicalDeclarations(
int stmt_pos, StatementT init, bool bound_names_are_lexical, int stmt_pos, StatementT init, ForInfo* for_info,
ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok); ZoneList<const AstRawString*>* labels, bool* ok);
StatementT ParseForAwaitStatement(ZoneList<const AstRawString*>* labels, StatementT ParseForAwaitStatement(ZoneList<const AstRawString*>* labels,
bool* ok); bool* ok);
@ -5541,22 +5541,24 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
ZoneList<const AstRawString*>* labels, bool* ok) { ZoneList<const AstRawString*>* labels, bool* ok) {
typename FunctionState::FunctionOrEvalRecordingScope recording_scope(
function_state_);
int stmt_pos = peek_position(); int stmt_pos = peek_position();
ForInfo for_info(this); ForInfo for_info(this);
bool bound_names_are_lexical = false;
Expect(Token::FOR, CHECK_OK); Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
if (peek() == Token::VAR || peek() == Token::CONST || if (peek() == Token::CONST || (peek() == Token::LET && IsNextLetKeyword())) {
(peek() == Token::LET && IsNextLetKeyword())) { // The initializer contains lexical declarations,
// The initializer contains declarations. // so create an in-between scope.
// Create an in-between scope for let-bound iteration variables.
BlockState for_state(zone(), &scope_); BlockState for_state(zone(), &scope_);
scope()->set_start_position(scanner()->location().beg_pos); scope()->set_start_position(scanner()->location().beg_pos);
// Also record whether inner functions or evals are found inside
// this loop, as this information is used to simplify the desugaring
// if none are found.
typename FunctionState::FunctionOrEvalRecordingScope recording_scope(
function_state_);
// Create an inner block scope which will be the parent scope of scopes // Create an inner block scope which will be the parent scope of scopes
// possibly created by ParseVariableDeclarations. // possibly created by ParseVariableDeclarations.
Scope* inner_block_scope = NewScope(BLOCK_SCOPE); Scope* inner_block_scope = NewScope(BLOCK_SCOPE);
@ -5565,33 +5567,43 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
ParseVariableDeclarations(kForStatement, &for_info.parsing_result, ParseVariableDeclarations(kForStatement, &for_info.parsing_result,
nullptr, CHECK_OK); nullptr, CHECK_OK);
} }
bound_names_are_lexical = DCHECK(IsLexicalVariableMode(for_info.parsing_result.descriptor.mode));
IsLexicalVariableMode(for_info.parsing_result.descriptor.mode);
for_info.position = scanner()->location().beg_pos; for_info.position = scanner()->location().beg_pos;
if (CheckInOrOf(&for_info.mode)) { if (CheckInOrOf(&for_info.mode)) {
scope()->set_is_hidden();
return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels, return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels,
inner_block_scope, ok); inner_block_scope, ok);
} }
Expect(Token::SEMICOLON, CHECK_OK); Expect(Token::SEMICOLON, CHECK_OK);
// One or more declaration not followed by in/of.
StatementT init = impl()->BuildInitializationBlock( StatementT init = impl()->BuildInitializationBlock(
&for_info.parsing_result, &for_info.parsing_result, &for_info.bound_names, CHECK_OK);
bound_names_are_lexical ? &for_info.bound_names : nullptr, CHECK_OK);
Scope* finalized = inner_block_scope->FinalizeBlockScope(); Scope* finalized = inner_block_scope->FinalizeBlockScope();
// No variable declarations will have been created in inner_block_scope. // No variable declarations will have been created in inner_block_scope.
DCHECK_NULL(finalized); DCHECK_NULL(finalized);
USE(finalized); USE(finalized);
// Standard 'for' loop, we have parsed the initializer at this point. return ParseStandardForLoopWithLexicalDeclarations(stmt_pos, init,
return ParseStandardForLoopWithDeclarations( &for_info, labels, ok);
stmt_pos, init, bound_names_are_lexical, &for_info, labels, ok);
} }
StatementT init = impl()->NullStatement(); StatementT init = impl()->NullStatement();
if (peek() != Token::SEMICOLON) { if (peek() == Token::VAR) {
ParseVariableDeclarations(kForStatement, &for_info.parsing_result, nullptr,
CHECK_OK);
DCHECK_EQ(for_info.parsing_result.descriptor.mode, VAR);
for_info.position = scanner()->location().beg_pos;
if (CheckInOrOf(&for_info.mode)) {
return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels,
nullptr, ok);
}
init = impl()->BuildInitializationBlock(&for_info.parsing_result, nullptr,
CHECK_OK);
} else if (peek() != Token::SEMICOLON) {
// The initializer does not contain declarations. // The initializer does not contain declarations.
int lhs_beg_pos = peek_position(); int lhs_beg_pos = peek_position();
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
@ -5634,7 +5646,6 @@ typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseForEachStatementWithDeclarations( ParserBase<Impl>::ParseForEachStatementWithDeclarations(
int stmt_pos, ForInfo* for_info, ZoneList<const AstRawString*>* labels, int stmt_pos, ForInfo* for_info, ZoneList<const AstRawString*>* labels,
Scope* inner_block_scope, bool* ok) { Scope* inner_block_scope, bool* ok) {
scope()->set_is_hidden();
// Just one declaration followed by in/of. // Just one declaration followed by in/of.
if (for_info->parsing_result.declarations.length() != 1) { if (for_info->parsing_result.declarations.length() != 1) {
impl()->ReportMessageAt(for_info->parsing_result.bindings_loc, impl()->ReportMessageAt(for_info->parsing_result.bindings_loc,
@ -5672,11 +5683,18 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
Scope* for_scope = nullptr;
if (inner_block_scope != nullptr) {
for_scope = inner_block_scope->outer_scope();
DCHECK(for_scope == scope());
inner_block_scope->set_start_position(scanner()->location().beg_pos);
}
ExpressionT each_variable = impl()->NullExpression(); ExpressionT each_variable = impl()->NullExpression();
BlockT body_block = impl()->NullStatement(); BlockT body_block = impl()->NullStatement();
{ {
BlockState block_state(&scope_, inner_block_scope); BlockState block_state(
scope()->set_start_position(scanner()->location().beg_pos); &scope_, inner_block_scope != nullptr ? inner_block_scope : scope_);
SourceRange body_range; SourceRange body_range;
SourceRangeScope range_scope(scanner(), &body_range); SourceRangeScope range_scope(scanner(), &body_range);
@ -5688,8 +5706,10 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
&each_variable, CHECK_OK); &each_variable, CHECK_OK);
body_block->statements()->Add(body, zone()); body_block->statements()->Add(body, zone());
scope()->set_end_position(scanner()->location().end_pos); if (inner_block_scope != nullptr) {
body_block->set_scope(scope()->FinalizeBlockScope()); inner_block_scope->set_end_position(scanner()->location().end_pos);
body_block->set_scope(inner_block_scope->FinalizeBlockScope());
}
} }
StatementT final_loop = impl()->InitializeForEachStatement( StatementT final_loop = impl()->InitializeForEachStatement(
@ -5697,8 +5717,11 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info, ok); init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info, ok);
scope()->set_end_position(scanner()->location().end_pos); if (for_scope != nullptr) {
Scope* for_scope = scope()->FinalizeBlockScope(); for_scope->set_end_position(scanner()->location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
}
// Parsed for-in loop w/ variable declarations. // Parsed for-in loop w/ variable declarations.
if (!impl()->IsNull(init_block)) { if (!impl()->IsNull(init_block)) {
init_block->statements()->Add(final_loop, zone()); init_block->statements()->Add(final_loop, zone());
@ -5749,38 +5772,34 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::StatementT typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseStandardForLoopWithDeclarations( ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations(
int stmt_pos, StatementT init, bool bound_names_are_lexical, int stmt_pos, StatementT init, ForInfo* for_info,
ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok) { ZoneList<const AstRawString*>* labels, bool* ok) {
// If there are let bindings, then condition and the next statement of the // The condition and the next statement of the for loop must be parsed
// for loop must be parsed in a new scope. // in a new scope.
Scope* inner_scope = scope(); Scope* inner_scope = NewScope(BLOCK_SCOPE);
if (bound_names_are_lexical && for_info->bound_names.length() > 0) {
inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE);
inner_scope->set_start_position(scanner()->location().beg_pos);
}
ForStatementT loop = impl()->NullStatement(); ForStatementT loop = impl()->NullStatement();
ExpressionT cond = impl()->NullExpression(); ExpressionT cond = impl()->NullExpression();
StatementT next = impl()->NullStatement(); StatementT next = impl()->NullStatement();
StatementT body = impl()->NullStatement(); StatementT body = impl()->NullStatement();
{ {
BlockState block_state(&scope_, inner_scope); BlockState block_state(&scope_, inner_scope);
scope()->set_start_position(scanner()->location().beg_pos);
loop = loop =
ParseStandardForLoop(stmt_pos, labels, &cond, &next, &body, CHECK_OK); ParseStandardForLoop(stmt_pos, labels, &cond, &next, &body, CHECK_OK);
scope()->set_end_position(scanner()->location().end_pos);
} }
scope()->set_end_position(scanner()->location().end_pos); scope()->set_end_position(scanner()->location().end_pos);
inner_scope->set_end_position(scanner()->location().end_pos); if (for_info->bound_names.length() > 0 &&
if (bound_names_are_lexical && for_info->bound_names.length() > 0) { function_state_->contains_function_or_eval()) {
if (function_state_->contains_function_or_eval()) { scope()->set_is_hidden();
scope()->set_is_hidden(); return impl()->DesugarLexicalBindingsInForStatement(
return impl()->DesugarLexicalBindingsInForStatement( loop, init, cond, next, body, inner_scope, *for_info, ok);
loop, init, cond, next, body, inner_scope, *for_info, CHECK_OK); } else {
} else { inner_scope = inner_scope->FinalizeBlockScope();
inner_scope = inner_scope->FinalizeBlockScope(); DCHECK_NULL(inner_scope);
CHECK_NULL(inner_scope); USE(inner_scope);
}
} }
Scope* for_scope = scope()->FinalizeBlockScope(); Scope* for_scope = scope()->FinalizeBlockScope();