Version 1.17.1

An earlier commit was also named 1.17.1, but that was an error.
That earlier commit was released as 1.17.0.

Cherry-pick 'f4029bf3ee72c6667f4099a0e2e747b22fe45c32' to stable
Cherry-pick 'e803457081ee5c0efcd05d924c168ceb4dc534c7' to stable
Cherry-pick '97a8c4caffd2e758c60a3e4502f07d6886ee0363' to stable
Cherry-pick '9d5e1331149062cd5de4ed5a54841c03872f8edd' to stable
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 637e978..a649682 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,14 @@
-## 1.17.0 - 2016-06-06
+## 1.17.1 - 2016-06-10
+
+Patch release, resolves two issues:
+
+* VM: Fixes a bug that caused crashes in async functions.
+(SDK issue [26668](https://github.com/dart-lang/sdk/issues/26668))
+
+* VM: Fixes a bug that caused garbage collection of reachable weak properties.
+(https://codereview.chromium.org/2041413005)
+
+## 1.17.0 - 2016-06-08
 
 ### Core library changes
 * `dart:convert`
diff --git a/runtime/platform/assert.h b/runtime/platform/assert.h
index a60d85d5..9d6d67c 100644
--- a/runtime/platform/assert.h
+++ b/runtime/platform/assert.h
@@ -281,6 +281,12 @@
 #endif  // if defined(DEBUG)
 
 
+#define RELEASE_ASSERT(cond)                                                   \
+  do {                                                                         \
+    if (!(cond)) dart::Assert(__FILE__, __LINE__).Fail("expected: %s", #cond); \
+  } while (false)
+
+
 // The COMPILE_ASSERT macro can be used to verify that a compile time
 // expression is true. For example, you could use it to verify the
 // size of a static array:
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index 069f341..2ac946a 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -177,12 +177,43 @@
     return class_stats_size_[class_id];
   }
 
-  // Returns true if some non-zero amount of work was performed.
-  bool DrainMarkingStack() {
+  bool ProcessPendingWeakProperties() {
+    bool marked = false;
+    RawWeakProperty* cur_weak = delayed_weak_properties_;
+    delayed_weak_properties_ = NULL;
+    while (cur_weak != NULL) {
+      uword next_weak = cur_weak->ptr()->next_;
+      RawObject* raw_key = cur_weak->ptr()->key_;
+      // Reset the next pointer in the weak property.
+      cur_weak->ptr()->next_ = 0;
+      if (raw_key->IsMarked()) {
+        RawObject* raw_val = cur_weak->ptr()->value_;
+        marked = marked || (raw_val->IsHeapObject() && !raw_val->IsMarked());
+
+        // The key is marked so we make sure to properly visit all pointers
+        // originating from this weak property.
+        VisitingOldObject(cur_weak);
+        cur_weak->VisitPointers(this);
+      } else {
+        // Requeue this weak property to be handled later.
+        EnqueueWeakProperty(cur_weak);
+      }
+      // Advance to next weak property in the queue.
+      cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak);
+    }
+    VisitingOldObject(NULL);
+    return marked;
+  }
+
+  void DrainMarkingStack() {
     RawObject* raw_obj = work_list_.Pop();
+    if ((raw_obj == NULL) && ProcessPendingWeakProperties()) {
+      raw_obj = work_list_.Pop();
+    }
+
     if (raw_obj == NULL) {
       ASSERT(visiting_old_object_ == NULL);
-      return false;
+      return;
     }
     do {
       do {
@@ -200,33 +231,13 @@
       } while (raw_obj != NULL);
 
       // Marking stack is empty.
-      // Process all the pending weak properties in this visitor.
-      RawWeakProperty* cur_weak = delayed_weak_properties_;
-      delayed_weak_properties_ = NULL;
-      while (cur_weak != NULL) {
-        uword next_weak = cur_weak->ptr()->next_;
-        RawObject* raw_key = cur_weak->ptr()->key_;
-        // Reset the next pointer in the weak property.
-        cur_weak->ptr()->next_ = 0;
-        if (raw_key->IsMarked()) {
-          // The key is marked so we make sure to properly visit all pointers
-          // originating from this weak property.
-          VisitingOldObject(cur_weak);
-          cur_weak->VisitPointers(this);
-        } else {
-          // Requeue this weak property to be handled later.
-          EnqueueWeakProperty(cur_weak);
-        }
-        // Advance to next weak property in the queue.
-        cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak);
-      }
+      ProcessPendingWeakProperties();
 
       // Check whether any further work was pushed either by other markers or
       // by the handling of weak properties.
       raw_obj = work_list_.Pop();
     } while (raw_obj != NULL);
     VisitingOldObject(NULL);
-    return true;
   }
 
   void VisitPointers(RawObject** first, RawObject** last) {
@@ -282,6 +293,7 @@
     while (cur_weak != NULL) {
       uword next_weak = cur_weak->ptr()->next_;
       cur_weak->ptr()->next_ = 0;
+      RELEASE_ASSERT(!cur_weak->ptr()->key_->IsMarked());
       WeakProperty::Clear(cur_weak);
       weak_properties_cleared++;
       // Advance to next weak property in the queue.
@@ -569,28 +581,54 @@
                                  skipped_code_functions);
       // Phase 1: Iterate over roots and drain marking stack in tasks.
       marker_->IterateRoots(isolate_, &visitor, task_index_, num_tasks_);
+
+      bool more_to_mark = false;
       do {
-        visitor.DrainMarkingStack();
+        do {
+          visitor.DrainMarkingStack();
 
-        // I can't find more work right now. If no other task is busy,
-        // then there will never be more work (NB: 1 is *before* decrement).
-        if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break;
+          // I can't find more work right now. If no other task is busy,
+          // then there will never be more work (NB: 1 is *before* decrement).
+          if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break;
 
-        // Wait for some work to appear.
-        // TODO(iposva): Replace busy-waiting with a solution using Monitor,
-        // and redraw the boundaries between stack/visitor/task as needed.
-        while (marking_stack_->IsEmpty() &&
-               AtomicOperations::LoadRelaxed(num_busy_) > 0) {
+          // Wait for some work to appear.
+          // TODO(iposva): Replace busy-waiting with a solution using Monitor,
+          // and redraw the boundaries between stack/visitor/task as needed.
+          while (marking_stack_->IsEmpty() &&
+                 AtomicOperations::LoadRelaxed(num_busy_) > 0) {
+          }
+
+          // If no tasks are busy, there will never be more work.
+          if (AtomicOperations::LoadRelaxed(num_busy_) == 0) break;
+
+          // I saw some work; get busy and compete for it.
+          AtomicOperations::FetchAndIncrement(num_busy_);
+        } while (true);
+        // Wait for all markers to stop.
+        barrier_->Sync();
+        ASSERT(AtomicOperations::LoadRelaxed(num_busy_) == 0);
+
+        // Check if we have any pending properties with marked keys.
+        // Those might have been marked by another marker.
+        more_to_mark = visitor.ProcessPendingWeakProperties();
+        if (more_to_mark) {
+          // We have more work to do. Notify others.
+          AtomicOperations::FetchAndIncrement(num_busy_);
         }
 
-        // If no tasks are busy, there will never be more work.
-        if (AtomicOperations::LoadRelaxed(num_busy_) == 0) break;
-
-        // I saw some work; get busy and compete for it.
-        AtomicOperations::FetchAndIncrement(num_busy_);
-      } while (true);
-      ASSERT(AtomicOperations::LoadRelaxed(num_busy_) == 0);
-      barrier_->Sync();
+        // Wait for all other markers to finish processing their pending
+        // weak properties and decide if they need to continue marking.
+        // Caveat: we need two barriers here to make this decision in lock step
+        // between all markers and the main thread.
+        barrier_->Sync();
+        if (!more_to_mark && (AtomicOperations::LoadRelaxed(num_busy_) > 0)) {
+          // All markers continue to marker as long as any single marker has
+          // some work to do.
+          AtomicOperations::FetchAndIncrement(num_busy_);
+          more_to_mark = true;
+        }
+        barrier_->Sync();
+      } while (more_to_mark);
 
       // Phase 2: Weak processing and follow-up marking on main thread.
       barrier_->Sync();
@@ -688,7 +726,19 @@
         ThreadPool* pool = Dart::thread_pool();
         pool->Run(mark_task);
       }
-      barrier.Sync();
+      bool more_to_mark = false;
+      do {
+        // Wait for all markers to stop.
+        barrier.Sync();
+
+        // Wait for all markers to go through weak properties and verify
+        // that there are no more objects to mark.
+        // Note: we need to have two barriers here because we want all markers
+        // and main thread to make decisions in lock step.
+        barrier.Sync();
+        more_to_mark = AtomicOperations::LoadRelaxed(&num_busy) > 0;
+        barrier.Sync();
+      } while (more_to_mark);
 
       // Phase 2: Weak processing on main thread.
       {
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index a07921f..6668731 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -10057,25 +10057,28 @@
     ConsumeToken();
     if (CurrentToken() != Token::kSEMICOLON) {
       const TokenPosition expr_pos = TokenPos();
+      const int function_level = current_block_->scope->function_level();
       if (current_function().IsGenerativeConstructor() &&
-          (current_block_->scope->function_level() == 0)) {
+          (function_level == 0)) {
         ReportError(expr_pos,
                     "return of a value is not allowed in constructors");
       } else if (current_function().IsGeneratorClosure() &&
-          (current_block_->scope->function_level() == 0)) {
+          (function_level == 0)) {
         ReportError(expr_pos, "generator functions may not return a value");
       }
       AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
       if (I->type_checks() &&
-          current_function().IsAsyncClosure() &&
-          (current_block_->scope->function_level() == 0)) {
+          (((function_level == 0) && current_function().IsAsyncClosure()) ||
+           ((function_level > 0) && current_function().IsAsyncFunction()))) {
         // In checked mode, when the declared result type is Future<T>, verify
         // that the returned expression is of type T or Future<T> as follows:
         // return temp = expr, temp is Future ? temp as Future<T> : temp as T;
         // In case of a mismatch, we need a TypeError and not a CastError, so
         // we do not actually implement an "as" test, but an "assignable" test.
-        const Function& async_func =
-            Function::Handle(Z, current_function().parent_function());
+        Function& async_func = Function::Handle(Z, current_function().raw());
+        if (function_level == 0) {
+          async_func = async_func.parent_function();
+        }
         const AbstractType& result_type =
             AbstractType::ZoneHandle(Z, async_func.result_type());
         const Class& future_class =
@@ -10087,32 +10090,41 @@
           if (!result_type_args.IsNull() && (result_type_args.Length() == 1)) {
             const AbstractType& result_type_arg =
                 AbstractType::ZoneHandle(Z, result_type_args.TypeAt(0));
-            LetNode* checked_expr = new(Z) LetNode(expr_pos);
-            LocalVariable* temp = checked_expr->AddInitializer(expr);
-            temp->set_is_final();
-            const AbstractType& future_type =
-                AbstractType::ZoneHandle(Z, future_class.RareType());
-            AstNode* is_future = new(Z) LoadLocalNode(expr_pos, temp);
-            is_future = new(Z) ComparisonNode(expr_pos,
-                                              Token::kIS,
-                                              is_future,
-                                              new(Z) TypeNode(expr_pos,
-                                                              future_type));
-            AstNode* as_future_t = new(Z) LoadLocalNode(expr_pos, temp);
-            as_future_t = new(Z) AssignableNode(expr_pos,
-                                                as_future_t,
-                                                result_type,
-                                                Symbols::FunctionResult());
-            AstNode* as_t = new(Z) LoadLocalNode(expr_pos, temp);
-            as_t = new(Z) AssignableNode(expr_pos,
-                                         as_t,
-                                         result_type_arg,
-                                         Symbols::FunctionResult());
-            checked_expr->AddNode(new(Z) ConditionalExprNode(expr_pos,
-                                                             is_future,
-                                                             as_future_t,
-                                                             as_t));
-            expr = checked_expr;
+            if (function_level == 0) {
+              // Parsing and generating code for async closure.
+              LetNode* checked_expr = new(Z) LetNode(expr_pos);
+              LocalVariable* temp = checked_expr->AddInitializer(expr);
+              temp->set_is_final();
+              const AbstractType& future_type =
+                  AbstractType::ZoneHandle(Z, future_class.RareType());
+              AstNode* is_future = new(Z) LoadLocalNode(expr_pos, temp);
+              is_future = new(Z) ComparisonNode(expr_pos,
+                                                Token::kIS,
+                                                is_future,
+                                                new(Z) TypeNode(expr_pos,
+                                                                future_type));
+              AstNode* as_future_t = new(Z) LoadLocalNode(expr_pos, temp);
+              as_future_t = new(Z) AssignableNode(expr_pos,
+                                                  as_future_t,
+                                                  result_type,
+                                                  Symbols::FunctionResult());
+              AstNode* as_t = new(Z) LoadLocalNode(expr_pos, temp);
+              as_t = new(Z) AssignableNode(expr_pos,
+                                           as_t,
+                                           result_type_arg,
+                                           Symbols::FunctionResult());
+              checked_expr->AddNode(new(Z) ConditionalExprNode(expr_pos,
+                                                               is_future,
+                                                               as_future_t,
+                                                               as_t));
+              expr = checked_expr;
+            } else {
+              // Parsing async function, but not generating async closure code.
+              if (!result_type_arg.IsInstantiated()) {
+                // Make sure that the instantiator is captured.
+                CaptureInstantiator();
+              }
+            }
           }
         }
       }
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index a0e3ee5..fe2f70b 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -4,6 +4,8 @@
 
 [ $compiler == dart2analyzer ]
 
+regress_26668_test: Fail # Issue 26678
+
 # Runtime negative test. No static errors or warnings.
 closure_call_wrong_argument_count_negative_test: skip
 
diff --git a/tests/language/regress_26668_test.dart b/tests/language/regress_26668_test.dart
new file mode 100644
index 0000000..ffadcc7
--- /dev/null
+++ b/tests/language/regress_26668_test.dart
@@ -0,0 +1,18 @@
+// 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.
+// Tests that the VM does not crash on weird corner cases of class Math.
+
+import 'dart:async';
+
+main() async {
+  var myClass = new CustomClass<int>();
+  await myClass.processData();
+}
+
+class CustomClass<T> {
+  Future<T> processData() async {
+    return 0;
+  }
+}
+
diff --git a/tools/VERSION b/tools/VERSION
index 056acef..b32057e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -26,6 +26,6 @@
 CHANNEL stable
 MAJOR 1
 MINOR 17
-PATCH 0
+PATCH 1
 PRERELEASE 0
 PRERELEASE_PATCH 0