diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect index c53e92f09d0e..94630fcc032e 100644 --- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect @@ -21,7 +21,7 @@ class Coordinate extends ffi::Struct { : super ffi::Struct::_fromPointer(#pointer) ; static factory allocate(ffi::Allocator* allocator, core::double* x, core::double* y, ffi::Pointer* next) → self::Coordinate* { - return let final self::Coordinate* #t1 = ffi::StructPointer|get#ref(ffi::AllocatorAlloc|call(allocator)) in block { + return let final self::Coordinate* #t1 = new self::Coordinate::#fromTypedDataBase(allocator.{ffi::Allocator::allocate}(self::Coordinate::#sizeOf)!) in block { #t1.{self::Coordinate::x} = x; #t1.{self::Coordinate::y} = y; #t1.{self::Coordinate::next} = next; diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect index ac239e847f72..79439bc1b470 100644 --- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect @@ -37,7 +37,7 @@ class Coordinate extends ffi::Struct { set next(ffi::Pointer #externalFieldValue) → void return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address}); static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer next) → self::Coordinate { - return let final self::Coordinate #t1 = ffi::StructPointer|get#ref(ffi::AllocatorAlloc|call(allocator)) in block { + return let final self::Coordinate #t1 = new self::Coordinate::#fromTypedDataBase(allocator.{ffi::Allocator::allocate}(self::Coordinate::#sizeOf)!) in block { #t1.{self::Coordinate::x} = x; #t1.{self::Coordinate::y} = y; #t1.{self::Coordinate::next} = next; diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect index ac239e847f72..79439bc1b470 100644 --- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect @@ -37,7 +37,7 @@ class Coordinate extends ffi::Struct { set next(ffi::Pointer #externalFieldValue) → void return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address}); static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer next) → self::Coordinate { - return let final self::Coordinate #t1 = ffi::StructPointer|get#ref(ffi::AllocatorAlloc|call(allocator)) in block { + return let final self::Coordinate #t1 = new self::Coordinate::#fromTypedDataBase(allocator.{ffi::Allocator::allocate}(self::Coordinate::#sizeOf)!) in block { #t1.{self::Coordinate::x} = x; #t1.{self::Coordinate::y} = y; #t1.{self::Coordinate::next} = next; diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart index 53cb8e95c909..05b408958340 100644 --- a/pkg/vm/lib/transformations/ffi_use_sites.dart +++ b/pkg/vm/lib/transformations/ffi_use_sites.dart @@ -186,8 +186,13 @@ class _FfiUseSiteTransformer extends FfiTransformer { _warningNativeTypeValid(nativeType, node, allowStructItself: false); - // TODO(http://dartbug.com/38721): Replace calls with direct - // constructor invocations. + // TODO(http://dartbug.com/38721): Change this to an error. + if (nativeType is TypeParameterType) { + // Do not rewire generic invocations. + return node; + } + + return _replaceRef(node); } else if (target == sizeOfMethod) { final DartType nativeType = node.arguments.types[0]; @@ -439,6 +444,28 @@ class _FfiUseSiteTransformer extends FfiTransformer { return StaticGet(field); } + Expression _replaceRef(StaticInvocation node) { + final dartType = node.arguments.types[0]; + final clazz = (dartType as InterfaceType).classNode; + final constructor = clazz.constructors + .firstWhere((c) => c.name == Name("#fromTypedDataBase")); + Expression pointer = NullCheck(node.arguments.positional[0]); + if (node.arguments.positional.length == 2) { + pointer = MethodInvocation( + pointer, + offsetByMethod.name, + Arguments([ + MethodInvocation( + node.arguments.positional[1], + numMultiplication.name, + Arguments([_inlineSizeOf(dartType)]), + numMultiplication) + ]), + offsetByMethod); + } + return ConstructorInvocation(constructor, Arguments([pointer])); + } + @override visitMethodInvocation(MethodInvocation node) { super.visitMethodInvocation(node); @@ -470,7 +497,7 @@ class _FfiUseSiteTransformer extends FfiTransformer { numMultiplication.name, Arguments([inlineSizeOf]), numMultiplication) - ], types: node.arguments.types), + ]), offsetByMethod); } } diff --git a/tests/ffi/structs_test.dart b/tests/ffi/structs_test.dart index e3394378dc64..68ee219bd5bf 100644 --- a/tests/ffi/structs_test.dart +++ b/tests/ffi/structs_test.dart @@ -18,6 +18,7 @@ void main() { for (int i = 0; i < 100; i++) { testStructAllocate(); testStructFromAddress(); + testStructIndexedAccess(); testStructWithNulls(); testTypeTest(); testUtf8(); @@ -25,7 +26,7 @@ void main() { } } -/// allocates each coordinate separately in c memory +/// Allocates each coordinate separately in c memory. void testStructAllocate() { final c1 = calloc() ..ref.x = 10.0 @@ -54,7 +55,7 @@ void testStructAllocate() { calloc.free(c3); } -/// allocates coordinates consecutively in c memory +/// Allocates coordinates consecutively in c memory. void testStructFromAddress() { Pointer c1 = calloc(3); Pointer c2 = c1.elementAt(1); @@ -84,6 +85,34 @@ void testStructFromAddress() { calloc.free(c1); } +/// Allocates coordinates consecutively in c memory. +void testStructIndexedAccess() { + Pointer cs = calloc(3); + cs[0] + ..x = 10.0 + ..y = 10.0 + ..next = cs.elementAt(2); + cs[1] + ..x = 20.0 + ..y = 20.0 + ..next = cs; + cs[2] + ..x = 30.0 + ..y = 30.0 + ..next = cs.elementAt(1); + + Coordinate currentCoordinate = cs.ref; + Expect.equals(10.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(30.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(20.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(10.0, currentCoordinate.x); + + calloc.free(cs); +} + void testStructWithNulls() { final coordinate = calloc() ..ref.x = 10.0 diff --git a/tests/ffi_2/structs_test.dart b/tests/ffi_2/structs_test.dart index e3394378dc64..68ee219bd5bf 100644 --- a/tests/ffi_2/structs_test.dart +++ b/tests/ffi_2/structs_test.dart @@ -18,6 +18,7 @@ void main() { for (int i = 0; i < 100; i++) { testStructAllocate(); testStructFromAddress(); + testStructIndexedAccess(); testStructWithNulls(); testTypeTest(); testUtf8(); @@ -25,7 +26,7 @@ void main() { } } -/// allocates each coordinate separately in c memory +/// Allocates each coordinate separately in c memory. void testStructAllocate() { final c1 = calloc() ..ref.x = 10.0 @@ -54,7 +55,7 @@ void testStructAllocate() { calloc.free(c3); } -/// allocates coordinates consecutively in c memory +/// Allocates coordinates consecutively in c memory. void testStructFromAddress() { Pointer c1 = calloc(3); Pointer c2 = c1.elementAt(1); @@ -84,6 +85,34 @@ void testStructFromAddress() { calloc.free(c1); } +/// Allocates coordinates consecutively in c memory. +void testStructIndexedAccess() { + Pointer cs = calloc(3); + cs[0] + ..x = 10.0 + ..y = 10.0 + ..next = cs.elementAt(2); + cs[1] + ..x = 20.0 + ..y = 20.0 + ..next = cs; + cs[2] + ..x = 30.0 + ..y = 30.0 + ..next = cs.elementAt(1); + + Coordinate currentCoordinate = cs.ref; + Expect.equals(10.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(30.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(20.0, currentCoordinate.x); + currentCoordinate = currentCoordinate.next.ref; + Expect.equals(10.0, currentCoordinate.x); + + calloc.free(cs); +} + void testStructWithNulls() { final coordinate = calloc() ..ref.x = 10.0