Version 2.16.0-58.0.dev

Merge commit '35202a3c5fd3d4ab80ba51d60f87b42068f1bb3a' into 'dev'
diff --git a/benchmarks/FfiAsTypedList/dart/FfiAsTypedList.dart b/benchmarks/FfiAsTypedList/dart/FfiAsTypedList.dart
new file mode 100644
index 0000000..f32f5d0
--- /dev/null
+++ b/benchmarks/FfiAsTypedList/dart/FfiAsTypedList.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2021, 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.
+
+// Micro-benchmark for creating TypeData lists from Pointers.
+//
+// The FfiMemory benchmark tests accessing memory through TypedData.
+
+import 'dart:ffi';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:ffi/ffi.dart';
+
+//
+// Benchmark fixture.
+//
+
+// Number of repeats: 1000
+const N = 1000;
+
+class FromPointerInt8 extends BenchmarkBase {
+  Pointer<Int8> pointer = nullptr;
+  FromPointerInt8() : super('FfiAsTypedList.FromPointerInt8');
+
+  @override
+  void setup() => pointer = calloc(1);
+  @override
+  void teardown() => calloc.free(pointer);
+
+  @override
+  void run() {
+    for (var i = 0; i < N; i++) {
+      pointer.asTypedList(1);
+    }
+  }
+}
+
+//
+// Main driver.
+//
+
+void main() {
+  final benchmarks = [
+    () => FromPointerInt8(),
+  ];
+  for (final benchmark in benchmarks) {
+    benchmark().report();
+  }
+}
diff --git a/benchmarks/FfiAsTypedList/dart2/FfiAsTypedList.dart b/benchmarks/FfiAsTypedList/dart2/FfiAsTypedList.dart
new file mode 100644
index 0000000..bab621d
--- /dev/null
+++ b/benchmarks/FfiAsTypedList/dart2/FfiAsTypedList.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2021, 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.
+
+// Micro-benchmark for creating TypeData lists from Pointers.
+//
+// The FfiMemory benchmark tests accessing memory through TypedData.
+
+// @dart=2.9
+
+import 'dart:ffi';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:ffi/ffi.dart';
+
+//
+// Benchmark fixture.
+//
+
+// Number of repeats: 1000
+const N = 1000;
+
+class FromPointerInt8 extends BenchmarkBase {
+  Pointer<Int8> pointer = nullptr;
+  FromPointerInt8() : super('FfiAsTypedList.FromPointerInt8');
+
+  @override
+  void setup() => pointer = calloc(1);
+  @override
+  void teardown() => calloc.free(pointer);
+
+  @override
+  void run() {
+    for (var i = 0; i < N; i++) {
+      pointer.asTypedList(1);
+    }
+  }
+}
+
+//
+// Main driver.
+//
+
+void main() {
+  final benchmarks = [
+    () => FromPointerInt8(),
+  ];
+  for (final benchmark in benchmarks) {
+    benchmark().report();
+  }
+}
diff --git a/pkg/test_runner/lib/src/fuchsia.dart b/pkg/test_runner/lib/src/fuchsia.dart
index a3880c5..aeeab96 100644
--- a/pkg/test_runner/lib/src/fuchsia.dart
+++ b/pkg/test_runner/lib/src/fuchsia.dart
@@ -11,11 +11,13 @@
 
 class FuchsiaEmulator {
   static final Uri toolsDir =
+      Repository.uri.resolve('third_party/fuchsia/sdk/linux/tools/x64/');
+  static final Uri scriptsDir =
       Repository.uri.resolve('third_party/fuchsia/sdk/linux/bin/');
-  static final String femuTool = toolsDir.resolve('femu.sh').toFilePath();
-  static final String fserveTool = toolsDir.resolve('fserve.sh').toFilePath();
-  static final String fpubTool = toolsDir.resolve('fpublish.sh').toFilePath();
-  static final String fsshTool = toolsDir.resolve('fssh.sh').toFilePath();
+  static final String femuTool = scriptsDir.resolve('femu.sh').toFilePath();
+  static final String fserveTool = toolsDir.resolve('fserve').toFilePath();
+  static final String fpubTool = toolsDir.resolve('fpublish').toFilePath();
+  static final String fsshTool = toolsDir.resolve('fssh').toFilePath();
   static final RegExp emulatorReadyPattern =
       RegExp(r'Using unique host name (.+)\.local\.');
   static final RegExp emulatorPidPattern =
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index 239f758..9f0bf75 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -68,91 +68,10 @@
   UNREACHABLE();
 }
 
-DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData, 0, 2) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
-  GET_NON_NULL_NATIVE_ARGUMENT(Integer, count, arguments->NativeArgAt(1));
-  const auto& pointer_type_arg = AbstractType::Handle(pointer.type_argument());
-  const classid_t type_cid = pointer_type_arg.type_class_id();
-  classid_t cid = 0;
-
-  switch (type_cid) {
-    case kFfiInt8Cid:
-      cid = kExternalTypedDataInt8ArrayCid;
-      break;
-    case kFfiUint8Cid:
-      cid = kExternalTypedDataUint8ArrayCid;
-      break;
-    case kFfiInt16Cid:
-      cid = kExternalTypedDataInt16ArrayCid;
-      break;
-    case kFfiUint16Cid:
-      cid = kExternalTypedDataUint16ArrayCid;
-      break;
-    case kFfiInt32Cid:
-      cid = kExternalTypedDataInt32ArrayCid;
-      break;
-    case kFfiUint32Cid:
-      cid = kExternalTypedDataUint32ArrayCid;
-      break;
-    case kFfiInt64Cid:
-      cid = kExternalTypedDataInt64ArrayCid;
-      break;
-    case kFfiUint64Cid:
-      cid = kExternalTypedDataUint64ArrayCid;
-      break;
-    case kFfiIntPtrCid:
-      cid = kWordSize == 4 ? kExternalTypedDataInt32ArrayCid
-                           : kExternalTypedDataInt64ArrayCid;
-      break;
-    case kFfiFloatCid:
-      cid = kExternalTypedDataFloat32ArrayCid;
-      break;
-    case kFfiDoubleCid:
-      cid = kExternalTypedDataFloat64ArrayCid;
-      break;
-    default: {
-      const String& error = String::Handle(
-          String::NewFormatted("Cannot create a TypedData from a Pointer to %s",
-                               pointer_type_arg.ToCString()));
-      Exceptions::ThrowArgumentError(error);
-      UNREACHABLE();
-    }
-  }
-
-  const intptr_t element_count = count.AsInt64Value();
-
-  if (element_count < 0 ||
-      element_count > ExternalTypedData::MaxElements(cid)) {
-    const String& error = String::Handle(
-        String::NewFormatted("Count must be in the range [0, %" Pd "].",
-                             ExternalTypedData::MaxElements(cid)));
-    Exceptions::ThrowArgumentError(error);
-  }
-
-  // The address must be aligned by the element size.
-  const intptr_t element_size = ExternalTypedData::ElementSizeFor(cid);
-  if (!Utils::IsAligned(pointer.NativeAddress(), element_size)) {
-    const String& error = String::Handle(
-        String::NewFormatted("Pointer address must be aligned to a multiple of"
-                             "the element size (%" Pd ").",
-                             element_size));
-    Exceptions::ThrowArgumentError(error);
-  }
-
-  const auto& typed_data_class =
-      Class::Handle(zone, isolate->group()->class_table()->At(cid));
-  const auto& error =
-      Error::Handle(zone, typed_data_class.EnsureIsAllocateFinalized(thread));
-  if (!error.IsNull()) {
-    Exceptions::PropagateError(error);
-  }
-
-  // We disable msan initialization check because the memory may not be
-  // initialized yet - dart code might do that later on.
-  return ExternalTypedData::New(
-      cid, reinterpret_cast<uint8_t*>(pointer.NativeAddress()), element_count,
-      Heap::kNew, /*perform_eager_msan_initialization_check=*/false);
-}
+#define DEFINE_NATIVE_ENTRY_AS_EXTERNAL_TYPED_DATA(type)                       \
+  DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData##type, 0, 2) { UNREACHABLE(); }
+CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(DEFINE_NATIVE_ENTRY_AS_EXTERNAL_TYPED_DATA)
+#undef DEFINE_NATIVE_ENTRY_AS_EXTERNAL_TYPED_DATA
 
 DEFINE_NATIVE_ENTRY(Ffi_nativeCallbackFunction, 1, 2) {
 #if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
diff --git a/runtime/tools/ffi/sdk_lib_ffi_generator.dart b/runtime/tools/ffi/sdk_lib_ffi_generator.dart
index d44c2ec..d32b0a1 100644
--- a/runtime/tools/ffi/sdk_lib_ffi_generator.dart
+++ b/runtime/tools/ffi/sdk_lib_ffi_generator.dart
@@ -223,7 +223,13 @@
       ? ""
       : """
   @patch
-  $typedListType asTypedList(int elements) => _asExternalTypedData(this, elements);
+  $typedListType asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<$nativeType>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, $elementSize);
+    _checkPointerAlignment(address, $elementSize);
+    return _asExternalTypedData$nativeType(this, length);
+  }
 """;
 
   if (container == "Pointer") {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 46b44a3..adade03 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -400,7 +400,16 @@
   V(Ffi_dl_lookup, 2)                                                          \
   V(Ffi_dl_getHandle, 1)                                                       \
   V(Ffi_dl_providesSymbol, 2)                                                  \
-  V(Ffi_asExternalTypedData, 2)                                                \
+  V(Ffi_asExternalTypedDataInt8, 2)                                            \
+  V(Ffi_asExternalTypedDataInt16, 2)                                           \
+  V(Ffi_asExternalTypedDataInt32, 2)                                           \
+  V(Ffi_asExternalTypedDataInt64, 2)                                           \
+  V(Ffi_asExternalTypedDataUint8, 2)                                           \
+  V(Ffi_asExternalTypedDataUint16, 2)                                          \
+  V(Ffi_asExternalTypedDataUint32, 2)                                          \
+  V(Ffi_asExternalTypedDataUint64, 2)                                          \
+  V(Ffi_asExternalTypedDataFloat, 2)                                           \
+  V(Ffi_asExternalTypedDataDouble, 2)                                          \
   V(Ffi_dl_processLibrary, 0)                                                  \
   V(Ffi_dl_executableLibrary, 0)                                               \
   V(Ffi_GetFfiNativeResolver, 0)                                               \
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index bc52316..9b647b3 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -140,7 +140,7 @@
   V(Int32x4Array)                                                              \
   V(Float64x2Array)
 
-#define CLASS_LIST_FFI_NUMERIC(V)                                              \
+#define CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(V)                                   \
   V(Int8)                                                                      \
   V(Int16)                                                                     \
   V(Int32)                                                                     \
@@ -149,10 +149,13 @@
   V(Uint16)                                                                    \
   V(Uint32)                                                                    \
   V(Uint64)                                                                    \
-  V(IntPtr)                                                                    \
   V(Float)                                                                     \
   V(Double)
 
+#define CLASS_LIST_FFI_NUMERIC(V)                                              \
+  CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(V)                                         \
+  V(IntPtr)
+
 #define CLASS_LIST_FFI_TYPE_MARKER(V)                                          \
   CLASS_LIST_FFI_NUMERIC(V)                                                    \
   V(Void)                                                                      \
diff --git a/runtime/vm/compiler/ffi/recognized_method.cc b/runtime/vm/compiler/ffi/recognized_method.cc
index fa93dd3..f2fd7b6 100644
--- a/runtime/vm/compiler/ffi/recognized_method.cc
+++ b/runtime/vm/compiler/ffi/recognized_method.cc
@@ -45,6 +45,33 @@
   }
 }
 
+classid_t ElementExternalTypedDataCid(classid_t class_id) {
+  switch (class_id) {
+    case kFfiInt8Cid:
+      return kExternalTypedDataInt8ArrayCid;
+    case kFfiUint8Cid:
+      return kExternalTypedDataUint8ArrayCid;
+    case kFfiInt16Cid:
+      return kExternalTypedDataInt16ArrayCid;
+    case kFfiUint16Cid:
+      return kExternalTypedDataUint16ArrayCid;
+    case kFfiInt32Cid:
+      return kExternalTypedDataInt32ArrayCid;
+    case kFfiUint32Cid:
+      return kExternalTypedDataUint32ArrayCid;
+    case kFfiInt64Cid:
+      return kExternalTypedDataInt64ArrayCid;
+    case kFfiUint64Cid:
+      return kExternalTypedDataUint64ArrayCid;
+    case kFfiFloatCid:
+      return kExternalTypedDataFloat32ArrayCid;
+    case kFfiDoubleCid:
+      return kExternalTypedDataFloat64ArrayCid;
+    default:
+      UNREACHABLE();
+  }
+}
+
 classid_t RecognizedMethodTypeArgCid(MethodRecognizer::Kind kind) {
   switch (kind) {
 #define LOAD_STORE(type)                                                       \
@@ -62,6 +89,11 @@
     case MethodRecognizer::kFfiLoadPointer:
     case MethodRecognizer::kFfiStorePointer:
       return kPointerCid;
+#define AS_EXTERNAL_TYPED_DATA(type)                                           \
+  case MethodRecognizer::kFfiAsExternalTypedData##type:                        \
+    return kFfi##type##Cid;
+    CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(AS_EXTERNAL_TYPED_DATA)
+#undef AS_EXTERNAL_TYPED_DATA
     default:
       UNREACHABLE();
   }
diff --git a/runtime/vm/compiler/ffi/recognized_method.h b/runtime/vm/compiler/ffi/recognized_method.h
index 993306e..98f4a31 100644
--- a/runtime/vm/compiler/ffi/recognized_method.h
+++ b/runtime/vm/compiler/ffi/recognized_method.h
@@ -23,6 +23,10 @@
 // TypedData class id for a NativeType type, except for Void and NativeFunction.
 classid_t ElementTypedDataCid(classid_t class_id);
 
+// ExternalTypedData class id for a NativeType type, except for Void,
+// NativeFunction, IntPtr and Pointer.
+classid_t ElementExternalTypedDataCid(classid_t class_id);
+
 // Returns the kFFi<type>Cid for the recognized load/store method [kind].
 classid_t RecognizedMethodTypeArgCid(MethodRecognizer::Kind kind);
 
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 37df7be..9b0e7cf 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -838,36 +838,20 @@
     case MethodRecognizer::kTypedData_Float32x4Array_factory:
     case MethodRecognizer::kTypedData_Int32x4Array_factory:
     case MethodRecognizer::kTypedData_Float64x2Array_factory:
-    case MethodRecognizer::kFfiLoadInt8:
-    case MethodRecognizer::kFfiLoadInt16:
-    case MethodRecognizer::kFfiLoadInt32:
-    case MethodRecognizer::kFfiLoadInt64:
-    case MethodRecognizer::kFfiLoadUint8:
-    case MethodRecognizer::kFfiLoadUint16:
-    case MethodRecognizer::kFfiLoadUint32:
-    case MethodRecognizer::kFfiLoadUint64:
-    case MethodRecognizer::kFfiLoadIntPtr:
-    case MethodRecognizer::kFfiLoadFloat:
-    case MethodRecognizer::kFfiLoadFloatUnaligned:
-    case MethodRecognizer::kFfiLoadDouble:
-    case MethodRecognizer::kFfiLoadDoubleUnaligned:
-    case MethodRecognizer::kFfiLoadPointer:
-    case MethodRecognizer::kFfiStoreInt8:
-    case MethodRecognizer::kFfiStoreInt16:
-    case MethodRecognizer::kFfiStoreInt32:
-    case MethodRecognizer::kFfiStoreInt64:
-    case MethodRecognizer::kFfiStoreUint8:
-    case MethodRecognizer::kFfiStoreUint16:
-    case MethodRecognizer::kFfiStoreUint32:
-    case MethodRecognizer::kFfiStoreUint64:
-    case MethodRecognizer::kFfiStoreIntPtr:
-    case MethodRecognizer::kFfiStoreFloat:
-    case MethodRecognizer::kFfiStoreFloatUnaligned:
-    case MethodRecognizer::kFfiStoreDouble:
-    case MethodRecognizer::kFfiStoreDoubleUnaligned:
-    case MethodRecognizer::kFfiStorePointer:
+#define FFI_LOAD_STORE(type)                                                   \
+  case MethodRecognizer::kFfiLoad##type:                                       \
+  case MethodRecognizer::kFfiStore##type:
+    CLASS_LIST_FFI_NUMERIC(FFI_LOAD_STORE)
+    FFI_LOAD_STORE(FloatUnaligned)
+    FFI_LOAD_STORE(DoubleUnaligned)
+    FFI_LOAD_STORE(Pointer)
+#undef FFI_LOAD_STORE
     case MethodRecognizer::kFfiFromAddress:
     case MethodRecognizer::kFfiGetAddress:
+#define FFI_AS_EXTERNAL_TYPED_DATA(type)                                       \
+  case MethodRecognizer::kFfiAsExternalTypedData##type:
+    CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(FFI_AS_EXTERNAL_TYPED_DATA)
+#undef FFI_AS_EXTERNAL_TYPED_DATA
     case MethodRecognizer::kGetNativeField:
     case MethodRecognizer::kObjectEquals:
     case MethodRecognizer::kStringBaseLength:
@@ -1347,20 +1331,13 @@
       ASSERT_EQUAL(function.NumParameters(), 0);
       body += IntConstant(static_cast<int64_t>(compiler::ffi::TargetAbi()));
       break;
-    case MethodRecognizer::kFfiLoadInt8:
-    case MethodRecognizer::kFfiLoadInt16:
-    case MethodRecognizer::kFfiLoadInt32:
-    case MethodRecognizer::kFfiLoadInt64:
-    case MethodRecognizer::kFfiLoadUint8:
-    case MethodRecognizer::kFfiLoadUint16:
-    case MethodRecognizer::kFfiLoadUint32:
-    case MethodRecognizer::kFfiLoadUint64:
-    case MethodRecognizer::kFfiLoadIntPtr:
-    case MethodRecognizer::kFfiLoadFloat:
-    case MethodRecognizer::kFfiLoadFloatUnaligned:
-    case MethodRecognizer::kFfiLoadDouble:
-    case MethodRecognizer::kFfiLoadDoubleUnaligned:
-    case MethodRecognizer::kFfiLoadPointer: {
+#define FFI_LOAD(type) case MethodRecognizer::kFfiLoad##type:
+    CLASS_LIST_FFI_NUMERIC(FFI_LOAD)
+    FFI_LOAD(FloatUnaligned)
+    FFI_LOAD(DoubleUnaligned)
+    FFI_LOAD(Pointer)
+#undef FFI_LOAD
+    {
       const classid_t ffi_type_arg_cid =
           compiler::ffi::RecognizedMethodTypeArgCid(kind);
       const AlignmentType alignment =
@@ -1426,20 +1403,13 @@
       }
       body += DropTempsPreserveTop(1);  // Drop [arg_offset].
     } break;
-    case MethodRecognizer::kFfiStoreInt8:
-    case MethodRecognizer::kFfiStoreInt16:
-    case MethodRecognizer::kFfiStoreInt32:
-    case MethodRecognizer::kFfiStoreInt64:
-    case MethodRecognizer::kFfiStoreUint8:
-    case MethodRecognizer::kFfiStoreUint16:
-    case MethodRecognizer::kFfiStoreUint32:
-    case MethodRecognizer::kFfiStoreUint64:
-    case MethodRecognizer::kFfiStoreIntPtr:
-    case MethodRecognizer::kFfiStoreFloat:
-    case MethodRecognizer::kFfiStoreFloatUnaligned:
-    case MethodRecognizer::kFfiStoreDouble:
-    case MethodRecognizer::kFfiStoreDoubleUnaligned:
-    case MethodRecognizer::kFfiStorePointer: {
+#define FFI_STORE(type) case MethodRecognizer::kFfiStore##type:
+    CLASS_LIST_FFI_NUMERIC(FFI_STORE)
+    FFI_STORE(FloatUnaligned)
+    FFI_STORE(DoubleUnaligned)
+    FFI_STORE(Pointer)
+#undef FFI_STORE
+    {
       const classid_t ffi_type_arg_cid =
           compiler::ffi::RecognizedMethodTypeArgCid(kind);
       const AlignmentType alignment =
@@ -1549,6 +1519,45 @@
       body += Constant(Bool::False());
 #endif  // defined(ARCH_IS_64_BIT)
     } break;
+#define FFI_AS_EXTERNAL_TYPED_DATA(type)                                       \
+  case MethodRecognizer::kFfiAsExternalTypedData##type:
+    CLASS_LIST_FFI_NUMERIC_FIXED_SIZE(FFI_AS_EXTERNAL_TYPED_DATA)
+#undef FFI_AS_EXTERNAL_TYPED_DATA
+    {
+      const classid_t ffi_type_arg_cid =
+          compiler::ffi::RecognizedMethodTypeArgCid(kind);
+      const classid_t external_typed_data_cid =
+          compiler::ffi::ElementExternalTypedDataCid(ffi_type_arg_cid);
+
+      auto class_table = thread_->isolate_group()->class_table();
+      ASSERT(class_table->HasValidClassAt(external_typed_data_cid));
+      const auto& typed_data_class = Class::ZoneHandle(
+          H.zone(), class_table->At(external_typed_data_cid));
+
+      // We assume that the caller has checked that the arguments are non-null
+      // and length is in the range [0, kSmiMax/elementSize].
+      ASSERT_EQUAL(function.NumParameters(), 2);
+      LocalVariable* arg_pointer = parsed_function_->RawParameterVariable(0);
+      LocalVariable* arg_length = parsed_function_->RawParameterVariable(1);
+
+      body += AllocateObject(TokenPosition::kNoSource, typed_data_class, 0);
+      LocalVariable* typed_data_object = MakeTemporary();
+
+      // Initialize the result's length field.
+      body += LoadLocal(typed_data_object);
+      body += LoadLocal(arg_length);
+      body += StoreNativeField(Slot::TypedDataBase_length(),
+                               StoreInstanceFieldInstr::Kind::kInitializing,
+                               kNoStoreBarrier);
+
+      // Initialize the result's data pointer field.
+      body += LoadLocal(typed_data_object);
+      body += LoadLocal(arg_pointer);
+      body += LoadNativeField(Slot::Pointer_data_field());
+      body += StoreNativeField(Slot::TypedDataBase_data_field(),
+                               StoreInstanceFieldInstr::Kind::kInitializing,
+                               kNoStoreBarrier);
+    } break;
     case MethodRecognizer::kGetNativeField: {
       auto& name = String::ZoneHandle(Z, function.name());
       // Note: This method is force optimized so we can push untagged, etc.
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 3ed3608..2d60271 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -221,6 +221,16 @@
   V(::, _storePointer, FfiStorePointer, 0xea6b7751)                            \
   V(::, _fromAddress, FfiFromAddress, 0xfd8cb1cc)                              \
   V(Pointer, get:address, FfiGetAddress, 0x7cde87be)                           \
+  V(::, _asExternalTypedDataInt8, FfiAsExternalTypedDataInt8, 0x768a0698)      \
+  V(::, _asExternalTypedDataInt16, FfiAsExternalTypedDataInt16, 0xd09cf9c6)    \
+  V(::, _asExternalTypedDataInt32, FfiAsExternalTypedDataInt32, 0x38248946)    \
+  V(::, _asExternalTypedDataInt64, FfiAsExternalTypedDataInt64, 0xafaa47fb)    \
+  V(::, _asExternalTypedDataUint8, FfiAsExternalTypedDataUint8, 0x35228834)    \
+  V(::, _asExternalTypedDataUint16, FfiAsExternalTypedDataUint16, 0x89a51e3a)  \
+  V(::, _asExternalTypedDataUint32, FfiAsExternalTypedDataUint32, 0xd272dc41)  \
+  V(::, _asExternalTypedDataUint64, FfiAsExternalTypedDataUint64, 0x06be71c5)  \
+  V(::, _asExternalTypedDataFloat, FfiAsExternalTypedDataFloat, 0x6f465e0c)    \
+  V(::, _asExternalTypedDataDouble, FfiAsExternalTypedDataDouble, 0x40cdd9e1)  \
   V(::, _getNativeField, GetNativeField, 0xa0139b85)                           \
   V(::, reachabilityFence, ReachabilityFence, 0x619235c1)                      \
   V(_Utf8Decoder, _scan, Utf8DecoderScan, 0x1dcaf73d)                          \
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 6fb03db..d1fe844 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3177,8 +3177,8 @@
   // run.
   bool ForceOptimize() const {
     return IsFfiFromAddress() || IsFfiGetAddress() || IsFfiLoad() ||
-           IsFfiStore() || IsFfiTrampoline() || IsTypedDataViewFactory() ||
-           IsUtf8Scan() || IsGetNativeField();
+           IsFfiStore() || IsFfiTrampoline() || IsFfiAsExternalTypedData() ||
+           IsTypedDataViewFactory() || IsUtf8Scan() || IsGetNativeField();
   }
 
   bool CanBeInlined() const;
@@ -3510,6 +3510,12 @@
     return kind == MethodRecognizer::kFfiGetAddress;
   }
 
+  bool IsFfiAsExternalTypedData() const {
+    const auto kind = recognized_kind();
+    return MethodRecognizer::kFfiAsExternalTypedDataInt8 <= kind &&
+           kind <= MethodRecognizer::kFfiAsExternalTypedDataDouble;
+  }
+
   bool IsGetNativeField() const {
     const auto kind = recognized_kind();
     return kind == MethodRecognizer::kGetNativeField;
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index 2dcd5f8..8816c44 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -4,7 +4,7 @@
 
 // All imports must be in all FFI patch files to not depend on the order
 // the patches are applied.
-import "dart:_internal" show patch;
+import "dart:_internal" show patch, has63BitSmis;
 import 'dart:typed_data';
 import 'dart:isolate';
 
@@ -44,6 +44,29 @@
       8, // windowsX64,
     ])[_abi()];
 
+@pragma("vm:prefer-inline")
+int get _smiMax {
+  // See runtime/vm/globals.h for how smiMax is calculated.
+  final smiBits = has63BitSmis ? 62 : 30;
+  return (1 << smiBits) - 1;
+}
+
+@pragma("vm:prefer-inline")
+void _checkExternalTypedDataLength(int length, int elementSize) {
+  final maxElements = _smiMax ~/ elementSize;
+  if (length < 0 || length > maxElements) {
+    throw ArgumentError("length must be in the range [0, $maxElements].");
+  }
+}
+
+@pragma("vm:prefer-inline")
+void _checkPointerAlignment(int address, int elementSize) {
+  if (address & (elementSize - 1) != 0) {
+    throw ArgumentError("Pointer address must be aligned to a multiple of "
+        "the element size ($elementSize).");
+  }
+}
+
 @patch
 int sizeOf<T extends NativeType>() {
   // This case should have been rewritten in pre-processing.
@@ -62,8 +85,46 @@
 external DS _asFunctionInternal<DS extends Function, NS extends Function>(
     Pointer<NativeFunction<NS>> ptr, bool isLeaf);
 
-@pragma("vm:external-name", "Ffi_asExternalTypedData")
-external dynamic _asExternalTypedData(Pointer ptr, int count);
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataInt8")
+external Int8List _asExternalTypedDataInt8(Pointer<Int8> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataInt16")
+external Int16List _asExternalTypedDataInt16(Pointer<Int16> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataInt32")
+external Int32List _asExternalTypedDataInt32(Pointer<Int32> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataInt64")
+external Int64List _asExternalTypedDataInt64(Pointer<Int64> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataUint8")
+external Uint8List _asExternalTypedDataUint8(Pointer<Uint8> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataUint16")
+external Uint16List _asExternalTypedDataUint16(Pointer<Uint16> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataUint32")
+external Uint32List _asExternalTypedDataUint32(Pointer<Uint32> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataUint64")
+external Uint64List _asExternalTypedDataUint64(Pointer<Uint64> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataFloat")
+external Float32List _asExternalTypedDataFloat(Pointer<Float> ptr, int length);
+
+@pragma("vm:recognized", "other")
+@pragma("vm:external-name", "Ffi_asExternalTypedDataDouble")
+external Float64List _asExternalTypedDataDouble(
+    Pointer<Double> ptr, int length);
 
 // Returns a Function object for a native callback.
 //
@@ -406,7 +467,13 @@
   operator []=(int index, int value) => _storeInt8(this, index, value);
 
   @patch
-  Int8List asTypedList(int elements) => _asExternalTypedData(this, elements);
+  Int8List asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<Int8>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, 1);
+    _checkPointerAlignment(address, 1);
+    return _asExternalTypedDataInt8(this, length);
+  }
 }
 
 extension Int16Pointer on Pointer<Int16> {
@@ -423,7 +490,13 @@
   operator []=(int index, int value) => _storeInt16(this, 2 * index, value);
 
   @patch
-  Int16List asTypedList(int elements) => _asExternalTypedData(this, elements);
+  Int16List asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<Int16>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, 2);
+    _checkPointerAlignment(address, 2);
+    return _asExternalTypedDataInt16(this, length);
+  }
 }
 
 extension Int32Pointer on Pointer<Int32> {
@@ -440,7 +513,13 @@
   operator []=(int index, int value) => _storeInt32(this, 4 * index, value);
 
   @patch
-  Int32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+  Int32List asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<Int32>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, 4);
+    _checkPointerAlignment(address, 4);
+    return _asExternalTypedDataInt32(this, length);
+  }
 }
 
 extension Int64Pointer on Pointer<Int64> {
@@ -457,7 +536,13 @@
   operator []=(int index, int value) => _storeInt64(this, 8 * index, value);
 
   @patch
-  Int64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+  Int64List asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<Int64>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, 8);
+    _checkPointerAlignment(address, 8);
+    return _asExternalTypedDataInt64(this, length);
+  }
 }
 
 extension Uint8Pointer on Pointer<Uint8> {
@@ -474,7 +559,13 @@
   operator []=(int index, int value) => _storeUint8(this, index, value);
 
   @patch
-  Uint8List asTypedList(int elements) => _asExternalTypedData(this, elements);
+  Uint8List asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<Uint8>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, 1);
+    _checkPointerAlignment(address, 1);
+    return _asExternalTypedDataUint8(this, length);
+  }
 }
 
 extension Uint16Pointer on Pointer<Uint16> {
@@ -491,7 +582,13 @@
   operator []=(int index, int value) => _storeUint16(this, 2 * index, value);
 
   @patch
-  Uint16List asTypedList(int elements) => _asExternalTypedData(this, elements);
+  Uint16List asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<Uint16>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, 2);
+    _checkPointerAlignment(address, 2);
+    return _asExternalTypedDataUint16(this, length);
+  }
 }
 
 extension Uint32Pointer on Pointer<Uint32> {
@@ -508,7 +605,13 @@
   operator []=(int index, int value) => _storeUint32(this, 4 * index, value);
 
   @patch
-  Uint32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+  Uint32List asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<Uint32>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, 4);
+    _checkPointerAlignment(address, 4);
+    return _asExternalTypedDataUint32(this, length);
+  }
 }
 
 extension Uint64Pointer on Pointer<Uint64> {
@@ -525,7 +628,13 @@
   operator []=(int index, int value) => _storeUint64(this, 8 * index, value);
 
   @patch
-  Uint64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+  Uint64List asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<Uint64>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, 8);
+    _checkPointerAlignment(address, 8);
+    return _asExternalTypedDataUint64(this, length);
+  }
 }
 
 extension IntPtrPointer on Pointer<IntPtr> {
@@ -557,7 +666,13 @@
   operator []=(int index, double value) => _storeFloat(this, 4 * index, value);
 
   @patch
-  Float32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+  Float32List asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<Float>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, 4);
+    _checkPointerAlignment(address, 4);
+    return _asExternalTypedDataFloat(this, length);
+  }
 }
 
 extension DoublePointer on Pointer<Double> {
@@ -574,7 +689,13 @@
   operator []=(int index, double value) => _storeDouble(this, 8 * index, value);
 
   @patch
-  Float64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+  Float64List asTypedList(int length) {
+    ArgumentError.checkNotNull(this, "Pointer<Double>");
+    ArgumentError.checkNotNull(length, "length");
+    _checkExternalTypedDataLength(length, 8);
+    _checkPointerAlignment(address, 8);
+    return _asExternalTypedDataDouble(this, length);
+  }
 }
 
 extension BoolPointer on Pointer<Bool> {
diff --git a/tools/VERSION b/tools/VERSION
index b55a51e..bde5370 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 16
 PATCH 0
-PRERELEASE 57
+PRERELEASE 58
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/try_benchmarks.sh b/tools/bots/try_benchmarks.sh
index d8ed384..2fb96f0 100755
--- a/tools/bots/try_benchmarks.sh
+++ b/tools/bots/try_benchmarks.sh
@@ -188,6 +188,8 @@
     out/ReleaseIA32/dart --sound-null-safety benchmarks/NativeCall/dart/NativeCall.dart
     out/ReleaseIA32/dart benchmarks/FfiBoringssl/dart2/FfiBoringssl.dart
     out/ReleaseIA32/dart --sound-null-safety benchmarks/FfiBoringssl/dart/FfiBoringssl.dart
+    out/ReleaseIA32/dart benchmarks/FfiAsTypedList/dart2/FfiAsTypedList.dart
+    out/ReleaseIA32/dart --sound-null-safety benchmarks/FfiAsTypedList/dart/FfiAsTypedList.dart
     out/ReleaseIA32/dart benchmarks/FfiCall/dart2/FfiCall.dart
     out/ReleaseIA32/dart --sound-null-safety benchmarks/FfiCall/dart/FfiCall.dart
     out/ReleaseIA32/dart benchmarks/FfiMemory/dart2/FfiMemory.dart