Version 2.12.0-142.0.dev

Merge commit '690ae7a7ba4f8038dcf58721411beb673c860438' into 'dev'
diff --git a/BUILD.gn b/BUILD.gn
index 3962d40..1140b668 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -159,16 +159,64 @@
   import("third_party/fuchsia/sdk/linux/build/component.gni")
   import("third_party/fuchsia/sdk/linux/build/package.gni")
 
-  fuchsia_component("fuchsia_test_component") {
-    testonly = true
-    data_deps = [ "runtime/bin:dart" ]
-    manifest = "build/fuchsia/dart.cmx"
+  template("dart_fuchsia_test_package") {
+    fuchsia_package(target_name) {
+      package_name = invoker.package_name
+      if (is_debug) {
+        package_name += "_debug"
+      } else if (is_release) {
+        package_name += "_release"
+      } else if (is_product) {
+        package_name += "_product"
+      }
+      testonly = true
+      deps = invoker.deps
+    }
+  }
 
-    resource_files = [
-      ".dart_tool/package_config.json",
-      "pkg/testing/test/hello_test.dart",
-      "tools/addlatexhash.dart",
-    ]
+  template("dart_fuchsia_test_component") {
+    fuchsia_component(target_name) {
+      testonly = true
+      data_deps = [ "runtime/bin:dart" ]
+      if (defined(invoker.data_deps)) {
+        data_deps += invoker.data_deps
+      }
+      manifest = "build/fuchsia/dart.cmx"
+
+      library_files = []
+      if (defined(invoker.library_files)) {
+        library_files += invoker.library_files
+      }
+      resource_files = [
+        ".dart_tool/package_config.json",
+        "pkg/testing/test/hello_test.dart",
+        "tools/addlatexhash.dart",
+      ]
+      resource_dirs = invoker.resource_dirs
+
+      resources = []
+      foreach(file, library_files) {
+        resources += [
+          {
+            path = root_out_dir + "/" + file
+            dest = "lib/" + file
+          },
+        ]
+      }
+      foreach(file, resource_files) {
+        resources += [
+          {
+            path = file
+            dest = "data/" + file
+          },
+        ]
+      }
+      resources +=
+          exec_script("tools/fuchsia/find_resources.py", resource_dirs, "json")
+    }
+  }
+
+  dart_fuchsia_test_component("fuchsia_test_component") {
     resource_dirs = [
       "tests/standalone_2",
       "pkg/async_helper",
@@ -190,30 +238,32 @@
       "third_party/pkg/string_scanner",
       "third_party/pkg/typed_data",
     ]
-
-    resources = []
-    foreach(file, resource_files) {
-      resources += [
-        {
-          path = file
-          dest = "data/" + file
-        },
-      ]
-    }
-    resources +=
-        exec_script("tools/fuchsia/find_resources.py", resource_dirs, "json")
   }
 
-  fuchsia_package("fuchsia_test_package") {
-    package_name = "dart_test_"
-    if (is_debug) {
-      package_name += "debug"
-    } else if (is_release) {
-      package_name += "release"
-    } else if (is_product) {
-      package_name += "product"
-    }
-    testonly = true
+  dart_fuchsia_test_package("fuchsia_test_package") {
+    package_name = "dart_test"
     deps = [ ":fuchsia_test_component" ]
   }
+
+  dart_fuchsia_test_component("fuchsia_ffi_test_component") {
+    data_deps = [
+      "runtime/bin:ffi_test_dynamic_library",
+      "runtime/bin:ffi_test_functions",
+    ]
+    library_files = [
+      "libffi_test_dynamic_library.so",
+      "libffi_test_functions.so",
+    ]
+    resource_dirs = [
+      "pkg/expect",
+      "pkg/meta",
+      "tests/ffi",
+      "third_party/pkg/ffi",
+    ]
+  }
+
+  dart_fuchsia_test_package("fuchsia_ffi_test_package") {
+    package_name = "dart_ffi_test"
+    deps = [ ":fuchsia_ffi_test_component" ]
+  }
 }
diff --git a/DEPS b/DEPS
index 4c67d48..66b4294 100644
--- a/DEPS
+++ b/DEPS
@@ -565,7 +565,7 @@
     "packages": [
       {
       "package": "fuchsia/sdk/gn/linux-amd64",
-      "version": "git_revision:8d5242d4f6ff8b7634b492700e60b0fd09abefa3"
+      "version": "git_revision:e0a61431eb6e28d31d293cbb0c12f6b3a089bba4"
       }
     ],
     "condition": 'host_os == "linux" and host_cpu == "x64"',
diff --git a/build/toolchain/fuchsia/BUILD.gn b/build/toolchain/fuchsia/BUILD.gn
index 2901377..b067bf4 100644
--- a/build/toolchain/fuchsia/BUILD.gn
+++ b/build/toolchain/fuchsia/BUILD.gn
@@ -17,9 +17,10 @@
 }
 
 toolchain("fuchsia") {
-  assert(target_cpu == "x64", "We currently only support 'x64' for fuchsia.")
+  assert(target_cpu == "x64" || target_cpu == "arm64",
+         "We currently only support 'x64' and 'arm64' for fuchsia.")
   toolchain_bin =
-      rebase_path("//buildtools/$host_os-$target_cpu/clang/bin", root_out_dir)
+      rebase_path("//buildtools/$host_os-x64/clang/bin", root_out_dir)
   fuchsia_sdk = rebase_path("//third_party/fuchsia/sdk/$host_os", root_out_dir)
 
   # We can't do string interpolation ($ in strings) on things with dots in
@@ -34,6 +35,10 @@
   strip = "${toolchain_bin}/llvm-strip"
 
   target_triple_flags = "--target=x86_64-fuchsia"
+  if (target_cpu == "arm64") {
+    target_triple_flags = "--target=aarch64-fuchsia"
+  }
+
   sysroot_flags = "--sysroot ${fuchsia_sdk}/arch/${target_cpu}/sysroot"
   lto_flags = ""
 
@@ -129,6 +134,11 @@
     exename = "{{target_output_name}}{{output_extension}}"
     outfile = "{{root_out_dir}}/$exename"
     rspfile = "$outfile.rsp"
+
+    # Note that the unstripped_outfile is in the exe.stripped folder.
+    # We should probably clean this up, but changing this and dart.cmx
+    # to point ./dart instead of ./exe.stripped/dart makes the build
+    # fail because ./dart does not end up in the manifest file.
     unstripped_outfile = "{{root_out_dir}}/exe.stripped/$exename"
     command = "$compiler_prefix $ld $target_triple_flags $sysroot_flags $lto_flags {{ldflags}} -o $unstripped_outfile -Wl,--build-id -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}} && ${strip} -o $outfile $unstripped_outfile"
     description = "LINK $outfile"
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
index 7fcb556..38fa836 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
@@ -41,6 +41,8 @@
       toType = parent.declaredElement.type;
     } else if (parent is ArgumentList) {
       toType = target.staticParameterElement.type;
+    } else if (parent is IndexExpression) {
+      toType = parent.realTarget.staticType;
     } else {
       return;
     }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 5995aaf..e0fed7e 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -814,6 +814,9 @@
       CreateClass.newInstance,
       CreateMixin.newInstance,
     ],
+    CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE: [
+      AddNullCheck.newInstance,
+    ],
     CompileTimeErrorCode.UNDEFINED_ANNOTATION: [
       ChangeTo.annotation,
       CreateClass.newInstance,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
index dc640e4..4dd8288 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
@@ -97,6 +97,19 @@
 ''');
   }
 
+  Future<void> test_indexExpression() async {
+    await resolveTestCode('''
+void f (List<String>? args) {
+  print(args[0]);
+}
+''');
+    await assertHasFix('''
+void f (List<String>? args) {
+  print(args![0]);
+}
+''');
+  }
+
   Future<void> test_initializer() async {
     await resolveTestCode('''
 void f(int? x) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index ede2b69..d1c4f9d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -3973,7 +3973,8 @@
   /// name.
   void pushQualifiedReference(Token start, Token periodBeforeName) {
     assert(checkState(start, [
-      /*suffix*/ if (periodBeforeName != null) ValueKinds.Identifier,
+      /*suffix*/ if (periodBeforeName != null)
+        unionOfKinds([ValueKinds.Identifier, ValueKinds.ParserRecovery]),
       /*type arguments*/ ValueKinds.TypeArgumentsOrNull,
       /*type*/ unionOfKinds([
         ValueKinds.Generator,
@@ -3982,7 +3983,18 @@
         ValueKinds.ParserRecovery
       ])
     ]));
-    Identifier suffix = popIfNotNull(periodBeforeName);
+    Object suffixObject = popIfNotNull(periodBeforeName);
+    Identifier suffix;
+    if (suffixObject is Identifier) {
+      suffix = suffixObject;
+    } else {
+      assert(
+          suffixObject == null || suffixObject is ParserRecovery,
+          "Unexpected qualified name suffix $suffixObject "
+          "(${suffixObject.runtimeType})");
+      // There was a `.` without a suffix.
+    }
+
     Identifier identifier;
     List<UnresolvedType> typeArguments = pop();
     Object type = pop();
diff --git a/pkg/front_end/testcases/general/issue44347.dart b/pkg/front_end/testcases/general/issue44347.dart
new file mode 100644
index 0000000..0389b03
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue44347.dart
@@ -0,0 +1,9 @@
+// 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.
+
+test() {
+  Set<int>.();
+}
+
+main() {}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/issue44347.dart.outline.expect b/pkg/front_end/testcases/general/issue44347.dart.outline.expect
new file mode 100644
index 0000000..a29647d
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue44347.dart.outline.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static method test() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/issue44347.dart.strong.expect b/pkg/front_end/testcases/general/issue44347.dart.strong.expect
new file mode 100644
index 0000000..df1f308
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue44347.dart.strong.expect
@@ -0,0 +1,17 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue44347.dart:6:12: Error: Expected an identifier, but got '('.
+// Try inserting an identifier before '('.
+//   Set<int>.();
+//            ^
+//
+import self as self;
+import "dart:collection" as col;
+import "dart:core" as core;
+
+static method test() → dynamic {
+  col::LinkedHashSet::•<core::int*>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/issue44347.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue44347.dart.strong.transformed.expect
new file mode 100644
index 0000000..a3adab2
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue44347.dart.strong.transformed.expect
@@ -0,0 +1,17 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue44347.dart:6:12: Error: Expected an identifier, but got '('.
+// Try inserting an identifier before '('.
+//   Set<int>.();
+//            ^
+//
+import self as self;
+import "dart:collection" as col;
+import "dart:core" as core;
+
+static method test() → dynamic {
+  new col::_CompactLinkedHashSet::•<core::int*>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/issue44347.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue44347.dart.textual_outline.expect
new file mode 100644
index 0000000..ec6b9e0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue44347.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+test() {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue44347.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue44347.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..f67dbb0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue44347.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+main() {}
+test() {}
diff --git a/runtime/lib/ffi_dynamic_library.cc b/runtime/lib/ffi_dynamic_library.cc
index ac11bd9..c95e972 100644
--- a/runtime/lib/ffi_dynamic_library.cc
+++ b/runtime/lib/ffi_dynamic_library.cc
@@ -9,7 +9,7 @@
 #include "vm/native_entry.h"
 
 #if !defined(HOST_OS_LINUX) && !defined(HOST_OS_MACOS) &&                      \
-    !defined(HOST_OS_ANDROID)
+    !defined(HOST_OS_ANDROID) && !defined(HOST_OS_FUCHSIA)
 // TODO(dacoharkes): Implement dynamic libraries for other targets & merge the
 // implementation with:
 // - runtime/bin/extensions.h
@@ -23,7 +23,8 @@
 namespace dart {
 
 static void* LoadExtensionLibrary(const char* library_file) {
-#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || defined(HOST_OS_ANDROID)
+#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) ||                        \
+    defined(HOST_OS_ANDROID) || defined(HOST_OS_FUCHSIA)
   void* handle = dlopen(library_file, RTLD_LAZY);
   if (handle == nullptr) {
     char* error = dlerror();
@@ -77,7 +78,8 @@
 }
 
 DEFINE_NATIVE_ENTRY(Ffi_dl_processLibrary, 0, 0) {
-#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || defined(HOST_OS_ANDROID)
+#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) ||                        \
+    defined(HOST_OS_ANDROID) || defined(HOST_OS_FUCHSIA)
   return DynamicLibrary::New(RTLD_DEFAULT);
 #else
   const Array& args = Array::Handle(Array::New(1));
@@ -93,7 +95,8 @@
 }
 
 static void* ResolveSymbol(void* handle, const char* symbol) {
-#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || defined(HOST_OS_ANDROID)
+#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) ||                        \
+    defined(HOST_OS_ANDROID) || defined(HOST_OS_FUCHSIA)
   dlerror();  // Clear any errors.
   void* pointer = dlsym(handle, symbol);
   if (pointer == nullptr) {
diff --git a/runtime/tests/vm/dart/dylib_utils.dart b/runtime/tests/vm/dart/dylib_utils.dart
index 3ac9c3f..a805b6c 100644
--- a/runtime/tests/vm/dart/dylib_utils.dart
+++ b/runtime/tests/vm/dart/dylib_utils.dart
@@ -6,7 +6,7 @@
 import 'dart:io' show Platform;
 
 String _platformPath(String name, {String path = ""}) {
-  if (Platform.isLinux || Platform.isAndroid)
+  if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia)
     return path + "lib" + name + ".so";
   if (Platform.isMacOS) return path + "lib" + name + ".dylib";
   if (Platform.isWindows) return path + name + ".dll";
diff --git a/runtime/tests/vm/dart_2/dylib_utils.dart b/runtime/tests/vm/dart_2/dylib_utils.dart
index 75ba33b..083e941 100644
--- a/runtime/tests/vm/dart_2/dylib_utils.dart
+++ b/runtime/tests/vm/dart_2/dylib_utils.dart
@@ -7,7 +7,7 @@
 
 String _platformPath(String name, {String path}) {
   if (path == null) path = "";
-  if (Platform.isLinux || Platform.isAndroid)
+  if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia)
     return path + "lib" + name + ".so";
   if (Platform.isMacOS) return path + "lib" + name + ".dylib";
   if (Platform.isWindows) return path + name + ".dll";
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 7ae73e4..c78165f 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -6213,7 +6213,7 @@
                                                    bool is_optimizing) const {
   // The temporary register needs to be callee-saved and not an argument
   // register.
-  ASSERT(((1 << CallingConventions::kFirstCalleeSavedCpuReg) &
+  ASSERT(((1 << CallingConventions::kFfiAnyNonAbiRegister) &
           CallingConventions::kArgumentRegisters) == 0);
 
   constexpr intptr_t kNumTemps = 2;
@@ -6227,8 +6227,8 @@
                       CallingConventions::kFirstNonArgumentRegister));
   summary->set_temp(0, Location::RegisterLocation(
                            CallingConventions::kSecondNonArgumentRegister));
-  summary->set_temp(1, Location::RegisterLocation(
-                           CallingConventions::kFirstCalleeSavedCpuReg));
+  summary->set_temp(
+      1, Location::RegisterLocation(CallingConventions::kFfiAnyNonAbiRegister));
   summary->set_out(0, marshaller_.LocInFfiCall(compiler::ffi::kResultIndex));
 
   for (intptr_t i = 0, n = marshaller_.num_args(); i < n; ++i) {
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 04b1857..eaf19a7 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -1390,9 +1390,7 @@
 
   __ PopNativeCalleeSavedRegisters();
 
-#if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
-#elif defined(USING_SHADOW_CALL_STACK)
+#if defined(TARGET_OS_FUCHSIA) && defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
 
@@ -1427,9 +1425,7 @@
   // Save a space for the code object.
   __ PushImmediate(0);
 
-#if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
-#elif defined(USING_SHADOW_CALL_STACK)
+#if defined(TARGET_OS_FUCHSIA) && defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
 
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 50100ea..28e03b5 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -1227,12 +1227,6 @@
 
   __ PopNativeCalleeSavedRegisters();
 
-#if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
-#elif defined(USING_SHADOW_CALL_STACK)
-#error Unimplemented
-#endif
-
   // Leave the entry frame.
   __ LeaveFrame();
 
@@ -1273,12 +1267,6 @@
   // Save a space for the code object.
   __ PushImmediate(0);
 
-#if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
-#elif defined(USING_SHADOW_CALL_STACK)
-#error Unimplemented
-#endif
-
   __ PushNativeCalleeSavedRegisters();
 
   // Load the thread object. If we were called by a trampoline, the thread is
@@ -1310,6 +1298,14 @@
   // Now that we have THR, we can set CSP.
   __ SetupCSPFromThread(THR);
 
+#if defined(TARGET_OS_FUCHSIA)
+  __ str(R18,
+         compiler::Address(
+             THR, compiler::target::Thread::saved_shadow_call_stack_offset()));
+#elif defined(USING_SHADOW_CALL_STACK)
+#error Unimplemented
+#endif
+
   // Refresh pinned registers values (inc. write barrier mask and null object).
   __ RestorePinnedRegisters();
 
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 985299e..d390e63 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -331,9 +331,7 @@
   __ popl(ESI);
   __ popl(EBX);
 
-#if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
-#elif defined(USING_SHADOW_CALL_STACK)
+#if defined(TARGET_OS_FUCHSIA) && defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
 
@@ -1068,9 +1066,7 @@
   __ xorl(EAX, EAX);
   __ pushl(EAX);
 
-#if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
-#elif defined(USING_SHADOW_CALL_STACK)
+#if defined(TARGET_OS_FUCHSIA) && defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
 
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 34af406..dfa039f 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -375,9 +375,7 @@
   // Restore C++ ABI callee-saved registers.
   __ PopRegisters(kCalleeSaveRegistersSet);
 
-#if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
-#elif defined(USING_SHADOW_CALL_STACK)
+#if defined(TARGET_OS_FUCHSIA) && defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
 
@@ -1131,9 +1129,7 @@
   // NativeReturnInstr::EmitNativeCode.
   __ EnterFrame(0);
 
-#if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
-#elif defined(USING_SHADOW_CALL_STACK)
+#if defined(TARGET_OS_FUCHSIA) && defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
 
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 5c2d42f..1605725 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -532,7 +532,7 @@
   // We choose these to avoid overlap between themselves and reserved registers.
   static constexpr Register kFirstNonArgumentRegister = R8;
   static constexpr Register kSecondNonArgumentRegister = R9;
-  static constexpr Register kFirstCalleeSavedCpuReg = R4;
+  static constexpr Register kFfiAnyNonAbiRegister = R4;
   static constexpr Register kStackPointerRegister = SPREG;
 
   COMPILE_ASSERT(
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index 5e94310..21a5b94 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -289,6 +289,8 @@
 const RegList kAbiArgumentCpuRegs =
     R(R0) | R(R1) | R(R2) | R(R3) | R(R4) | R(R5) | R(R6) | R(R7);
 #if defined(TARGET_OS_FUCHSIA)
+// We rely on R18 not bying touched by Dart generated assembly or stubs at all.
+// We rely on that any calls into C++ also preserve R18.
 const RegList kAbiPreservedCpuRegs = R(R18) | R(R19) | R(R20) | R(R21) |
                                      R(R22) | R(R23) | R(R24) | R(R25) |
                                      R(R26) | R(R27) | R(R28);
@@ -392,7 +394,7 @@
   static constexpr Register kSecondReturnReg = kNoRegister;
   static constexpr FpuRegister kReturnFpuReg = V0;
 
-  static constexpr Register kFirstCalleeSavedCpuReg = kAbiFirstPreservedCpuReg;
+  static constexpr Register kFfiAnyNonAbiRegister = R19;
   static constexpr Register kFirstNonArgumentRegister = R9;
   static constexpr Register kSecondNonArgumentRegister = R10;
   static constexpr Register kStackPointerRegister = SPREG;
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index 8e47d4d..bc3c7cb 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -272,7 +272,7 @@
   // NativeReturnInstr::EmitNativeCode.
   static constexpr XmmRegister kReturnFpuReg = XMM0;
 
-  static constexpr Register kFirstCalleeSavedCpuReg = EBX;
+  static constexpr Register kFfiAnyNonAbiRegister = EBX;
   static constexpr Register kFirstNonArgumentRegister = EAX;
   static constexpr Register kSecondNonArgumentRegister = ECX;
   static constexpr Register kStackPointerRegister = SPREG;
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index 480f565..a403340 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -445,12 +445,12 @@
 
   COMPILE_ASSERT((kArgumentRegisters & kReservedCpuRegisters) == 0);
 
-  static constexpr Register kFirstCalleeSavedCpuReg = RBX;
+  static constexpr Register kFfiAnyNonAbiRegister = RBX;
   static constexpr Register kFirstNonArgumentRegister = RAX;
   static constexpr Register kSecondNonArgumentRegister = RBX;
   static constexpr Register kStackPointerRegister = SPREG;
 
-  COMPILE_ASSERT(((R(kFirstCalleeSavedCpuReg)) & kCalleeSaveCpuRegisters) != 0);
+  COMPILE_ASSERT(((R(kFfiAnyNonAbiRegister)) & kCalleeSaveCpuRegisters) != 0);
 
   COMPILE_ASSERT(
       ((R(kFirstNonArgumentRegister) | R(kSecondNonArgumentRegister)) &
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 7c58510..cefda8b 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -307,13 +307,7 @@
 
   static StringPtr GetEnvironmentValue(Thread* thread, const String& name);
 
-  static bool IsFfiEnabled() {
-#if defined(TAGET_OS_FUCHSIA)
-    return false;
-#else
-    return FLAG_enable_ffi;
-#endif
-  }
+  static bool IsFfiEnabled() { return FLAG_enable_ffi; }
 
  private:
   static Dart_Handle InitNewHandle(Thread* thread, ObjectPtr raw);
diff --git a/runtime/vm/ffi_callback_trampolines.cc b/runtime/vm/ffi_callback_trampolines.cc
index 4bf926e..169d8f8 100644
--- a/runtime/vm/ffi_callback_trampolines.cc
+++ b/runtime/vm/ffi_callback_trampolines.cc
@@ -45,10 +45,13 @@
   }
 
   if (trampolines_left_on_page_ == 0) {
+    // Fuchsia requires memory to be allocated with ZX_RIGHT_EXECUTE in order
+    // to be flipped to kReadExecute after being kReadWrite.
     VirtualMemory* const memory = VirtualMemory::AllocateAligned(
         /*size=*/VirtualMemory::PageSize(),
         /*alignment=*/VirtualMemory::PageSize(),
-        /*is_executable=*/false, /*name=*/"Dart VM FFI callback trampolines");
+        /*is_executable=*/true, /*name=*/"Dart VM FFI callback trampolines");
+    memory->Protect(VirtualMemory::kReadWrite);
 
     if (memory == nullptr) {
       Exceptions::ThrowOOM();
diff --git a/samples/ffi/dylib_utils.dart b/samples/ffi/dylib_utils.dart
index 220c0fc..77faa88 100644
--- a/samples/ffi/dylib_utils.dart
+++ b/samples/ffi/dylib_utils.dart
@@ -6,7 +6,7 @@
 import 'dart:io' show Platform;
 
 String _platformPath(String name, String path) {
-  if (Platform.isLinux || Platform.isAndroid)
+  if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia)
     return path + "lib" + name + ".so";
   if (Platform.isMacOS) return path + "lib" + name + ".dylib";
   if (Platform.isWindows) return path + name + ".dll";
diff --git a/samples/ffi/sqlite/lib/src/ffi/dylib_utils.dart b/samples/ffi/sqlite/lib/src/ffi/dylib_utils.dart
index 220c0fc..77faa88 100644
--- a/samples/ffi/sqlite/lib/src/ffi/dylib_utils.dart
+++ b/samples/ffi/sqlite/lib/src/ffi/dylib_utils.dart
@@ -6,7 +6,7 @@
 import 'dart:io' show Platform;
 
 String _platformPath(String name, String path) {
-  if (Platform.isLinux || Platform.isAndroid)
+  if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia)
     return path + "lib" + name + ".so";
   if (Platform.isMacOS) return path + "lib" + name + ".dylib";
   if (Platform.isWindows) return path + name + ".dll";
diff --git a/samples_2/ffi/dylib_utils.dart b/samples_2/ffi/dylib_utils.dart
index 39653fa..b783ad8 100644
--- a/samples_2/ffi/dylib_utils.dart
+++ b/samples_2/ffi/dylib_utils.dart
@@ -9,7 +9,7 @@
 
 String _platformPath(String name, {String path}) {
   if (path == null) path = "";
-  if (Platform.isLinux || Platform.isAndroid)
+  if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia)
     return path + "lib" + name + ".so";
   if (Platform.isMacOS) return path + "lib" + name + ".dylib";
   if (Platform.isWindows) return path + name + ".dll";
diff --git a/samples_2/ffi/sqlite/lib/src/ffi/dylib_utils.dart b/samples_2/ffi/sqlite/lib/src/ffi/dylib_utils.dart
index 39653fa..b783ad8 100644
--- a/samples_2/ffi/sqlite/lib/src/ffi/dylib_utils.dart
+++ b/samples_2/ffi/sqlite/lib/src/ffi/dylib_utils.dart
@@ -9,7 +9,7 @@
 
 String _platformPath(String name, {String path}) {
   if (path == null) path = "";
-  if (Platform.isLinux || Platform.isAndroid)
+  if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia)
     return path + "lib" + name + ".so";
   if (Platform.isMacOS) return path + "lib" + name + ".dylib";
   if (Platform.isWindows) return path + name + ".dll";
diff --git a/tests/ffi/all_positive.dart b/tests/ffi/all_positive.dart
new file mode 100644
index 0000000..d3d1db3
--- /dev/null
+++ b/tests/ffi/all_positive.dart
@@ -0,0 +1,96 @@
+// 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.
+
+// Generated by prepare_flutter_bundle.dart and not ignoring vmspecific.
+// Used in fuchsia_test_component.
+//
+// Note that we are not using any VM flags here, so we are not exercising GC
+// corner cases etc. However, we are mainly interested in exercising the
+// calling convention on Fuchsia.
+
+import "dart:async";
+
+import "aliasing_test.dart" as main0;
+import "data_not_asan_test.dart" as main1;
+import "data_test.dart" as main2;
+import "dylib_isolates_test.dart" as main3;
+import "extension_methods_test.dart" as main4;
+import "external_typed_data_test.dart" as main5;
+import "function_callbacks_many_test.dart" as main6;
+import "function_callbacks_test.dart" as main7;
+import "function_callbacks_very_many_test.dart" as main8;
+import "function_structs_test.dart" as main9;
+import "function_test.dart" as main10;
+import "function_very_many_test.dart" as main11;
+import "hardfp_test.dart" as main12;
+import "negative_function_test.dart" as main13;
+import "regress_37254_test.dart" as main16;
+import "regress_39044_test.dart" as main17;
+import "regress_39063_test.dart" as main18;
+import "regress_39885_test.dart" as main19;
+import "regress_40537_test.dart" as main20;
+import "regress_43016_test.dart" as main21;
+import "regress_43693_test.dart" as main22;
+import "regress_jump_to_frame_test.dart" as main23;
+import "sizeof_test.dart" as main24;
+import "snapshot_test.dart" as main25;
+import "stacktrace_regress_37910_test.dart" as main26;
+import "structs_test.dart" as main27;
+import "variance_function_test.dart" as main28;
+import "vmspecific_function_callbacks_exit_test.dart" as main29;
+import "vmspecific_function_test.dart" as main30;
+import "vmspecific_handle_dynamically_linked_test.dart" as main31;
+import "vmspecific_handle_test.dart" as main32;
+import "vmspecific_object_gc_test.dart" as main34;
+import "vmspecific_regress_37100_test.dart" as main35;
+import "vmspecific_regress_37511_callbacks_test.dart" as main36;
+import "vmspecific_regress_37511_test.dart" as main37;
+import "vmspecific_regress_37780_test.dart" as main38;
+
+Future invoke(dynamic fun) async {
+  if (fun is void Function() || fun is Future Function()) {
+    return await fun();
+  } else {
+    return await fun(<String>[]);
+  }
+}
+
+dynamic main() async {
+  await invoke(main0.main);
+  await invoke(main1.main);
+  await invoke(main2.main);
+  await invoke(main3.main);
+  await invoke(main4.main);
+  await invoke(main5.main);
+  await invoke(main6.main);
+  await invoke(main7.main);
+  await invoke(main8.main);
+  await invoke(main9.main);
+  await invoke(main10.main);
+  await invoke(main11.main);
+  await invoke(main12.main);
+  await invoke(main13.main);
+  await invoke(main16.main);
+  await invoke(main17.main);
+  await invoke(main18.main);
+  await invoke(main19.main);
+  await invoke(main20.main);
+  await invoke(main21.main);
+  await invoke(main22.main);
+  await invoke(main23.main);
+  await invoke(main24.main);
+  await invoke(main25.main);
+  await invoke(main26.main);
+  await invoke(main27.main);
+  await invoke(main28.main);
+  await invoke(main29.main);
+  await invoke(main30.main);
+  await invoke(main31.main);
+  await invoke(main32.main);
+  await invoke(main34.main);
+  await invoke(main35.main);
+  await invoke(main36.main);
+  await invoke(main37.main);
+  await invoke(main38.main);
+}
diff --git a/tests/ffi/dylib_utils.dart b/tests/ffi/dylib_utils.dart
index 2b7ac27..c2c8db8 100644
--- a/tests/ffi/dylib_utils.dart
+++ b/tests/ffi/dylib_utils.dart
@@ -7,7 +7,7 @@
 
 String _platformPath(String name, {String? path}) {
   if (path == null) path = "";
-  if (Platform.isLinux || Platform.isAndroid)
+  if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia)
     return path + "lib" + name + ".so";
   if (Platform.isMacOS) return path + "lib" + name + ".dylib";
   if (Platform.isWindows) return path + name + ".dll";
diff --git a/tests/ffi_2/all_positive.dart b/tests/ffi_2/all_positive.dart
new file mode 100644
index 0000000..699add9
--- /dev/null
+++ b/tests/ffi_2/all_positive.dart
@@ -0,0 +1,102 @@
+// 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.
+
+// Generated by prepare_flutter_bundle.dart and not ignoring vmspecific.
+// Used in fuchsia_test_component.
+//
+// Note that we are not using any VM flags here, so we are not exercising GC
+// corner cases etc. However, we are mainly interested in exercising the
+// calling convention on Fuchsia.
+
+import "dart:async";
+
+import "aliasing_test.dart" as main0;
+import "data_not_asan_test.dart" as main1;
+import "data_test.dart" as main2;
+import "dylib_isolates_test.dart" as main3;
+import "extension_methods_test.dart" as main4;
+import "external_typed_data_test.dart" as main5;
+import "function_callbacks_many_test.dart" as main6;
+import "function_callbacks_test.dart" as main7;
+import "function_callbacks_very_many_test.dart" as main8;
+import "function_structs_test.dart" as main9;
+import "function_test.dart" as main10;
+import "function_very_many_test.dart" as main11;
+import "hardfp_test.dart" as main12;
+import "negative_function_test.dart" as main13;
+import "null_regress_39068_test.dart" as main14;
+import "null_test.dart" as main15;
+import "regress_37254_test.dart" as main16;
+import "regress_39044_test.dart" as main17;
+import "regress_39063_test.dart" as main18;
+import "regress_39885_test.dart" as main19;
+import "regress_40537_test.dart" as main20;
+import "regress_43016_test.dart" as main21;
+import "regress_43693_test.dart" as main22;
+import "regress_jump_to_frame_test.dart" as main23;
+import "sizeof_test.dart" as main24;
+import "snapshot_test.dart" as main25;
+import "stacktrace_regress_37910_test.dart" as main26;
+import "structs_test.dart" as main27;
+import "variance_function_test.dart" as main28;
+import "vmspecific_function_callbacks_exit_test.dart" as main29;
+import "vmspecific_function_test.dart" as main30;
+import "vmspecific_handle_dynamically_linked_test.dart" as main31;
+import "vmspecific_handle_test.dart" as main32;
+import "vmspecific_null_test.dart" as main33;
+import "vmspecific_object_gc_test.dart" as main34;
+import "vmspecific_regress_37100_test.dart" as main35;
+import "vmspecific_regress_37511_callbacks_test.dart" as main36;
+import "vmspecific_regress_37511_test.dart" as main37;
+import "vmspecific_regress_37780_test.dart" as main38;
+
+Future invoke(dynamic fun) async {
+  if (fun is void Function() || fun is Future Function()) {
+    return await fun();
+  } else {
+    return await fun(<String>[]);
+  }
+}
+
+dynamic main() async {
+  await invoke(main0.main);
+  await invoke(main1.main);
+  await invoke(main2.main);
+  await invoke(main3.main);
+  await invoke(main4.main);
+  await invoke(main5.main);
+  await invoke(main6.main);
+  await invoke(main7.main);
+  await invoke(main8.main);
+  await invoke(main9.main);
+  await invoke(main10.main);
+  await invoke(main11.main);
+  await invoke(main12.main);
+  await invoke(main13.main);
+  await invoke(main14.main);
+  await invoke(main15.main);
+  await invoke(main16.main);
+  await invoke(main17.main);
+  await invoke(main18.main);
+  await invoke(main19.main);
+  await invoke(main20.main);
+  await invoke(main21.main);
+  await invoke(main22.main);
+  await invoke(main23.main);
+  await invoke(main24.main);
+  await invoke(main25.main);
+  await invoke(main26.main);
+  await invoke(main27.main);
+  await invoke(main28.main);
+  await invoke(main29.main);
+  await invoke(main30.main);
+  await invoke(main31.main);
+  await invoke(main32.main);
+  await invoke(main33.main);
+  await invoke(main34.main);
+  await invoke(main35.main);
+  await invoke(main36.main);
+  await invoke(main37.main);
+  await invoke(main38.main);
+}
diff --git a/tests/ffi_2/dylib_utils.dart b/tests/ffi_2/dylib_utils.dart
index fb8153a..c6f9127 100644
--- a/tests/ffi_2/dylib_utils.dart
+++ b/tests/ffi_2/dylib_utils.dart
@@ -7,7 +7,7 @@
 
 String _platformPath(String name, {String path}) {
   if (path == null) path = "";
-  if (Platform.isLinux || Platform.isAndroid)
+  if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia)
     return path + "lib" + name + ".so";
   if (Platform.isMacOS) return path + "lib" + name + ".dylib";
   if (Platform.isWindows) return path + name + ".dll";
diff --git a/tools/VERSION b/tools/VERSION
index d086c9e..ad81f86 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 141
+PRERELEASE 142
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index ae3f53f..2bf93261 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -693,7 +693,6 @@
         "host-checked": true
       }
     },
-
     "dart2js-hostasserts-strong-mac-x64-(d8|chrome)": {
       "options": {
         "builder-tag": "dart2js-strong",
@@ -1743,8 +1742,11 @@
           "script": "tools/build.py",
           "arguments": [
             "--os=fuchsia",
+            "--arch=x64,arm64",
             "runtime",
-            "create_sdk"
+            "create_sdk",
+            "fuchsia_test_package",
+            "fuchsia_ffi_test_package"
           ]
         }
       ]
diff --git a/tools/gn.py b/tools/gn.py
index 161c35a..f315ade 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -68,9 +68,7 @@
 
 
 def HostCpuForArch(arch):
-    if arch in [
-            'ia32', 'arm', 'armv6', 'simarm', 'simarmv6', 'simarm_x64'
-    ]:
+    if arch in ['ia32', 'arm', 'armv6', 'simarm', 'simarmv6', 'simarm_x64']:
         return 'x86'
     if arch in ['x64', 'arm64', 'simarm64', 'arm_x64']:
         return 'x64'
@@ -119,6 +117,7 @@
             return l[1]
     return None
 
+
 def UseSysroot(args, gn_args):
     # Don't try to use a Linux sysroot if we aren't on Linux.
     if gn_args['target_os'] != 'linux' and HOST_OS != 'linux':
@@ -319,22 +318,22 @@
             return False
         if os_name == 'android':
             if not HOST_OS in ['linux', 'macos']:
-                print("Cross-compilation to %s is not supported on host os %s."
-                      % (os_name, HOST_OS))
+                print(
+                    "Cross-compilation to %s is not supported on host os %s." %
+                    (os_name, HOST_OS))
                 return False
-            if not arch in [
-                    'ia32', 'x64', 'arm', 'arm_x64', 'armv6', 'arm64'
-            ]:
+            if not arch in ['ia32', 'x64', 'arm', 'arm_x64', 'armv6', 'arm64']:
                 print(
                     "Cross-compilation to %s is not supported for architecture %s."
                     % (os_name, arch))
                 return False
         elif os_name == 'fuchsia':
             if HOST_OS != 'linux':
-                print("Cross-compilation to %s is not supported on host os %s."
-                      % (os_name, HOST_OS))
+                print(
+                    "Cross-compilation to %s is not supported on host os %s." %
+                    (os_name, HOST_OS))
                 return False
-            if arch != 'x64':
+            if arch != 'x64' and arch != 'arm64':
                 print(
                     "Cross-compilation to %s is not supported for architecture %s."
                     % (os_name, arch))