From 91c6dc15de164e69052de7c6b1d608c57e5dea7d Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Mon, 14 Oct 2019 09:52:58 +0000 Subject: [PATCH] [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 Reviewed-by: Martin Kustermann --- runtime/tools/ffi/sdk_lib_ffi_generator.dart | 85 +++++++++++---- sdk/lib/_internal/vm/lib/ffi_patch.dart | 32 +++++- sdk/lib/ffi/ffi.dart | 99 +++++++++++++++++- sdk_nnbd/lib/_internal/vm/lib/ffi_patch.dart | 32 +++++- sdk_nnbd/lib/ffi/ffi.dart | 104 +++++++++++++++++-- tests/ffi/external_typed_data_test.dart | 75 ++++++------- tests/ffi/highmem_32bit_test.dart | 8 +- tests/ffi/regress_37511_test.dart | 2 +- 8 files changed, 352 insertions(+), 85 deletions(-) diff --git a/runtime/tools/ffi/sdk_lib_ffi_generator.dart b/runtime/tools/ffi/sdk_lib_ffi_generator.dart index 565ccdda4883..657920d44545 100644 --- a/runtime/tools/ffi/sdk_lib_ffi_generator.dart +++ b/runtime/tools/ffi/sdk_lib_ffi_generator.dart @@ -15,19 +15,19 @@ import 'package:args/args.dart'; // Configuration. // -const Map 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 @@ main(List arguments) { 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 @@ void generateHeader(StringBuffer buffer) { 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 @@ void generatePublicExtension( 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 @@ $loadSignExtend /// $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 @@ extension ${nativeType}Pointer on Pointer<$nativeType> { @patch operator []=(int index, $dartType value) => _store$nativeType(this, index, value); + +$asTypedList } """); @@ -185,3 +214,15 @@ Uri dartfmtPath() { // 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 ea2df82c1c22..1407b6ba0521 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 _knownSizes = { Int8: 1, @@ -268,6 +268,9 @@ extension Int8Pointer on Pointer { @patch operator []=(int index, int value) => _storeInt8(this, index, value); + + @patch + Int8List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Int16Pointer on Pointer { @@ -282,6 +285,9 @@ extension Int16Pointer on Pointer { @patch operator []=(int index, int value) => _storeInt16(this, index, value); + + @patch + Int16List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Int32Pointer on Pointer { @@ -296,6 +302,9 @@ extension Int32Pointer on Pointer { @patch operator []=(int index, int value) => _storeInt32(this, index, value); + + @patch + Int32List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Int64Pointer on Pointer { @@ -310,6 +319,9 @@ extension Int64Pointer on Pointer { @patch operator []=(int index, int value) => _storeInt64(this, index, value); + + @patch + Int64List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Uint8Pointer on Pointer { @@ -324,6 +336,9 @@ extension Uint8Pointer on Pointer { @patch operator []=(int index, int value) => _storeUint8(this, index, value); + + @patch + Uint8List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Uint16Pointer on Pointer { @@ -338,6 +353,9 @@ extension Uint16Pointer on Pointer { @patch operator []=(int index, int value) => _storeUint16(this, index, value); + + @patch + Uint16List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Uint32Pointer on Pointer { @@ -352,6 +370,9 @@ extension Uint32Pointer on Pointer { @patch operator []=(int index, int value) => _storeUint32(this, index, value); + + @patch + Uint32List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Uint64Pointer on Pointer { @@ -366,6 +387,9 @@ extension Uint64Pointer on Pointer { @patch operator []=(int index, int value) => _storeUint64(this, index, value); + + @patch + Uint64List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension IntPtrPointer on Pointer { @@ -394,6 +418,9 @@ extension FloatPointer on Pointer { @patch operator []=(int index, double value) => _storeFloat(this, index, value); + + @patch + Float32List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension DoublePointer on Pointer { @@ -408,6 +435,9 @@ extension DoublePointer on Pointer { @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 a0d2820abb4c..1b15eb392961 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 @@ class Pointer extends NativeType { /// 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 @@ extension Int8Pointer on Pointer { /// /// 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 @@ extension Int16Pointer on Pointer { /// /// 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 @@ extension Int32Pointer on Pointer { /// /// 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 @@ extension Int64Pointer on Pointer { /// /// 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 @@ extension Uint8Pointer on Pointer { /// /// 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 @@ extension Uint16Pointer on Pointer { /// /// 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 @@ extension Uint32Pointer on Pointer { /// /// 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 @@ extension Uint64Pointer on Pointer { /// /// 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 @@ extension FloatPointer on Pointer { /// /// 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 @@ extension DoublePointer on Pointer { /// /// 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 82946a468559..43c209885ab1 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 _knownSizes = { Int8: 1, @@ -270,6 +270,9 @@ extension Int8Pointer on Pointer { @patch operator []=(int index, int value) => _storeInt8(this, index, value); + + @patch + Int8List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Int16Pointer on Pointer { @@ -284,6 +287,9 @@ extension Int16Pointer on Pointer { @patch operator []=(int index, int value) => _storeInt16(this, index, value); + + @patch + Int16List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Int32Pointer on Pointer { @@ -298,6 +304,9 @@ extension Int32Pointer on Pointer { @patch operator []=(int index, int value) => _storeInt32(this, index, value); + + @patch + Int32List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Int64Pointer on Pointer { @@ -312,6 +321,9 @@ extension Int64Pointer on Pointer { @patch operator []=(int index, int value) => _storeInt64(this, index, value); + + @patch + Int64List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Uint8Pointer on Pointer { @@ -326,6 +338,9 @@ extension Uint8Pointer on Pointer { @patch operator []=(int index, int value) => _storeUint8(this, index, value); + + @patch + Uint8List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Uint16Pointer on Pointer { @@ -340,6 +355,9 @@ extension Uint16Pointer on Pointer { @patch operator []=(int index, int value) => _storeUint16(this, index, value); + + @patch + Uint16List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Uint32Pointer on Pointer { @@ -354,6 +372,9 @@ extension Uint32Pointer on Pointer { @patch operator []=(int index, int value) => _storeUint32(this, index, value); + + @patch + Uint32List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension Uint64Pointer on Pointer { @@ -368,6 +389,9 @@ extension Uint64Pointer on Pointer { @patch operator []=(int index, int value) => _storeUint64(this, index, value); + + @patch + Uint64List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension IntPtrPointer on Pointer { @@ -396,6 +420,9 @@ extension FloatPointer on Pointer { @patch operator []=(int index, double value) => _storeFloat(this, index, value); + + @patch + Float32List asTypedList(int elements) => _asExternalTypedData(this, elements); } extension DoublePointer on Pointer { @@ -410,6 +437,9 @@ extension DoublePointer on Pointer { @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 57274f557fdb..2dbed065f478 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 @@ class Pointer extends NativeType { /// 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 @@ class Pointer extends NativeType { /// /// 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 @@ class Pointer extends NativeType { /// 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 @@ extension Int8Pointer on Pointer { /// /// 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 @@ extension Int16Pointer on Pointer { /// /// 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 @@ extension Int32Pointer on Pointer { /// /// 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 @@ extension Int64Pointer on Pointer { /// /// 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 @@ extension Uint8Pointer on Pointer { /// /// 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 @@ extension Uint16Pointer on Pointer { /// /// 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 @@ extension Uint32Pointer on Pointer { /// /// 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 @@ extension Uint64Pointer on Pointer { /// /// 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 @@ extension FloatPointer on Pointer { /// /// 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 @@ extension DoublePointer on Pointer { /// /// 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 ae0fbbb705af..8d19f79a37f6 100644 --- a/tests/ffi/external_typed_data_test.dart +++ b/tests/ffi/external_typed_data_test.dart @@ -26,7 +26,6 @@ main() { testInt64Store(); testUint64Load(); testUint64Store(); - testIntPtr(); testFloatLoad(); testFloatStore(); testDoubleLoad(); @@ -44,7 +43,7 @@ void testInt8Load() { // Load Pointer 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 testInt8Load() { void testInt8Store() { // Store Pointer 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 @@ void testUint8Load() { // Load Pointer 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 testUint8Load() { void testUint8Store() { // Store Pointer 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 @@ void testInt16Load() { // Load Pointer 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 testInt16Load() { void testInt16Store() { // Store Pointer 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 @@ void testUint16Load() { // Load Pointer 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 testUint16Load() { void testUint16Store() { // Store Pointer 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 @@ void testInt32Load() { // Load Pointer 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 testInt32Load() { void testInt32Store() { // Store Pointer 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 @@ void testUint32Load() { // Load Pointer 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 testUint32Load() { void testUint32Store() { // Store Pointer 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 @@ void testInt64Load() { // Load Pointer 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 testInt64Load() { void testInt64Store() { // Store Pointer 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 @@ void testUint64Load() { // Load Pointer 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 testUint64Load() { void testUint64Store() { // Store Pointer 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() == 4; - Pointer ptr = allocate(); - final array = ptr.asExternalTypedData(); - if (is32Bit) { - Expect.type(array); - } else { - Expect.type(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 @@ void testFloatLoad() { // Load Pointer 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 testFloatLoad() { void testFloatStore() { // Store Pointer 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 @@ void testDoubleLoad() { // Load Pointer 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 testDoubleLoad() { void testDoubleStore() { // Store Pointer 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 @@ void testArrayLoad() { 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 testArrayLoad() { void testArrayStore() { const int count = 0x100; Pointer 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 testArrayStore() { void testNegativeArray() { Pointer ptr = nullptr; - Expect.throws(() => ptr.asExternalTypedData(count: -1)); + Expect.throws(() => ptr.asTypedList(-1)); } // Tests that the address we're creating an ExternalTypedData from is aligned to // the element size. void testAlignment() { Expect.throws( - () => Pointer.fromAddress(1).asExternalTypedData()); + () => Pointer.fromAddress(1).asTypedList(1)); Expect.throws( - () => Pointer.fromAddress(2).asExternalTypedData()); + () => Pointer.fromAddress(2).asTypedList(1)); Expect.throws( - () => Pointer.fromAddress(4).asExternalTypedData()); + () => Pointer.fromAddress(4).asTypedList(1)); Expect.throws( - () => Pointer.fromAddress(1).asExternalTypedData()); + () => Pointer.fromAddress(1).asTypedList(1)); Expect.throws( - () => Pointer.fromAddress(2).asExternalTypedData()); + () => Pointer.fromAddress(2).asTypedList(1)); Expect.throws( - () => Pointer.fromAddress(4).asExternalTypedData()); + () => Pointer.fromAddress(4).asTypedList(1)); Expect.throws( - () => Pointer.fromAddress(2).asExternalTypedData()); + () => Pointer.fromAddress(2).asTypedList(1)); Expect.throws( - () => Pointer.fromAddress(4).asExternalTypedData()); + () => Pointer.fromAddress(4).asTypedList(1)); } diff --git a/tests/ffi/highmem_32bit_test.dart b/tests/ffi/highmem_32bit_test.dart index 36e9c5f15b98..eeee5fadebf3 100644 --- a/tests/ffi/highmem_32bit_test.dart +++ b/tests/ffi/highmem_32bit_test.dart @@ -51,23 +51,23 @@ void testLoadsAndStores(int indexOffset, Pointer memory) { memory[indexOffset + i] = 10 + i; } Expect.listEquals([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([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([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([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 memory, int indexOffset) { diff --git a/tests/ffi/regress_37511_test.dart b/tests/ffi/regress_37511_test.dart index 03403e4390ce..e2a2e70d23a3 100644 --- a/tests/ffi/regress_37511_test.dart +++ b/tests/ffi/regress_37511_test.dart @@ -36,7 +36,7 @@ final List functionsToTest = [ () => highAddressPointer.address, () => highAddressPointer.elementAt(1), () => highAddressPointer.offsetBy(1), - () => highAddressPointer.asExternalTypedData(), + () => highAddressPointer.asTypedList(1), // DynamicLibrary operations. doDlopen,