Commit f4f19408 authored by adamk's avatar adamk Committed by Commit bot

Eagerly declare variables in ParseVariableDeclarations where possible

This avoids spending lots of time in Scope::RemoveUnresolved for very long
variable declaration lists.

BUG=v8:4699
LOG=n

Review URL: https://codereview.chromium.org/1655313003

Cr-Commit-Position: refs/heads/master@{#34047}
parent 3ec14170
...@@ -2332,17 +2332,16 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, ...@@ -2332,17 +2332,16 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
// is inside an initializer block, it is ignored. // is inside an initializer block, it is ignored.
DeclarationParsingResult parsing_result; DeclarationParsingResult parsing_result;
ParseVariableDeclarations(var_context, &parsing_result, CHECK_OK); Block* result =
ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK);
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
Block* result = parsing_result.BuildInitializationBlock(names, CHECK_OK);
return result; return result;
} }
Block* Parser::ParseVariableDeclarations(
void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, VariableDeclarationContext var_context,
DeclarationParsingResult* parsing_result, DeclarationParsingResult* parsing_result,
bool* ok) { ZoneList<const AstRawString*>* names, bool* ok) {
// VariableDeclarations :: // VariableDeclarations ::
// ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
// //
...@@ -2362,12 +2361,19 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, ...@@ -2362,12 +2361,19 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
parsing_result->descriptor.declaration_pos = peek_position(); parsing_result->descriptor.declaration_pos = peek_position();
parsing_result->descriptor.initialization_pos = peek_position(); parsing_result->descriptor.initialization_pos = peek_position();
parsing_result->descriptor.mode = VAR; parsing_result->descriptor.mode = VAR;
Block* init_block = nullptr;
if (var_context != kForStatement) {
init_block = factory()->NewBlock(
NULL, 1, true, parsing_result->descriptor.declaration_pos);
}
if (peek() == Token::VAR) { if (peek() == Token::VAR) {
if (is_strong(language_mode())) { if (is_strong(language_mode())) {
Scanner::Location location = scanner()->peek_location(); Scanner::Location location = scanner()->peek_location();
ReportMessageAt(location, MessageTemplate::kStrongVar); ReportMessageAt(location, MessageTemplate::kStrongVar);
*ok = false; *ok = false;
return; return nullptr;
} }
Consume(Token::VAR); Consume(Token::VAR);
} else if (peek() == Token::CONST && allow_const()) { } else if (peek() == Token::CONST && allow_const()) {
...@@ -2405,18 +2411,15 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, ...@@ -2405,18 +2411,15 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
{ {
ExpressionClassifier pattern_classifier; ExpressionClassifier pattern_classifier;
Token::Value next = peek(); Token::Value next = peek();
pattern = ParsePrimaryExpression(&pattern_classifier, ok); pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
if (!*ok) return; ValidateBindingPattern(&pattern_classifier, CHECK_OK);
ValidateBindingPattern(&pattern_classifier, ok);
if (!*ok) return;
if (IsLexicalVariableMode(parsing_result->descriptor.mode)) { if (IsLexicalVariableMode(parsing_result->descriptor.mode)) {
ValidateLetPattern(&pattern_classifier, ok); ValidateLetPattern(&pattern_classifier, CHECK_OK);
if (!*ok) return;
} }
if (!allow_harmony_destructuring_bind() && !pattern->IsVariableProxy()) { if (!allow_harmony_destructuring_bind() && !pattern->IsVariableProxy()) {
ReportUnexpectedToken(next); ReportUnexpectedToken(next);
*ok = false; *ok = false;
return; return nullptr;
} }
} }
...@@ -2433,10 +2436,8 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, ...@@ -2433,10 +2436,8 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
if (Check(Token::ASSIGN)) { if (Check(Token::ASSIGN)) {
ExpressionClassifier classifier; ExpressionClassifier classifier;
value = ParseAssignmentExpression(var_context != kForStatement, value = ParseAssignmentExpression(var_context != kForStatement,
&classifier, ok); &classifier, CHECK_OK);
if (!*ok) return; value = ParserTraits::RewriteNonPattern(value, &classifier, CHECK_OK);
value = ParserTraits::RewriteNonPattern(value, &classifier, ok);
if (!*ok) return;
variable_loc.end_pos = scanner()->location().end_pos; variable_loc.end_pos = scanner()->location().end_pos;
if (!parsing_result->first_initializer_loc.IsValid()) { if (!parsing_result->first_initializer_loc.IsValid()) {
...@@ -2471,7 +2472,7 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, ...@@ -2471,7 +2472,7 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
MessageTemplate::kDeclarationMissingInitializer, MessageTemplate::kDeclarationMissingInitializer,
!pattern->IsVariableProxy() ? "destructuring" : "const"); !pattern->IsVariableProxy() ? "destructuring" : "const");
*ok = false; *ok = false;
return; return nullptr;
} }
// 'let x' and (legacy) 'const x' initialize 'x' to undefined. // 'let x' and (legacy) 'const x' initialize 'x' to undefined.
...@@ -2485,13 +2486,28 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, ...@@ -2485,13 +2486,28 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
initializer_position = position(); initializer_position = position();
} }
parsing_result->declarations.Add(DeclarationParsingResult::Declaration( DeclarationParsingResult::Declaration decl(pattern, initializer_position,
pattern, initializer_position, value)); value);
if (var_context == kForStatement) {
// Save the declaration for further handling in ParseForStatement.
parsing_result->declarations.Add(decl);
} else {
// Immediately declare the variable otherwise. This avoids O(N^2)
// behavior (where N is the number of variables in a single
// declaration) in the PatternRewriter having to do with removing
// and adding VariableProxies to the Scope (see bug 4699).
DCHECK_NOT_NULL(init_block);
PatternRewriter::DeclareAndInitializeVariables(
init_block, &parsing_result->descriptor, &decl, names, CHECK_OK);
}
first_declaration = false; first_declaration = false;
} while (peek() == Token::COMMA); } while (peek() == Token::COMMA);
parsing_result->bindings_loc = parsing_result->bindings_loc =
Scanner::Location(bindings_start, scanner()->location().end_pos); Scanner::Location(bindings_start, scanner()->location().end_pos);
DCHECK(*ok);
return init_block;
} }
...@@ -3632,7 +3648,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3632,7 +3648,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
if (peek() != Token::SEMICOLON) { if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) || if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
(peek() == Token::LET && IsNextLetKeyword())) { (peek() == Token::LET && IsNextLetKeyword())) {
ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK); ParseVariableDeclarations(kForStatement, &parsing_result, nullptr,
CHECK_OK);
ForEachStatement::VisitMode mode; ForEachStatement::VisitMode mode;
int each_beg_pos = scanner()->location().beg_pos; int each_beg_pos = scanner()->location().beg_pos;
......
...@@ -878,10 +878,10 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -878,10 +878,10 @@ class Parser : public ParserBase<ParserTraits> {
bool* ok_; bool* ok_;
}; };
Block* ParseVariableDeclarations(VariableDeclarationContext var_context,
void ParseVariableDeclarations(VariableDeclarationContext var_context, DeclarationParsingResult* parsing_result,
DeclarationParsingResult* parsing_result, ZoneList<const AstRawString*>* names,
bool* ok); bool* ok);
Statement* ParseExpressionOrLabelledStatement( Statement* ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* labels, bool* ok); ZoneList<const AstRawString*>* labels, bool* ok);
IfStatement* ParseIfStatement(ZoneList<const AstRawString*>* labels, IfStatement* ParseIfStatement(ZoneList<const AstRawString*>* labels,
......
*%(basename)s:10: SyntaxError: Identifier 'x' has already been declared *%(basename)s:10: SyntaxError: Identifier 'x' has already been declared
let x; let x;
^ ^
SyntaxError: Identifier 'x' has already been declared SyntaxError: Identifier 'x' has already been declared
*%(basename)s:9: SyntaxError: Identifier 'x' has already been declared *%(basename)s:9: SyntaxError: Identifier 'x' has already been declared
var x; var x;
^ ^
SyntaxError: Identifier 'x' has already been declared SyntaxError: Identifier 'x' has already been declared
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