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

Unified Diff: src/parsing/parser.cc

Issue 1634553002: Fix bug where generators got closed prematurely. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Address comments. Created 4 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/js/generator.js ('k') | test/cctest/test-ast-expression-visitor.cc » ('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 dd9744e7f6314d72f1b3b91ad4b28218da7d1225..5e88b58fefce96eecbd887e82005aee15decc139 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -4655,35 +4655,72 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
{
BlockState block_state(&scope_, inner_scope);
- // For generators, allocate and yield an iterator on function entry.
if (IsGeneratorFunction(kind)) {
- ZoneList<Expression*>* arguments =
- new(zone()) ZoneList<Expression*>(0, zone());
- CallRuntime* allocation = factory()->NewCallRuntime(
- Runtime::kCreateJSGeneratorObject, arguments, pos);
- VariableProxy* init_proxy = factory()->NewVariableProxy(
- function_state_->generator_object_variable());
- Assignment* assignment = factory()->NewAssignment(
- Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
- VariableProxy* get_proxy = factory()->NewVariableProxy(
- function_state_->generator_object_variable());
- Yield* yield = factory()->NewYield(
- get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
- body->Add(factory()->NewExpressionStatement(
- yield, RelocInfo::kNoPosition), zone());
- }
+ // We produce:
+ //
+ // try { InitialYield; ...body...; FinalYield }
+ // finally { %GeneratorClose(generator) }
+ //
+ // - InitialYield yields the actual generator object.
+ // - FinalYield yields {value: foo, done: true} where foo is the
+ // completion value of body. (This is needed here in case the body
+ // falls through without an explicit return.)
+ // - Any return statement inside the body will be converted into a similar
+ // FinalYield.
+ // - If the generator terminates for whatever reason, we must close it.
+ // Hence the finally clause.
+
+ Block* try_block =
+ factory()->NewBlock(nullptr, 3, false, RelocInfo::kNoPosition);
- ParseStatementList(body, Token::RBRACE, CHECK_OK);
+ {
+ ZoneList<Expression*>* arguments =
+ new (zone()) ZoneList<Expression*>(0, zone());
+ CallRuntime* allocation = factory()->NewCallRuntime(
+ Runtime::kCreateJSGeneratorObject, arguments, pos);
+ VariableProxy* init_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ Assignment* assignment = factory()->NewAssignment(
+ Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
+ VariableProxy* get_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ Yield* yield = factory()->NewYield(
+ get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
+ try_block->statements()->Add(
+ factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition),
+ zone());
+ }
+
+ ParseStatementList(try_block->statements(), Token::RBRACE, CHECK_OK);
- if (IsGeneratorFunction(kind)) {
VariableProxy* get_proxy = factory()->NewVariableProxy(
function_state_->generator_object_variable());
Expression* undefined =
factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
Yield* yield = factory()->NewYield(get_proxy, undefined, Yield::kFinal,
RelocInfo::kNoPosition);
- body->Add(factory()->NewExpressionStatement(
- yield, RelocInfo::kNoPosition), zone());
+ try_block->statements()->Add(
+ factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition),
+ zone());
+
+ Block* finally_block =
+ factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition);
+ 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::kGeneratorClose, args, RelocInfo::kNoPosition);
+ finally_block->statements()->Add(
+ factory()->NewExpressionStatement(call, RelocInfo::kNoPosition),
+ zone());
+
+ body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
+ RelocInfo::kNoPosition),
+ zone());
+ } else {
+ ParseStatementList(body, Token::RBRACE, CHECK_OK);
}
if (IsSubclassConstructor(kind)) {
« no previous file with comments | « src/js/generator.js ('k') | test/cctest/test-ast-expression-visitor.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698