[vm/ffi] Pointer.asExternalTypedData to extension method

Issue: https://github.com/dart-lang/sdk/issues/38610

Change-Id: Ib07f50b23e3be2bce2d7b973c0f0196884397952
Cq-Include-Trybots: luci.dart.try:vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,app-kernel-linux-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-dartkb-linux-debug-simarm64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-dartkb-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-dartkb-linux-release-x64-abi-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-reload-mac-release-simdbc64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-precomp-mac-release-simarm_x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121384
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/tools/ffi/sdk_lib_ffi_generator.dart b/runtime/tools/ffi/sdk_lib_ffi_generator.dart
index 565ccdd..657920d 100644
--- a/runtime/tools/ffi/sdk_lib_ffi_generator.dart
+++ b/runtime/tools/ffi/sdk_lib_ffi_generator.dart
@@ -15,19 +15,19 @@
 // Configuration.
 //
 
-const Map<String, String> nativeToDartType = {
-  "Int8": "int",
-  "Int16": "int",
-  "Int32": "int",
-  "Int64": "int",
-  "Uint8": "int",
-  "Uint16": "int",
-  "Uint32": "int",
-  "Uint64": "int",
-  "IntPtr": "int",
-  "Float": "double",
-  "Double": "double",
-};
+const configuration = [
+  Config("Int8", "int", "Int8List", 1),
+  Config("Int16", "int", "Int16List", 2),
+  Config("Int32", "int", "Int32List", 4),
+  Config("Int64", "int", "Int64List", 8),
+  Config("Uint8", "int", "Uint8List", 1),
+  Config("Uint16", "int", "Uint16List", 2),
+  Config("Uint32", "int", "Uint32List", 4),
+  Config("Uint64", "int", "Uint64List", 8),
+  Config("IntPtr", "int", kDoNotEmit, kIntPtrElementSize),
+  Config("Float", "double", "Float32List", 4),
+  Config("Double", "double", "Float64List", 8),
+];
 
 //
 // Generator.
@@ -41,13 +41,11 @@
   generate(path, "ffi_patch.g.dart", generatePatchExtension);
 }
 
-void generate(Uri path, String fileName,
-    Function(StringBuffer, String, String) generator) {
+void generate(
+    Uri path, String fileName, Function(StringBuffer, Config) generator) {
   final buffer = StringBuffer();
   generateHeader(buffer);
-  nativeToDartType.forEach((String nativeType, String dartType) {
-    generator(buffer, nativeType, dartType);
-  });
+  configuration.forEach((Config c) => generator(buffer, c));
   generateFooter(buffer);
 
   final fullPath = path.resolve(fileName).path;
@@ -73,8 +71,12 @@
   buffer.write(header);
 }
 
-void generatePublicExtension(
-    StringBuffer buffer, String nativeType, String dartType) {
+void generatePublicExtension(StringBuffer buffer, Config config) {
+  final nativeType = config.nativeType;
+  final dartType = config.dartType;
+  final typedListType = config.typedListType;
+  final elementSize = config.elementSize;
+
   final storeTrunctateInt = """
   /// Note that ints which do not fit in `$nativeType` are truncated.
 """;
@@ -92,6 +94,19 @@
 
   final loadSignExtend = _isInt(nativeType) ? loadSignExtendInt : "";
 
+  final asTypedList = typedListType == kDoNotEmit
+      ? ""
+      : """
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + ${elementSize > 1 ? '$elementSize * ' : ''}length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external $typedListType asTypedList(int length);
+""";
+
   // TODO(dartdoc-bug): Use [] instead of ``, once issue
   // https://github.com/dart-lang/dartdoc/issues/2039 is fixed.
   buffer.write("""
@@ -124,13 +139,25 @@
 $storeTruncate  ///
   /// Note that `address` needs to be aligned to the size of `$nativeType`.
   external void operator []=(int index, $dartType value);
+
+$asTypedList
 }
 
 """);
 }
 
-void generatePatchExtension(
-    StringBuffer buffer, String nativeType, String dartType) {
+void generatePatchExtension(StringBuffer buffer, Config config) {
+  final nativeType = config.nativeType;
+  final dartType = config.dartType;
+  final typedListType = config.typedListType;
+
+  final asTypedList = typedListType == kDoNotEmit
+      ? ""
+      : """
+  @patch
+  $typedListType asTypedList(int elements) => _asExternalTypedData(this, elements);
+""";
+
   buffer.write("""
 extension ${nativeType}Pointer on Pointer<$nativeType> {
  @patch
@@ -144,6 +171,8 @@
 
   @patch
   operator []=(int index, $dartType value) => _store$nativeType(this, index, value);
+
+$asTypedList
 }
 
 """);
@@ -185,3 +214,15 @@
   // pinned fully supports extension methods.
   return Uri.parse("dartfmt");
 }
+
+class Config {
+  final String nativeType;
+  final String dartType;
+  final String typedListType;
+  final int elementSize;
+  const Config(
+      this.nativeType, this.dartType, this.typedListType, this.elementSize);
+}
+
+const String kDoNotEmit = "donotemit";
+const int kIntPtrElementSize = -1;
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index ea2df82..1407b6b 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -5,7 +5,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:typed_data' show TypedData;
+import 'dart:typed_data';
 
 const Map<Type, int> _knownSizes = {
   Int8: 1,
@@ -268,6 +268,9 @@
 
   @patch
   operator []=(int index, int value) => _storeInt8(this, index, value);
+
+  @patch
+  Int8List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Int16Pointer on Pointer<Int16> {
@@ -282,6 +285,9 @@
 
   @patch
   operator []=(int index, int value) => _storeInt16(this, index, value);
+
+  @patch
+  Int16List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Int32Pointer on Pointer<Int32> {
@@ -296,6 +302,9 @@
 
   @patch
   operator []=(int index, int value) => _storeInt32(this, index, value);
+
+  @patch
+  Int32List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Int64Pointer on Pointer<Int64> {
@@ -310,6 +319,9 @@
 
   @patch
   operator []=(int index, int value) => _storeInt64(this, index, value);
+
+  @patch
+  Int64List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Uint8Pointer on Pointer<Uint8> {
@@ -324,6 +336,9 @@
 
   @patch
   operator []=(int index, int value) => _storeUint8(this, index, value);
+
+  @patch
+  Uint8List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Uint16Pointer on Pointer<Uint16> {
@@ -338,6 +353,9 @@
 
   @patch
   operator []=(int index, int value) => _storeUint16(this, index, value);
+
+  @patch
+  Uint16List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Uint32Pointer on Pointer<Uint32> {
@@ -352,6 +370,9 @@
 
   @patch
   operator []=(int index, int value) => _storeUint32(this, index, value);
+
+  @patch
+  Uint32List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Uint64Pointer on Pointer<Uint64> {
@@ -366,6 +387,9 @@
 
   @patch
   operator []=(int index, int value) => _storeUint64(this, index, value);
+
+  @patch
+  Uint64List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension IntPtrPointer on Pointer<IntPtr> {
@@ -394,6 +418,9 @@
 
   @patch
   operator []=(int index, double value) => _storeFloat(this, index, value);
+
+  @patch
+  Float32List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension DoublePointer on Pointer<Double> {
@@ -408,6 +435,9 @@
 
   @patch
   operator []=(int index, double value) => _storeDouble(this, index, value);
+
+  @patch
+  Float64List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 //
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index a0d2820..1b15eb3 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -14,7 +14,7 @@
  */
 library dart.ffi;
 
-import 'dart:typed_data' show TypedData;
+import 'dart:typed_data';
 
 part "native_type.dart";
 part "annotations.dart";
@@ -143,10 +143,9 @@
   /// data from a [Pointer] to any other native type is not supported.
   ///
   /// The pointer must be aligned to a multiple of the native type's size.
-  //
-  // TODO(37773): Use extension methods to articulate more precise return types.
-  // We should still keep this member though as a generic way to access a
-  // Pointer of unknown type.
+  ///
+  /// Deprecated, replace with `asTypedList()`.
+  @deprecated
   external TypedData asExternalTypedData({int count: 1});
 
   /// Equality for Pointers only depends on their address.
@@ -200,6 +199,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Int8`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Int8List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Int16].
@@ -235,6 +243,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Int16`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 2 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Int16List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Int32].
@@ -270,6 +287,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Int32`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Int32List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Int64].
@@ -305,6 +331,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Int64`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Int64List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Uint8].
@@ -340,6 +375,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Uint8`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Uint8List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Uint16].
@@ -375,6 +419,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Uint16`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 2 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Uint16List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Uint32].
@@ -410,6 +463,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Uint32`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Uint32List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Uint64].
@@ -445,6 +507,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Uint64`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Uint64List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [IntPtr].
@@ -513,6 +584,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Float`.
   external void operator []=(int index, double value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Float32List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Double].
@@ -546,6 +626,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Double`.
   external void operator []=(int index, double value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Float64List asTypedList(int length);
 }
 
 //
diff --git a/sdk_nnbd/lib/_internal/vm/lib/ffi_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/ffi_patch.dart
index 82946a4..43c2098 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/ffi_patch.dart
@@ -7,7 +7,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:typed_data' show TypedData;
+import 'dart:typed_data';
 
 const Map<Type, int> _knownSizes = {
   Int8: 1,
@@ -270,6 +270,9 @@
 
   @patch
   operator []=(int index, int value) => _storeInt8(this, index, value);
+
+  @patch
+  Int8List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Int16Pointer on Pointer<Int16> {
@@ -284,6 +287,9 @@
 
   @patch
   operator []=(int index, int value) => _storeInt16(this, index, value);
+
+  @patch
+  Int16List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Int32Pointer on Pointer<Int32> {
@@ -298,6 +304,9 @@
 
   @patch
   operator []=(int index, int value) => _storeInt32(this, index, value);
+
+  @patch
+  Int32List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Int64Pointer on Pointer<Int64> {
@@ -312,6 +321,9 @@
 
   @patch
   operator []=(int index, int value) => _storeInt64(this, index, value);
+
+  @patch
+  Int64List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Uint8Pointer on Pointer<Uint8> {
@@ -326,6 +338,9 @@
 
   @patch
   operator []=(int index, int value) => _storeUint8(this, index, value);
+
+  @patch
+  Uint8List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Uint16Pointer on Pointer<Uint16> {
@@ -340,6 +355,9 @@
 
   @patch
   operator []=(int index, int value) => _storeUint16(this, index, value);
+
+  @patch
+  Uint16List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Uint32Pointer on Pointer<Uint32> {
@@ -354,6 +372,9 @@
 
   @patch
   operator []=(int index, int value) => _storeUint32(this, index, value);
+
+  @patch
+  Uint32List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension Uint64Pointer on Pointer<Uint64> {
@@ -368,6 +389,9 @@
 
   @patch
   operator []=(int index, int value) => _storeUint64(this, index, value);
+
+  @patch
+  Uint64List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension IntPtrPointer on Pointer<IntPtr> {
@@ -396,6 +420,9 @@
 
   @patch
   operator []=(int index, double value) => _storeFloat(this, index, value);
+
+  @patch
+  Float32List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 extension DoublePointer on Pointer<Double> {
@@ -410,6 +437,9 @@
 
   @patch
   operator []=(int index, double value) => _storeDouble(this, index, value);
+
+  @patch
+  Float64List asTypedList(int elements) => _asExternalTypedData(this, elements);
 }
 
 //
diff --git a/sdk_nnbd/lib/ffi/ffi.dart b/sdk_nnbd/lib/ffi/ffi.dart
index 57274f5..2dbed06 100644
--- a/sdk_nnbd/lib/ffi/ffi.dart
+++ b/sdk_nnbd/lib/ffi/ffi.dart
@@ -16,7 +16,7 @@
  */
 library dart.ffi;
 
-import 'dart:typed_data' show TypedData;
+import 'dart:typed_data';
 
 part "native_type.dart";
 part "annotations.dart";
@@ -43,7 +43,7 @@
   /// On Windows, this memory may only be freed via [Pointer.free].
   ///
   /// This method is deprecated. Please resolve allocation methods via
-  /// [DynamicLibrary] instead.
+  /// [DynamicLibrary] instead, or use "package:ffi".
   @deprecated
   external factory Pointer.allocate({int count: 1});
 
@@ -78,7 +78,8 @@
   ///
   /// Note that `this.address` needs to be aligned to the size of `T`.
   ///
-  /// Deprecated, use `pointer[...] =` and `pointer.value =` instead.
+  /// Deprecated, use `pointer[...] =` and `pointer.value =` instead, or use
+  /// "package:ffi".
   @deprecated
   external void store(@DartRepresentationOf("T") Object value);
 
@@ -144,10 +145,9 @@
   /// data from a [Pointer] to any other native type is not supported.
   ///
   /// The pointer must be aligned to a multiple of the native type's size.
-  //
-  // TODO(37773): Use extension methods to articulate more precise return types.
-  // We should still keep this member though as a generic way to access a
-  // Pointer of unknown type.
+  ///
+  /// Deprecated, replace with `asTypedList()`.
+  @deprecated
   external TypedData asExternalTypedData({int count: 1});
 
   /// Equality for Pointers only depends on their address.
@@ -201,6 +201,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Int8`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Int8List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Int16].
@@ -236,6 +245,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Int16`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 2 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Int16List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Int32].
@@ -271,6 +289,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Int32`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Int32List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Int64].
@@ -306,6 +333,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Int64`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Int64List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Uint8].
@@ -341,6 +377,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Uint8`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Uint8List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Uint16].
@@ -376,6 +421,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Uint16`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 2 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Uint16List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Uint32].
@@ -411,6 +465,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Uint32`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Uint32List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Uint64].
@@ -446,6 +509,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Uint64`.
   external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Uint64List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [IntPtr].
@@ -514,6 +586,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Float`.
   external void operator []=(int index, double value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Float32List asTypedList(int length);
 }
 
 /// Extension on [Pointer] specialized for the type argument [Double].
@@ -547,6 +628,15 @@
   ///
   /// Note that `address` needs to be aligned to the size of `Double`.
   external void operator []=(int index, double value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from `address`
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Float64List asTypedList(int length);
 }
 
 //
diff --git a/tests/ffi/external_typed_data_test.dart b/tests/ffi/external_typed_data_test.dart
index ae0fbbb..8d19f79 100644
--- a/tests/ffi/external_typed_data_test.dart
+++ b/tests/ffi/external_typed_data_test.dart
@@ -26,7 +26,6 @@
   testInt64Store();
   testUint64Load();
   testUint64Store();
-  testIntPtr();
   testFloatLoad();
   testFloatStore();
   testDoubleLoad();
@@ -44,7 +43,7 @@
   // Load
   Pointer<Int8> ptr = allocate();
   ptr.value = 0xff;
-  Int8List list = ptr.asExternalTypedData();
+  Int8List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
   free(ptr);
@@ -53,7 +52,7 @@
 void testInt8Store() {
   // Store
   Pointer<Int8> ptr = allocate();
-  Int8List list = ptr.asExternalTypedData();
+  Int8List list = ptr.asTypedList(1);
   list[0] = 0xff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
@@ -64,7 +63,7 @@
   // Load
   Pointer<Uint8> ptr = allocate();
   ptr.value = 0xff;
-  Uint8List list = ptr.asExternalTypedData();
+  Uint8List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xff);
   Expect.equals(list.length, 1);
   free(ptr);
@@ -73,7 +72,7 @@
 void testUint8Store() {
   // Store
   Pointer<Uint8> ptr = allocate();
-  Uint8List list = ptr.asExternalTypedData();
+  Uint8List list = ptr.asTypedList(1);
   list[0] = 0xff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xff);
@@ -84,7 +83,7 @@
   // Load
   Pointer<Int16> ptr = allocate();
   ptr.value = 0xffff;
-  Int16List list = ptr.asExternalTypedData();
+  Int16List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
   free(ptr);
@@ -93,7 +92,7 @@
 void testInt16Store() {
   // Store
   Pointer<Int16> ptr = allocate();
-  Int16List list = ptr.asExternalTypedData();
+  Int16List list = ptr.asTypedList(1);
   list[0] = 0xffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
@@ -104,7 +103,7 @@
   // Load
   Pointer<Uint16> ptr = allocate();
   ptr.value = 0xffff;
-  Uint16List list = ptr.asExternalTypedData();
+  Uint16List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffff);
   Expect.equals(list.length, 1);
   free(ptr);
@@ -113,7 +112,7 @@
 void testUint16Store() {
   // Store
   Pointer<Uint16> ptr = allocate();
-  Uint16List list = ptr.asExternalTypedData();
+  Uint16List list = ptr.asTypedList(1);
   list[0] = 0xffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xffff);
@@ -124,7 +123,7 @@
   // Load
   Pointer<Int32> ptr = allocate();
   ptr.value = 0xffffffff;
-  Int32List list = ptr.asExternalTypedData();
+  Int32List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
   free(ptr);
@@ -133,7 +132,7 @@
 void testInt32Store() {
   // Store
   Pointer<Int32> ptr = allocate();
-  Int32List list = ptr.asExternalTypedData();
+  Int32List list = ptr.asTypedList(1);
   list[0] = 0xffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
@@ -144,7 +143,7 @@
   // Load
   Pointer<Uint32> ptr = allocate();
   ptr.value = 0xffffffff;
-  Uint32List list = ptr.asExternalTypedData();
+  Uint32List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffffffff);
   Expect.equals(list.length, 1);
   free(ptr);
@@ -153,7 +152,7 @@
 void testUint32Store() {
   // Store
   Pointer<Uint32> ptr = allocate();
-  Uint32List list = ptr.asExternalTypedData();
+  Uint32List list = ptr.asTypedList(1);
   list[0] = 0xffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xffffffff);
@@ -164,7 +163,7 @@
   // Load
   Pointer<Int64> ptr = allocate();
   ptr.value = 0xffffffffffffffff;
-  Int64List list = ptr.asExternalTypedData();
+  Int64List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
   free(ptr);
@@ -173,7 +172,7 @@
 void testInt64Store() {
   // Store
   Pointer<Int64> ptr = allocate();
-  Int64List list = ptr.asExternalTypedData();
+  Int64List list = ptr.asTypedList(1);
   list[0] = 0xffffffffffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, -1);
@@ -184,7 +183,7 @@
   // Load
   Pointer<Uint64> ptr = allocate();
   ptr.value = 0xffffffffffffffff;
-  Uint64List list = ptr.asExternalTypedData();
+  Uint64List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffffffffffffffff);
   Expect.equals(list.length, 1);
   free(ptr);
@@ -193,25 +192,13 @@
 void testUint64Store() {
   // Store
   Pointer<Uint64> ptr = allocate();
-  Uint64List list = ptr.asExternalTypedData();
+  Uint64List list = ptr.asTypedList(1);
   list[0] = 0xffffffffffffffff;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, 0xffffffffffffffff);
   free(ptr);
 }
 
-void testIntPtr() {
-  bool is32Bit = sizeOf<IntPtr>() == 4;
-  Pointer<IntPtr> ptr = allocate();
-  final array = ptr.asExternalTypedData();
-  if (is32Bit) {
-    Expect.type<Int32List>(array);
-  } else {
-    Expect.type<Int64List>(array);
-  }
-  free(ptr);
-}
-
 double maxFloat = (2 - pow(2, -23)) * pow(2, 127);
 double maxDouble = (2 - pow(2, -52)) * pow(2, pow(2, 10) - 1);
 
@@ -219,7 +206,7 @@
   // Load
   Pointer<Float> ptr = allocate();
   ptr.value = maxFloat;
-  Float32List list = ptr.asExternalTypedData();
+  Float32List list = ptr.asTypedList(1);
   Expect.equals(list[0], maxFloat);
   Expect.equals(list.length, 1);
   free(ptr);
@@ -228,7 +215,7 @@
 void testFloatStore() {
   // Store
   Pointer<Float> ptr = allocate();
-  Float32List list = ptr.asExternalTypedData();
+  Float32List list = ptr.asTypedList(1);
   list[0] = maxFloat;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, maxFloat);
@@ -239,7 +226,7 @@
   // Load
   Pointer<Double> ptr = allocate();
   ptr.value = maxDouble;
-  Float64List list = ptr.asExternalTypedData();
+  Float64List list = ptr.asTypedList(1);
   Expect.equals(list[0], maxDouble);
   Expect.equals(list.length, 1);
   free(ptr);
@@ -248,7 +235,7 @@
 void testDoubleStore() {
   // Store
   Pointer<Double> ptr = allocate();
-  Float64List list = ptr.asExternalTypedData();
+  Float64List list = ptr.asTypedList(1);
   list[0] = maxDouble;
   Expect.equals(list.length, 1);
   Expect.equals(ptr.value, maxDouble);
@@ -261,7 +248,7 @@
   for (int i = 0; i < count; ++i) {
     ptr[i] = i;
   }
-  Int32List array = ptr.asExternalTypedData(count: count);
+  Int32List array = ptr.asTypedList(count);
   for (int i = 0; i < count; ++i) {
     Expect.equals(array[i], i);
   }
@@ -271,7 +258,7 @@
 void testArrayStore() {
   const int count = 0x100;
   Pointer<Int32> ptr = allocate(count: count);
-  Int32List array = ptr.asExternalTypedData(count: count);
+  Int32List array = ptr.asTypedList(count);
   for (int i = 0; i < count; ++i) {
     array[i] = i;
   }
@@ -283,26 +270,26 @@
 
 void testNegativeArray() {
   Pointer<Int32> ptr = nullptr;
-  Expect.throws<ArgumentError>(() => ptr.asExternalTypedData(count: -1));
+  Expect.throws<ArgumentError>(() => ptr.asTypedList(-1));
 }
 
 // Tests that the address we're creating an ExternalTypedData from is aligned to
 // the element size.
 void testAlignment() {
   Expect.throws<ArgumentError>(
-      () => Pointer<Int16>.fromAddress(1).asExternalTypedData());
+      () => Pointer<Int16>.fromAddress(1).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Int32>.fromAddress(2).asExternalTypedData());
+      () => Pointer<Int32>.fromAddress(2).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Int64>.fromAddress(4).asExternalTypedData());
+      () => Pointer<Int64>.fromAddress(4).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Uint16>.fromAddress(1).asExternalTypedData());
+      () => Pointer<Uint16>.fromAddress(1).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Uint32>.fromAddress(2).asExternalTypedData());
+      () => Pointer<Uint32>.fromAddress(2).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Uint64>.fromAddress(4).asExternalTypedData());
+      () => Pointer<Uint64>.fromAddress(4).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Float>.fromAddress(2).asExternalTypedData());
+      () => Pointer<Float>.fromAddress(2).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Double>.fromAddress(4).asExternalTypedData());
+      () => Pointer<Double>.fromAddress(4).asTypedList(1));
 }
diff --git a/tests/ffi/highmem_32bit_test.dart b/tests/ffi/highmem_32bit_test.dart
index 36e9c5f..eeee5fa 100644
--- a/tests/ffi/highmem_32bit_test.dart
+++ b/tests/ffi/highmem_32bit_test.dart
@@ -51,23 +51,23 @@
     memory[indexOffset + i] = 10 + i;
   }
   Expect.listEquals(<int>[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
-      memory.offsetBy(indexOffset).asExternalTypedData(count: 10) as Uint8List);
+      memory.offsetBy(indexOffset).asTypedList(10));
 
   for (int i = 0; i < 9; ++i) {
     swapBytes(memory, indexOffset + 0, i, i + 1);
   }
   Expect.listEquals(<int>[11, 12, 13, 14, 15, 16, 17, 18, 19, 10],
-      memory.offsetBy(indexOffset).asExternalTypedData(count: 10) as Uint8List);
+      memory.offsetBy(indexOffset).asTypedList(10));
   for (int i = 0; i < 9; ++i) {
     swapBytes(memory, indexOffset + kIgnoreBytesPositive, i, i + 1);
   }
   Expect.listEquals(<int>[12, 13, 14, 15, 16, 17, 18, 19, 10, 11],
-      memory.offsetBy(indexOffset).asExternalTypedData(count: 10) as Uint8List);
+      memory.offsetBy(indexOffset).asTypedList(10));
   for (int i = 0; i < 9; ++i) {
     swapBytes(memory, indexOffset + kIgnoreBytesNegative, i, i + 1);
   }
   Expect.listEquals(<int>[13, 14, 15, 16, 17, 18, 19, 10, 11, 12],
-      memory.offsetBy(indexOffset).asExternalTypedData(count: 10) as Uint8List);
+      memory.offsetBy(indexOffset).asTypedList(10));
 }
 
 void testOnHighOrLowMemory(Pointer<Uint8> memory, int indexOffset) {
diff --git a/tests/ffi/regress_37511_test.dart b/tests/ffi/regress_37511_test.dart
index 03403e4..e2a2e70 100644
--- a/tests/ffi/regress_37511_test.dart
+++ b/tests/ffi/regress_37511_test.dart
@@ -36,7 +36,7 @@
   () => highAddressPointer.address,
   () => highAddressPointer.elementAt(1),
   () => highAddressPointer.offsetBy(1),
-  () => highAddressPointer.asExternalTypedData(),
+  () => highAddressPointer.asTypedList(1),
 
   // DynamicLibrary operations.
   doDlopen,