Version 2.12.0-118.0.dev

Merge commit '16f163157aa2b3d6f39a8dae4ce96d9c663e8f0c' into 'dev'
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 49dcb3d..30a2a3dd 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -759,30 +759,26 @@
       );
 
       try {
-        List<Assist> assists;
-        try {
-          var processor = AssistProcessor(context);
-          assists = await processor.compute();
-        } on InconsistentAnalysisException {
-          assists = [];
-        } catch (exception, stackTrace) {
-          var parametersFile = '''
-offset: $offset
-length: $length
-      ''';
-          throw CaughtExceptionWithFiles(exception, stackTrace, {
-            file: result.content,
-            'parameters': parametersFile,
-          });
-        }
-
+        var processor = AssistProcessor(context);
+        var assists = await processor.compute();
         assists.sort(Assist.SORT_BY_RELEVANCE);
         for (var assist in assists) {
           changes.add(assist.change);
         }
+      } on InconsistentAnalysisException {
+        // ignore
+      } catch (exception, stackTrace) {
+        var parametersFile = '''
+offset: $offset
+length: $length
+      ''';
+        throw CaughtExceptionWithFiles(exception, stackTrace, {
+          file: result.content,
+          'parameters': parametersFile,
+        });
+      }
 
-        server.requestStatistics?.addItemTimeNow(request, 'computedAssists');
-      } catch (_) {}
+      server.requestStatistics?.addItemTimeNow(request, 'computedAssists');
     }
 
     return changes;
diff --git a/runtime/platform/atomic.h b/runtime/platform/atomic.h
index 7a966f5..98bc900 100644
--- a/runtime/platform/atomic.h
+++ b/runtime/platform/atomic.h
@@ -100,14 +100,18 @@
   bool compare_exchange_weak(
       T& expected,  // NOLINT
       T desired,
-      std::memory_order order = std::memory_order_acq_rel) {
-    return value_.compare_exchange_weak(expected, desired, order, order);
+      std::memory_order success_order = std::memory_order_acq_rel,
+      std::memory_order failure_order = std::memory_order_seq_cst) {
+    return value_.compare_exchange_weak(expected, desired, success_order,
+                                        failure_order);
   }
   bool compare_exchange_strong(
       T& expected,  // NOLINT
       T desired,
-      std::memory_order order = std::memory_order_acq_rel) {
-    return value_.compare_exchange_strong(expected, desired, order, order);
+      std::memory_order success_order = std::memory_order_acq_rel,
+      std::memory_order failure_order = std::memory_order_seq_cst) {
+    return value_.compare_exchange_strong(expected, desired, success_order,
+                                          failure_order);
   }
 
   // Require explicit loads and stores.
diff --git a/runtime/vm/compiler/backend/type_propagator_test.cc b/runtime/vm/compiler/backend/type_propagator_test.cc
index 2920aca..852a885 100644
--- a/runtime/vm/compiler/backend/type_propagator_test.cc
+++ b/runtime/vm/compiler/backend/type_propagator_test.cc
@@ -187,7 +187,11 @@
                  /*is_reflectable=*/true,
                  /*is_late=*/false, object_class, Object::dynamic_type(),
                  TokenPosition::kNoSource, TokenPosition::kNoSource));
-  thread->isolate_group()->RegisterStaticField(field, Instance::Handle());
+  {
+    SafepointWriteRwLocker locker(thread,
+                                  thread->isolate_group()->program_lock());
+    thread->isolate_group()->RegisterStaticField(field, Instance::Handle());
+  }
 
   FlowGraphBuilderHelper H;
 
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 9dd6654..9f63a72 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -697,8 +697,7 @@
   }
   I->isolate_object_store()->Init();
   I->isolate_object_store()->PreallocateObjects();
-  I->set_field_table(T, source_isolate_group->initial_field_table()->Clone(
-                            /*is_isolate_field_table=*/true));
+  I->set_field_table(T, source_isolate_group->initial_field_table()->Clone(I));
 
   return true;
 }
@@ -743,8 +742,7 @@
       return error.raw();
     }
 
-    I->set_field_table(T, I->group()->initial_field_table()->Clone(
-                              /*is_isolate_field_table=*/true));
+    I->set_field_table(T, I->group()->initial_field_table()->Clone(I));
 
 #if defined(SUPPORT_TIMELINE)
     if (tbes.enabled()) {
diff --git a/runtime/vm/field_table.cc b/runtime/vm/field_table.cc
index 8185067..a6358a1 100644
--- a/runtime/vm/field_table.cc
+++ b/runtime/vm/field_table.cc
@@ -98,13 +98,13 @@
   // via store to table_.
   std::atomic_thread_fence(std::memory_order_release);
   table_ = new_table;
-  if (is_isolate_field_table_) {
-    Thread::Current()->field_table_values_ = table_;
+  if (isolate_ != nullptr) {
+    isolate_->mutator_thread()->field_table_values_ = table_;
   }
 }
 
-FieldTable* FieldTable::Clone(bool is_isolate_field_table) {
-  FieldTable* clone = new FieldTable(is_isolate_field_table);
+FieldTable* FieldTable::Clone(Isolate* for_isolate) {
+  FieldTable* clone = new FieldTable(for_isolate);
   auto new_table = static_cast<InstancePtr*>(
       malloc(capacity_ * sizeof(InstancePtr)));  // NOLINT
   memmove(new_table, table_, capacity_ * sizeof(InstancePtr));
diff --git a/runtime/vm/field_table.h b/runtime/vm/field_table.h
index dde4200..4fc1ca8 100644
--- a/runtime/vm/field_table.h
+++ b/runtime/vm/field_table.h
@@ -16,17 +16,18 @@
 
 namespace dart {
 
+class Isolate;
 class Field;
 
 class FieldTable {
  public:
-  explicit FieldTable(bool is_isolate_field_table)
+  explicit FieldTable(Isolate* isolate)
       : top_(0),
         capacity_(0),
         free_head_(-1),
         table_(nullptr),
         old_tables_(new MallocGrowableArray<InstancePtr*>()),
-        is_isolate_field_table_(is_isolate_field_table) {}
+        isolate_(isolate) {}
 
   ~FieldTable();
 
@@ -56,7 +57,7 @@
   }
   void SetAt(intptr_t index, InstancePtr raw_instance);
 
-  FieldTable* Clone(bool is_isolate_field_table);
+  FieldTable* Clone(Isolate* for_isolate);
 
   void VisitObjectPointers(ObjectPointerVisitor* visitor);
 
@@ -83,10 +84,10 @@
   // so it will get freed when its are no longer in use.
   MallocGrowableArray<InstancePtr*>* old_tables_;
 
-  // Whether this table is used as a isolate-specific table of it's global field
-  // values and therefore needs to keep the cached field table in the `Thread`
-  // object up-to-date.
-  bool is_isolate_field_table_;
+  // If non-NULL, it will specify the isolate this field table belongs to.
+  // Growing the field table will keep the cached field table on the isolate's
+  // mutator thread up-to-date.
+  Isolate* isolate_;
 
   DISALLOW_COPY_AND_ASSIGN(FieldTable);
 };
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 52ce79c..96e7750 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -353,7 +353,7 @@
       store_buffer_(new StoreBuffer()),
       heap_(nullptr),
       saved_unlinked_calls_(Array::null()),
-      initial_field_table_(new FieldTable(/*is_isolate_field_table=*/false)),
+      initial_field_table_(new FieldTable(/*isolate=*/nullptr)),
       symbols_lock_(new SafepointRwLock()),
       type_canonicalization_mutex_(
           NOT_IN_PRODUCT("IsolateGroup::type_canonicalization_mutex_")),
@@ -907,6 +907,8 @@
 
 void IsolateGroup::RegisterStaticField(const Field& field,
                                        const Instance& initial_value) {
+  ASSERT(program_lock()->IsCurrentThreadWriter());
+
   ASSERT(field.is_static());
   initial_field_table()->Register(field);
   initial_field_table()->SetAt(field.field_id(), initial_value.raw());
@@ -1631,7 +1633,7 @@
       default_tag_(UserTag::null()),
       ic_miss_code_(Code::null()),
       shared_class_table_(isolate_group->shared_class_table()),
-      field_table_(new FieldTable(/*is_isolate_field_table=*/true)),
+      field_table_(new FieldTable(/*isolate=*/this)),
       isolate_group_(isolate_group),
       isolate_object_store_(
           new IsolateObjectStore(isolate_group->object_store())),
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index ccd43d8..cc5e5c1 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -3065,7 +3065,11 @@
   const Field& field = Field::Handle(Field::New(
       field_name, true, false, false, true, false, cls, Object::dynamic_type(),
       TokenPosition::kMinSource, TokenPosition::kMinSource));
-  thread->isolate_group()->RegisterStaticField(field, Instance::sentinel());
+  {
+    SafepointWriteRwLocker locker(thread,
+                                  thread->isolate_group()->program_lock());
+    thread->isolate_group()->RegisterStaticField(field, Instance::sentinel());
+  }
   return field.raw();
 }
 
diff --git a/sdk/lib/_internal/vm/lib/growable_array.dart b/sdk/lib/_internal/vm/lib/growable_array.dart
index 537fb34..865b874 100644
--- a/sdk/lib/_internal/vm/lib/growable_array.dart
+++ b/sdk/lib/_internal/vm/lib/growable_array.dart
@@ -261,7 +261,7 @@
   void add(T value) {
     var len = length;
     if (len == _capacity) {
-      _grow(_nextCapacity(len));
+      _growToNextCapacity();
     }
     _setLength(len + 1);
     this[len] = value;
@@ -310,7 +310,7 @@
         if (this.length != newLen) throw new ConcurrentModificationError(this);
         len = newLen;
       }
-      _grow(_nextCapacity(_capacity));
+      _growToNextCapacity();
     } while (true);
   }
 
@@ -370,6 +370,14 @@
     _setData(newData);
   }
 
+  // This method is marked as never-inline to conserve code size.
+  // It is called in rare cases, but used in the add() which is
+  // used very often and always inlined.
+  @pragma("vm:never-inline")
+  void _growToNextCapacity() {
+    _grow(_nextCapacity(_capacity));
+  }
+
   void _shrink(int new_capacity, int new_length) {
     var newData = _allocateData(new_capacity);
     // This is a work-around for dartbug.com/30090. See the comment in _grow.
diff --git a/sdk/lib/ffi/struct.dart b/sdk/lib/ffi/struct.dart
index 0faf7ca..da034ef 100644
--- a/sdk/lib/ffi/struct.dart
+++ b/sdk/lib/ffi/struct.dart
@@ -4,19 +4,48 @@
 
 part of dart.ffi;
 
-/// This class is extended to define structs.
+/// The supertype of all FFI struct types.
 ///
-/// Fields in a struct, annotated with a subtype of [NativeType], are
-/// automatically transformed into wrappers to access the fields of the struct
-/// in native memory.
+/// FFI struct types should extend this class and declare fields corresponding
+/// to the underlying native structure.
 ///
-/// All fields in a struct must either have a type which extends [NativeType] or
-/// else have an annotation indicating the corresponding native type (e.g.
-/// "@Int32()" for "int").
+/// Field declarations in a [Struct] subclass declaration are automatically
+/// given a setter and getter implementation which accesses the native struct's
+/// field in memory.
+///
+/// All field declarations in a [Struct] subclass declaration must either have
+/// type [int] or [float] and be annotated with a [NativeType] representing the
+/// native type, or must be of type [Pointer]. For example:
+///
+/// ```
+/// typedef struct {
+///  int a;
+///  float b;
+///  void* c;
+/// } my_struct;
+/// ```
+///
+/// ```
+/// class MyStruct extends Struct {
+///   @Int32
+///   external int a;
+///
+///   @Float
+///   external double b;
+///
+///   external Pointer<Void> c;
+/// }
+/// ```
+///
+/// All field declarations in a [Struct] subclass declaration must be marked
+/// `external`. You cannot create instances of the class, only have it point to
+/// existing native memory, so there is no memory in which to store non-native
+/// fields. External fields also cannot be initialized by constructors since no
+/// Dart object is being created.
 ///
 /// Instances of a subclass of [Struct] have reference semantics and are backed
 /// by native memory. The may allocated via allocation or loaded from a
-/// [Pointer], but not by a generative constructor.
+/// [Pointer], but cannot be created by a generative constructor.
 abstract class Struct extends NativeType {
   final Object _addressOf;
 
diff --git a/tests/language/async/return_throw_test.dart b/tests/language/async/return_throw_test.dart
new file mode 100644
index 0000000..43c9271
--- /dev/null
+++ b/tests/language/async/return_throw_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2020, 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 "package:expect/expect.dart";
+
+Future<String> f() async {
+  throw 'f';
+}
+
+Future<String> g() async {
+  try {
+    // Should obtain the `Future<String>`, await it, then throw.
+    return f();
+  } catch (e) {
+    // Having caught the exception, we return a value.
+    return 'g';
+  }
+}
+
+void main() async {
+  Expect.equals('g', await g());
+}
diff --git a/tests/language_2/async/return_throw_test.dart b/tests/language_2/async/return_throw_test.dart
new file mode 100644
index 0000000..43c9271
--- /dev/null
+++ b/tests/language_2/async/return_throw_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2020, 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 "package:expect/expect.dart";
+
+Future<String> f() async {
+  throw 'f';
+}
+
+Future<String> g() async {
+  try {
+    // Should obtain the `Future<String>`, await it, then throw.
+    return f();
+  } catch (e) {
+    // Having caught the exception, we return a value.
+    return 'g';
+  }
+}
+
+void main() async {
+  Expect.equals('g', await g());
+}
diff --git a/tools/VERSION b/tools/VERSION
index c7c1689..4f60b94 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 117
+PRERELEASE 118
 PRERELEASE_PATCH 0
\ No newline at end of file