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

Unified Diff: src/parsing/parser.cc

Issue 2119353002: [parser] Fix bug in for-of desugaring. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase. Created 4 years, 5 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') | test/cctest/interpreter/bytecode_expectations/ForOf.golden » ('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 ce3deb5f93ab46263c6f4c1d5131916696f7c6ac..84e835f6be37f081daee8a6b5d5bf7e58621002c 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -3186,12 +3186,16 @@ Expression* Parser::BuildIteratorNextResult(Expression* iterator,
throw_call, pos);
}
-void Parser::InitializeForEachStatement(ForEachStatement* stmt,
- Expression* each, Expression* subject,
- Statement* body, int each_keyword_pos) {
+Statement* Parser::InitializeForEachStatement(ForEachStatement* stmt,
+ Expression* each,
+ Expression* subject,
+ Statement* body,
+ int each_keyword_pos) {
ForOfStatement* for_of = stmt->AsForOfStatement();
if (for_of != NULL) {
- InitializeForOfStatement(for_of, each, subject, body, each_keyword_pos);
+ const bool finalize = true;
+ return InitializeForOfStatement(for_of, each, subject, body, finalize,
+ each_keyword_pos);
} else {
if (each->IsArrayLiteral() || each->IsObjectLiteral()) {
Variable* temp =
@@ -3211,38 +3215,49 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
}
stmt->AsForInStatement()->Initialize(each, subject, body);
}
+ return stmt;
}
-void Parser::InitializeForOfStatement(ForOfStatement* for_of, Expression* each,
- Expression* iterable, Statement* body,
- int next_result_pos) {
+Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of,
+ Expression* each,
+ Expression* iterable,
+ Statement* body, bool finalize,
+ int next_result_pos) {
+ // Create the auxiliary expressions needed for iterating over the iterable,
+ // and initialize the given ForOfStatement with them.
+ // If finalize is true, also instrument the loop with code that performs the
+ // proper ES6 iterator finalization. In that case, the result is not
+ // immediately a ForOfStatement.
+
+ const int nopos = kNoSourcePosition;
+ auto avfactory = ast_value_factory();
+
Variable* iterator =
scope_->NewTemporary(ast_value_factory()->dot_iterator_string());
Variable* result =
scope_->NewTemporary(ast_value_factory()->dot_result_string());
-
- Expression* assign_iterator;
- Expression* next_result;
- Expression* result_done;
- Expression* assign_each;
-
- int get_iterator_pos = iterable->position();
+ Variable* completion = scope_->NewTemporary(avfactory->empty_string());
// iterator = iterable[Symbol.iterator]()
- assign_iterator = factory()->NewAssignment(
- Token::ASSIGN, factory()->NewVariableProxy(iterator),
- GetIterator(iterable, factory(), get_iterator_pos), iterable->position());
+ Expression* assign_iterator;
+ {
+ assign_iterator = factory()->NewAssignment(
+ Token::ASSIGN, factory()->NewVariableProxy(iterator),
+ GetIterator(iterable, factory(), iterable->position()),
+ iterable->position());
+ }
// !%_IsJSReceiver(result = iterator.next()) &&
// %ThrowIteratorResultNotAnObject(result)
+ Expression* next_result;
{
- // result = iterator.next()
Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
next_result =
BuildIteratorNextResult(iterator_proxy, result, next_result_pos);
}
// result.done
+ Expression* result_done;
{
Expression* done_literal = factory()->NewStringLiteral(
ast_value_factory()->done_string(), kNoSourcePosition);
@@ -3251,23 +3266,84 @@ void Parser::InitializeForOfStatement(ForOfStatement* for_of, Expression* each,
factory()->NewProperty(result_proxy, done_literal, kNoSourcePosition);
}
- // each = result.value
+ // result.value
+ Expression* result_value;
{
- Expression* value_literal = factory()->NewStringLiteral(
- ast_value_factory()->value_string(), kNoSourcePosition);
+ Expression* value_literal =
+ factory()->NewStringLiteral(avfactory->value_string(), nopos);
Expression* result_proxy = factory()->NewVariableProxy(result);
- Expression* result_value =
- factory()->NewProperty(result_proxy, value_literal, kNoSourcePosition);
- assign_each = factory()->NewAssignment(Token::ASSIGN, each, result_value,
- kNoSourcePosition);
+ result_value = factory()->NewProperty(result_proxy, value_literal, nopos);
+ }
+
+ // {{completion = kAbruptCompletion;}}
+ Statement* set_completion_abrupt;
+ if (finalize) {
+ Expression* proxy = factory()->NewVariableProxy(completion);
+ Expression* assignment = factory()->NewAssignment(
+ Token::ASSIGN, proxy,
+ factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
+
+ Block* block = factory()->NewBlock(nullptr, 1, true, nopos);
+ block->statements()->Add(
+ factory()->NewExpressionStatement(assignment, nopos), zone());
+ set_completion_abrupt = block;
+ }
+
+ // do { let tmp = #result_value; #set_completion_abrupt; tmp }
+ // Expression* result_value (gets overwritten)
+ if (finalize) {
+ Variable* var_tmp = scope_->NewTemporary(avfactory->empty_string());
+ Expression* tmp = factory()->NewVariableProxy(var_tmp);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, tmp, result_value, nopos);
+
+ Block* block = factory()->NewBlock(nullptr, 2, false, nopos);
+ block->statements()->Add(
+ factory()->NewExpressionStatement(assignment, nopos), zone());
+ block->statements()->Add(set_completion_abrupt, zone());
+
+ result_value = factory()->NewDoExpression(block, var_tmp, nopos);
+ }
+
+ // each = #result_value;
+ Expression* assign_each;
+ {
+ assign_each =
+ factory()->NewAssignment(Token::ASSIGN, each, result_value, nopos);
if (each->IsArrayLiteral() || each->IsObjectLiteral()) {
assign_each = PatternRewriter::RewriteDestructuringAssignment(
this, assign_each->AsAssignment(), scope_);
}
}
+ // {{completion = kNormalCompletion;}}
+ Statement* set_completion_normal;
+ if (finalize) {
+ Expression* proxy = factory()->NewVariableProxy(completion);
+ Expression* assignment = factory()->NewAssignment(
+ Token::ASSIGN, proxy,
+ factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
+
+ Block* block = factory()->NewBlock(nullptr, 1, true, nopos);
+ block->statements()->Add(
+ factory()->NewExpressionStatement(assignment, nopos), zone());
+ set_completion_normal = block;
+ }
+
+ // { #loop-body; #set_completion_normal }
+ // Statement* body (gets overwritten)
+ if (finalize) {
+ Block* block = factory()->NewBlock(nullptr, 2, false, nopos);
+ block->statements()->Add(body, zone());
+ block->statements()->Add(set_completion_normal, zone());
+ body = block;
+ }
+
for_of->Initialize(body, iterator, assign_iterator, next_result, result_done,
assign_each);
+ return finalize
+ ? ParserTraits::FinalizeForOfStatement(for_of, completion, nopos)
+ : for_of;
}
Statement* Parser::DesugarLexicalBindingsInForStatement(
@@ -3652,6 +3728,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Block* body_block =
factory()->NewBlock(NULL, 3, false, kNoSourcePosition);
+ Statement* final_loop;
{
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideForInOfBody);
@@ -3678,8 +3755,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
body_block->statements()->Add(body, zone());
VariableProxy* temp_proxy =
factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
- InitializeForEachStatement(loop, temp_proxy, enumerable, body_block,
- each_keyword_position);
+ final_loop = InitializeForEachStatement(
+ loop, temp_proxy, enumerable, body_block, each_keyword_position);
}
body_scope->set_end_position(scanner()->location().end_pos);
body_scope = body_scope->FinalizeBlockScope();
@@ -3706,12 +3783,6 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
}
}
- Statement* final_loop =
- loop->IsForOfStatement()
- ? FinalizeForOfStatement(loop->AsForOfStatement(),
- kNoSourcePosition)
- : loop;
-
for_scope->set_end_position(scanner()->location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
// Parsed for-in loop w/ variable declarations.
@@ -3775,14 +3846,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// For legacy compat reasons, give for loops similar treatment to
// if statements in allowing a function declaration for a body
Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
- InitializeForEachStatement(loop, expression, enumerable, body,
- each_keyword_position);
-
- Statement* final_loop =
- loop->IsForOfStatement()
- ? FinalizeForOfStatement(loop->AsForOfStatement(),
- kNoSourcePosition)
- : loop;
+ Statement* final_loop = InitializeForEachStatement(
+ loop, expression, enumerable, body, each_keyword_position);
for_scope->set_end_position(scanner()->location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
@@ -5876,9 +5941,10 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
// for (each of spread) %AppendElement($R, each)
ForEachStatement* loop = factory()->NewForEachStatement(
ForEachStatement::ITERATE, nullptr, kNoSourcePosition);
+ const bool finalize = false;
InitializeForOfStatement(loop->AsForOfStatement(),
factory()->NewVariableProxy(each), subject,
- append_body);
+ append_body, finalize);
do_block->statements()->Add(loop, zone());
}
}
@@ -6870,13 +6936,13 @@ void ParserTraits::BuildIteratorCloseForCompletion(
statements->Add(maybe_call_return, zone);
}
-
-Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) {
+Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop,
+ Variable* var_completion,
+ int pos) {
//
// This function replaces the loop with the following wrapping:
//
- // let each;
- // let completion = kNormalCompletion;
+ // completion = kNormalCompletion;
// try {
// try {
// #loop;
@@ -6890,41 +6956,14 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) {
// }
// }
//
- // where the loop's body is wrapped as follows:
- //
- // {
- // #loop-body
- // {{completion = kNormalCompletion;}}
- // }
- //
- // and the loop's assign_each is wrapped as follows
- //
- // do {
- // {{completion = kAbruptCompletion;}}
- // #assign-each
- // }
+ // Note that the loop's body and its assign_each already contain appropriate
+ // assignments to completion (see InitializeForOfStatement).
//
const int nopos = kNoSourcePosition;
auto factory = parser_->factory();
- auto avfactory = parser_->ast_value_factory();
- auto scope = parser_->scope_;
auto zone = parser_->zone();
- Variable* var_completion = scope->NewTemporary(avfactory->empty_string());
-
- // let each;
- Variable* var_each = scope->NewTemporary(avfactory->empty_string());
- Statement* initialize_each;
- {
- Expression* proxy = factory->NewVariableProxy(var_each);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, proxy,
- factory->NewUndefinedLiteral(nopos), nopos);
- initialize_each =
- factory->NewExpressionStatement(assignment, nopos);
- }
-
// !(completion === kNormalCompletion || IS_UNDEFINED(#iterator))
Expression* closing_condition;
{
@@ -6939,66 +6978,13 @@ Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) {
nopos);
}
- // {{completion = kNormalCompletion;}}
- Statement* set_completion_normal;
+ Block* final_loop = factory->NewBlock(nullptr, 2, false, nopos);
{
- Expression* proxy = factory->NewVariableProxy(var_completion);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, proxy,
- factory->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
-
- Block* block = factory->NewBlock(nullptr, 1, true, nopos);
- block->statements()->Add(
- factory->NewExpressionStatement(assignment, nopos), zone);
- set_completion_normal = block;
- }
-
- // {{completion = kAbruptCompletion;}}
- Statement* set_completion_abrupt;
- {
- Expression* proxy = factory->NewVariableProxy(var_completion);
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, proxy,
- factory->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
-
- Block* block = factory->NewBlock(nullptr, 1, true, nopos);
- block->statements()->Add(factory->NewExpressionStatement(assignment, nopos),
- zone);
- set_completion_abrupt = block;
- }
-
- // { #loop-body; #set_completion_normal }
- Block* new_body = factory->NewBlock(nullptr, 2, false, nopos);
- {
- new_body->statements()->Add(loop->body(), zone);
- new_body->statements()->Add(set_completion_normal, zone);
- }
-
- // { #set_completion_abrupt; #assign-each }
- Block* new_assign_each = factory->NewBlock(nullptr, 2, false, nopos);
- {
- new_assign_each->statements()->Add(set_completion_abrupt, zone);
- new_assign_each->statements()->Add(
- factory->NewExpressionStatement(loop->assign_each(), nopos), zone);
- }
-
- // Now put things together.
-
- loop->set_body(new_body);
- loop->set_assign_each(
- factory->NewDoExpression(new_assign_each, var_each, nopos));
-
- Statement* final_loop;
- {
- Block* target = factory->NewBlock(nullptr, 3, false, nopos);
- target->statements()->Add(initialize_each, zone);
-
Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
try_block->statements()->Add(loop, zone);
FinalizeIteratorUse(var_completion, closing_condition, loop->iterator(),
- try_block, target);
- final_loop = target;
+ try_block, final_loop);
}
return final_loop;
« no previous file with comments | « src/parsing/parser.h ('k') | test/cctest/interpreter/bytecode_expectations/ForOf.golden » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698