Restore try contexts when breaking out of async for loops

Restore the try context in the finally clause of the implicit
try-finally around await-for loops. This ensures that the context
is restored even when breaking out of the loop.

BUG=24935
R=fschneider@google.com, regis@google.com

Review URL: https://codereview.chromium.org/1661433003 .
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 2034a2f..bed681e 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -8719,7 +8719,7 @@
       outer_try->try_index() : CatchClauseNode::kInvalidTryIndex;
 
   // The finally block contains a call to cancel the stream.
-  // :for-in-iter.cancel()
+  // :for-in-iter.cancel();
 
   // Inline the finally block to the exit points in the try block.
   intptr_t node_index = 0;
@@ -8729,6 +8729,17 @@
   }
   do {
     OpenBlock();
+
+    // Restore the saved try context of the enclosing try block if one
+    // exists.
+    if (outer_saved_try_ctx != NULL) {
+      current_block_->statements->Add(new (Z) StoreLocalNode(
+          TokenPosition::kNoSource,
+          outer_saved_try_ctx,
+          new (Z) LoadLocalNode(TokenPosition::kNoSource,
+                                outer_async_saved_try_ctx)));
+    }
+    // :for-in-iter.cancel();
     ArgumentListNode* no_args =
         new(Z) ArgumentListNode(TokenPosition::kNoSource);
     current_block_->statements->Add(
@@ -8737,6 +8748,7 @@
             Symbols::Cancel(),
             no_args));
     finally_clause = CloseBlock();
+
     AstNode* node_to_inline = try_statement->GetNodeToInlineFinally(node_index);
     if (node_to_inline != NULL) {
       InlinedFinallyNode* node =
@@ -9127,7 +9139,7 @@
   if (try_stack_ != NULL) {
     try_stack_->enter_finally();
   }
-  // In case of async closures we need to restore the saved try index of an
+  // In case of async closures we need to restore the saved try context of an
   // outer try block (if it exists).  The current try block has already been
   // removed from the stack of try blocks.
   if (is_async) {
diff --git a/tests/language/regress_24935_test.dart b/tests/language/regress_24935_test.dart
new file mode 100644
index 0000000..53f6f49
--- /dev/null
+++ b/tests/language/regress_24935_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+S() => new Stream.fromIterable([1]);
+
+Future main() async {
+  L: for (var s = 0; s < 10; s++) {
+    await for (var s1 in S()){
+      await for (var s2 in S()){
+        continue L;
+      }
+    }
+  }
+  // Regression check: make sure throwing an exception
+  // after breaking out of the innermost loop does not
+  // crash the VM. In other words, the expected test
+  // outcome is an unhandled exception.
+  throw "ball"; /// 01: runtime error
+}
+
+