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

Side by Side Diff: runtime/vm/parser.cc

Issue 1014273003: Make await for cancel the stream when breaking out of the loop (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 9 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/parser.h" 5 #include "vm/parser.h"
6 6
7 #include "lib/invocation_mirror.h" 7 #include "lib/invocation_mirror.h"
8 #include "platform/utils.h" 8 #include "platform/utils.h"
9 #include "vm/ast_transformer.h" 9 #include "vm/ast_transformer.h"
10 #include "vm/bootstrap.h" 10 #include "vm/bootstrap.h"
(...skipping 6837 matching lines...) Expand 10 before | Expand all | Expand 10 after
6848 current_block_ = current_block_->parent; 6848 current_block_ = current_block_->parent;
6849 return statements; 6849 return statements;
6850 } 6850 }
6851 6851
6852 6852
6853 SequenceNode* Parser::CloseAsyncFunction(const Function& closure, 6853 SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
6854 SequenceNode* closure_body) { 6854 SequenceNode* closure_body) {
6855 TRACE_PARSER("CloseAsyncFunction"); 6855 TRACE_PARSER("CloseAsyncFunction");
6856 ASSERT(!closure.IsNull()); 6856 ASSERT(!closure.IsNull());
6857 ASSERT(closure_body != NULL); 6857 ASSERT(closure_body != NULL);
6858
6858 // The block for the async closure body has already been closed. Close the 6859 // The block for the async closure body has already been closed. Close the
6859 // corresponding function block. 6860 // corresponding function block.
6860 CloseBlock(); 6861 CloseBlock();
6861 6862
6862 closure_body->scope()->LookupVariable(Symbols::AwaitJumpVar(), false); 6863 closure_body->scope()->LookupVariable(Symbols::AwaitJumpVar(), false);
6863 closure_body->scope()->LookupVariable(Symbols::AwaitContextVar(), false); 6864 closure_body->scope()->LookupVariable(Symbols::AwaitContextVar(), false);
6864 closure_body->scope()->CaptureVariable(Symbols::AsyncCompleter()); 6865 closure_body->scope()->CaptureVariable(Symbols::AsyncCompleter());
6865 6866
6866 // Create and return a new future that executes a closure with the current 6867 // Create and return a new future that executes a closure with the current
6867 // body. 6868 // body.
(...skipping 1460 matching lines...) Expand 10 before | Expand all | Expand 10 after
8328 intptr_t loop_var_pos = TokenPos(); 8329 intptr_t loop_var_pos = TokenPos();
8329 const String* loop_var_name = ExpectIdentifier("variable name expected"); 8330 const String* loop_var_name = ExpectIdentifier("variable name expected");
8330 8331
8331 // Parse stream expression. 8332 // Parse stream expression.
8332 ExpectToken(Token::kIN); 8333 ExpectToken(Token::kIN);
8333 const intptr_t stream_pos = TokenPos(); 8334 const intptr_t stream_pos = TokenPos();
8334 AstNode* stream_expr = 8335 AstNode* stream_expr =
8335 ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); 8336 ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
8336 ExpectToken(Token::kRPAREN); 8337 ExpectToken(Token::kRPAREN);
8337 8338
8339 // Open a block for the iterator variable and the try-finally
8340 // statement that contains the loop.
8338 OpenBlock(); 8341 OpenBlock();
8342 const Block* loop_block = current_block_;
8339 8343
8340 // Build creation of implicit StreamIterator. 8344 // Build creation of implicit StreamIterator.
8341 // var :for-in-iter = new StreamIterator(stream_expr). 8345 // var :for-in-iter = new StreamIterator(stream_expr).
8342 const Class& stream_iterator_cls = 8346 const Class& stream_iterator_cls =
8343 Class::ZoneHandle(Z, I->object_store()->stream_iterator_class()); 8347 Class::ZoneHandle(Z, I->object_store()->stream_iterator_class());
8344 ASSERT(!stream_iterator_cls.IsNull()); 8348 ASSERT(!stream_iterator_cls.IsNull());
8345 const Function& iterator_ctor = 8349 const Function& iterator_ctor =
8346 Function::ZoneHandle(Z, stream_iterator_cls.LookupFunction( 8350 Function::ZoneHandle(Z, stream_iterator_cls.LookupFunction(
8347 Symbols::StreamIteratorConstructor())); 8351 Symbols::StreamIteratorConstructor()));
8348 ASSERT(!iterator_ctor.IsNull()); 8352 ASSERT(!iterator_ctor.IsNull());
8349 ArgumentListNode* ctor_args = new (Z) ArgumentListNode(Scanner::kNoSourcePos); 8353 ArgumentListNode* ctor_args = new (Z) ArgumentListNode(Scanner::kNoSourcePos);
8350 ctor_args->Add(stream_expr); 8354 ctor_args->Add(stream_expr);
8351 ConstructorCallNode* ctor_call = 8355 ConstructorCallNode* ctor_call =
8352 new (Z) ConstructorCallNode(Scanner::kNoSourcePos, 8356 new (Z) ConstructorCallNode(Scanner::kNoSourcePos,
8353 TypeArguments::ZoneHandle(Z), 8357 TypeArguments::ZoneHandle(Z),
8354 iterator_ctor, 8358 iterator_ctor,
8355 ctor_args); 8359 ctor_args);
8356 const AbstractType& iterator_type = Type::ZoneHandle(Z, Type::DynamicType()); 8360 const AbstractType& iterator_type = Type::ZoneHandle(Z, Type::DynamicType());
8357 LocalVariable* iterator_var = new(Z) LocalVariable( 8361 LocalVariable* iterator_var = new(Z) LocalVariable(
8358 stream_pos, Symbols::ForInIter(), iterator_type); 8362 stream_pos, Symbols::ForInIter(), iterator_type);
8359 current_block_->scope->AddVariable(iterator_var); 8363 current_block_->scope->AddVariable(iterator_var);
8360 AstNode* iterator_init = 8364 AstNode* iterator_init =
8361 new(Z) StoreLocalNode(stream_pos, iterator_var, ctor_call); 8365 new(Z) StoreLocalNode(stream_pos, iterator_var, ctor_call);
8362 current_block_->statements->Add(iterator_init); 8366 current_block_->statements->Add(iterator_init);
8363 8367
8368 // We need to ensure that the stream is cancelled after the loop.
8369 // Thus, wrap the loop in a try-finally that calls :for-in-iter.close()
8370 // in the finally clause. It is harmless to call close() if the stream
8371 // is already cancelled (when moveNext() returns false).
8372 // Note: even though this is async code, we do not need to set up
8373 // the closurized saved_exception_var and saved_stack_trace_var because
8374 // there can not be a suspend/resume event before the exception is
8375 // rethrown in the catch clause. The catch block of the implicit
8376 // try-finally is empty.
8377 LocalVariable* context_var = NULL;
8378 LocalVariable* exception_var = NULL;
8379 LocalVariable* stack_trace_var = NULL;
8380 LocalVariable* saved_exception_var = NULL;
8381 LocalVariable* saved_stack_trace_var = NULL;
8382 SetupExceptionVariables(current_block_->scope,
8383 false, // Do not create the saved_ vars.
8384 &context_var,
8385 &exception_var,
8386 &stack_trace_var,
8387 &saved_exception_var,
8388 &saved_stack_trace_var);
8389 OpenBlock(); // try block.
8390 PushTry(current_block_);
8391 SetupSavedTryContext(context_var);
8392
8393 // Build while loop condition.
8394 // while (await :for-in-iter.moveNext())
8364 LocalScope* try_scope; 8395 LocalScope* try_scope;
8365 int16_t try_index; 8396 int16_t try_index;
8366 LocalScope* outer_try_scope; 8397 LocalScope* outer_try_scope;
8367 int16_t outer_try_index; 8398 int16_t outer_try_index;
8368 CheckAsyncOpInTryBlock(&try_scope, &try_index, 8399 CheckAsyncOpInTryBlock(&try_scope, &try_index,
8369 &outer_try_scope, &outer_try_index); 8400 &outer_try_scope, &outer_try_index);
8370 8401
8371 // Build while loop condition.
8372 // while (await :for-in-iter.moveNext())
8373 ArgumentListNode* no_args = new(Z) ArgumentListNode(stream_pos); 8402 ArgumentListNode* no_args = new(Z) ArgumentListNode(stream_pos);
8374 AstNode* iterator_moveNext = new(Z) InstanceCallNode( 8403 AstNode* iterator_moveNext = new(Z) InstanceCallNode(
8375 stream_pos, 8404 stream_pos,
8376 new(Z) LoadLocalNode(stream_pos, iterator_var), 8405 new(Z) LoadLocalNode(stream_pos, iterator_var),
8377 Symbols::MoveNext(), 8406 Symbols::MoveNext(),
8378 no_args); 8407 no_args);
8379 AstNode* await_moveNext = new (Z) AwaitNode(stream_pos, 8408 AstNode* await_moveNext =
8380 iterator_moveNext, 8409 new(Z) AwaitNode(stream_pos,
8381 try_scope, 8410 iterator_moveNext,
8382 try_index, 8411 try_scope,
8383 outer_try_scope, 8412 try_index,
8384 outer_try_index); 8413 outer_try_scope,
8414 outer_try_index);
8385 OpenBlock(); 8415 OpenBlock();
8386 AwaitTransformer at(current_block_->statements, async_temp_scope_); 8416 AwaitTransformer at(current_block_->statements, async_temp_scope_);
8387 AstNode* transformed_await = at.Transform(await_moveNext); 8417 await_moveNext = at.Transform(await_moveNext);
8388 SequenceNode* await_preamble = CloseBlock(); 8418 SequenceNode* await_preamble = CloseBlock();
8389 8419
8390 // Parse the for loop body. Ideally, we would use ParseNestedStatement() 8420 // Parse the for loop body. Ideally, we would use ParseNestedStatement()
8391 // here, but that does not work well because we have to insert an implicit 8421 // here, but that does not work well because we have to insert an implicit
8392 // variable assignment and potentially a variable declaration in the 8422 // variable assignment and potentially a variable declaration in the
8393 // loop body. 8423 // loop body.
8394 OpenLoopBlock(); 8424 OpenLoopBlock();
8425
8395 SourceLabel* label = 8426 SourceLabel* label =
8396 SourceLabel::New(await_for_pos, label_name, SourceLabel::kFor); 8427 SourceLabel::New(await_for_pos, label_name, SourceLabel::kFor);
8397 current_block_->scope->AddLabel(label); 8428 current_block_->scope->AddLabel(label);
8398 const intptr_t loop_var_assignment_pos = TokenPos(); 8429 const intptr_t loop_var_assignment_pos = TokenPos();
8399 8430
8400 AstNode* iterator_current = new(Z) InstanceGetterNode( 8431 AstNode* iterator_current = new(Z) InstanceGetterNode(
8401 loop_var_assignment_pos, 8432 loop_var_assignment_pos,
8402 new(Z) LoadLocalNode(loop_var_assignment_pos, iterator_var), 8433 new(Z) LoadLocalNode(loop_var_assignment_pos, iterator_var),
8403 Symbols::Current()); 8434 Symbols::Current());
8404 8435
(...skipping 17 matching lines...) Expand all
8422 } else { 8453 } else {
8423 AstNode* loop_var_primary = 8454 AstNode* loop_var_primary =
8424 ResolveIdent(loop_var_pos, *loop_var_name, false); 8455 ResolveIdent(loop_var_pos, *loop_var_name, false);
8425 ASSERT(!loop_var_primary->IsPrimaryNode()); 8456 ASSERT(!loop_var_primary->IsPrimaryNode());
8426 loop_var_assignment = CreateAssignmentNode(loop_var_primary, 8457 loop_var_assignment = CreateAssignmentNode(loop_var_primary,
8427 iterator_current, 8458 iterator_current,
8428 loop_var_name, 8459 loop_var_name,
8429 loop_var_assignment_pos); 8460 loop_var_assignment_pos);
8430 ASSERT(loop_var_assignment != NULL); 8461 ASSERT(loop_var_assignment != NULL);
8431 } 8462 }
8463
8432 current_block_->statements->Add(loop_var_assignment); 8464 current_block_->statements->Add(loop_var_assignment);
8433 8465
8434 // Now parse the for-in loop statement or block. 8466 // Now parse the for-in loop statement or block.
8435 if (CurrentToken() == Token::kLBRACE) { 8467 if (CurrentToken() == Token::kLBRACE) {
8436 ConsumeToken(); 8468 ConsumeToken();
8437 ParseStatementSequence(); 8469 ParseStatementSequence();
8438 ExpectToken(Token::kRBRACE); 8470 ExpectToken(Token::kRBRACE);
8439 } else { 8471 } else {
8440 AstNode* statement = ParseStatement(); 8472 AstNode* statement = ParseStatement();
8441 if (statement != NULL) { 8473 if (statement != NULL) {
8442 current_block_->statements->Add(statement); 8474 current_block_->statements->Add(statement);
8443 } 8475 }
8444 } 8476 }
8445 SequenceNode* for_loop_statement = CloseBlock(); 8477 SequenceNode* for_loop_block = CloseBlock();
8446 8478
8447 WhileNode* while_node = new (Z) WhileNode(await_for_pos, 8479 WhileNode* while_node = new (Z) WhileNode(await_for_pos,
8448 label, 8480 label,
8449 transformed_await, 8481 await_moveNext,
8450 await_preamble, 8482 await_preamble,
8451 for_loop_statement); 8483 for_loop_block);
8484 // Add the while loop to the try block.
8452 current_block_->statements->Add(while_node); 8485 current_block_->statements->Add(while_node);
8453 8486
8487 SequenceNode* try_block = CloseBlock();
8488
8489
regis 2015/03/24 23:46:27 remove extra blank line
hausner 2015/03/24 23:57:29 Done.
8490 // Create an empty "catch all" block that rethrows the current
8491 // exception and stacktrace.
8492 try_stack_->enter_catch();
8493 SequenceNode* catch_block = new(Z) SequenceNode(await_for_pos, NULL);
8494
8495 if (outer_try_scope != NULL) {
8496 // TODO(hausner): Do we need to restore the saved try context here? The
8497 // code does not touch any captured variables, it just rethrows the
8498 // current exception.
regis 2015/03/24 23:46:27 The code may not access captured variables, but if
hausner 2015/03/24 23:57:29 True, thank you. Removed comment.
8499 catch_block->Add(AwaitTransformer::RestoreSavedTryContext(
8500 Z, outer_try_scope, outer_try_index));
8501 }
8502
8503 // We don't need to copy the current execption and stack trace variables
regis 2015/03/24 23:46:27 typo
hausner 2015/03/24 23:57:29 Done.
8504 // into :saved_exception_var and :saved_stack_trace_var here because there
8505 // is no code in the catch clause that could suspend the function.
8506
8507 // Rethrow the exception.
8508 catch_block->Add(new(Z) ThrowNode(
8509 await_for_pos,
8510 new(Z) LoadLocalNode(await_for_pos, exception_var),
8511 new(Z) LoadLocalNode(await_for_pos, stack_trace_var)));
8512
8513 TryStack* try_statement = PopTry();
8514 ASSERT(try_index == try_statement->try_index());
8515
8516 // The finally block contains a call to cancel the stream.
8517 // :for-in-iter.cancel()
8518
8519 // Inline the finally block to the exit points in the try block.
8520 intptr_t node_index = 0;
8521 SequenceNode* finally_clause = NULL;
8522 do {
8523 OpenBlock();
8524 ArgumentListNode* no_args =
8525 new(Z) ArgumentListNode(Scanner::kNoSourcePos);
8526 current_block_->statements->Add(
8527 new(Z) InstanceCallNode(Scanner::kNoSourcePos,
8528 new(Z) LoadLocalNode(Scanner::kNoSourcePos, iterator_var),
8529 Symbols::Cancel(),
8530 no_args));
8531 finally_clause = CloseBlock();
8532 AstNode* node_to_inline = try_statement->GetNodeToInlineFinally(node_index);
8533 if (node_to_inline != NULL) {
8534 InlinedFinallyNode* node =
8535 new(Z) InlinedFinallyNode(Scanner::kNoSourcePos,
8536 finally_clause,
8537 context_var,
8538 outer_try_index);
8539 finally_clause = NULL;
8540 AddFinallyBlockToNode(true, node_to_inline, node);
8541 node_index++;
8542 }
8543 } while (finally_clause == NULL);
8544
8545 // Create the try-statement and add to the current sequence, which is
8546 // the block around the loop statement.
8547
8548 const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
8549 const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld));
8550 handler_types.SetAt(0, dynamic_type); // Catch block handles all exceptions.
8551
8552 CatchClauseNode* catch_clause = new(Z) CatchClauseNode(await_for_pos,
8553 catch_block,
8554 handler_types,
8555 context_var,
8556 exception_var,
8557 stack_trace_var,
8558 exception_var,
8559 stack_trace_var,
8560 AllocateTryIndex(),
8561 true); // Needs stack trace.
8562
8563 AstNode* try_catch_node =
8564 new(Z) TryCatchNode(await_for_pos,
8565 try_block,
8566 context_var,
8567 catch_clause,
8568 finally_clause,
8569 try_index);
8570
8571 ASSERT(current_block_ == loop_block);
8572 loop_block->statements->Add(try_catch_node);
8573
8454 return CloseBlock(); // Implicit block around while loop. 8574 return CloseBlock(); // Implicit block around while loop.
8455 } 8575 }
8456 8576
8457 8577
8458 AstNode* Parser::ParseForInStatement(intptr_t forin_pos, 8578 AstNode* Parser::ParseForInStatement(intptr_t forin_pos,
8459 SourceLabel* label) { 8579 SourceLabel* label) {
8460 TRACE_PARSER("ParseForInStatement"); 8580 TRACE_PARSER("ParseForInStatement");
8461 bool loop_var_is_final = (CurrentToken() == Token::kFINAL); 8581 bool loop_var_is_final = (CurrentToken() == Token::kFINAL);
8462 if (CurrentToken() == Token::kCONST) { 8582 if (CurrentToken() == Token::kCONST) {
8463 ReportError("Loop variable cannot be 'const'"); 8583 ReportError("Loop variable cannot be 'const'");
(...skipping 4817 matching lines...) Expand 10 before | Expand all | Expand 10 after
13281 void Parser::SkipQualIdent() { 13401 void Parser::SkipQualIdent() {
13282 ASSERT(IsIdentifier()); 13402 ASSERT(IsIdentifier());
13283 ConsumeToken(); 13403 ConsumeToken();
13284 if (CurrentToken() == Token::kPERIOD) { 13404 if (CurrentToken() == Token::kPERIOD) {
13285 ConsumeToken(); // Consume the kPERIOD token. 13405 ConsumeToken(); // Consume the kPERIOD token.
13286 ExpectIdentifier("identifier expected after '.'"); 13406 ExpectIdentifier("identifier expected after '.'");
13287 } 13407 }
13288 } 13408 }
13289 13409
13290 } // namespace dart 13410 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698