diff --git a/pkg/vm/lib/transformations/ffi/use_sites.dart b/pkg/vm/lib/transformations/ffi/use_sites.dart index 37348b7c953..85b13b62868 100644 --- a/pkg/vm/lib/transformations/ffi/use_sites.dart +++ b/pkg/vm/lib/transformations/ffi/use_sites.dart @@ -938,14 +938,43 @@ mixin _FfiUseSiteTransformer on FfiTransformer { final constructor = clazz.constructors .firstWhere((c) => c.name == Name("#fromTypedDataBase")); - final typedDataBasePrime = typedDataBaseOffset( - getArrayTypedDataBaseField(NullCheck(node.arguments.positional[0])), - multiply(node.arguments.positional[1], inlineSizeOf(dartType)!), - inlineSizeOf(dartType)!, - dartType, - node.fileOffset); + final arrayVar = VariableDeclaration("#array", + initializer: NullCheck(node.arguments.positional[0]), + type: InterfaceType(arrayClass, Nullability.nonNullable), + isSynthesized: true) + ..fileOffset = node.fileOffset; + final indexVar = VariableDeclaration("#index", + initializer: NullCheck(node.arguments.positional[1]), + type: coreTypes.intNonNullableRawType, + isSynthesized: true) + ..fileOffset = node.fileOffset; - return ConstructorInvocation(constructor, Arguments([typedDataBasePrime])); + return BlockExpression( + Block([ + arrayVar, + indexVar, + ExpressionStatement(InstanceInvocation( + InstanceAccessKind.Instance, + VariableGet(arrayVar), + arrayCheckIndex.name, + Arguments([VariableGet(indexVar)]), + interfaceTarget: arrayCheckIndex, + functionType: arrayCheckIndex.getterType as FunctionType, + )), + ]), + ConstructorInvocation( + constructor, + Arguments([ + typedDataBaseOffset( + getArrayTypedDataBaseField(VariableGet(arrayVar)), + multiply(VariableGet(indexVar), inlineSizeOf(dartType)!), + inlineSizeOf(dartType)!, + dartType, + node.fileOffset, + ) + ]), + ), + ); } /// Generates an expression that returns a new `Array`. @@ -1031,12 +1060,13 @@ mixin _FfiUseSiteTransformer on FfiTransformer { arrayVar, indexVar, ExpressionStatement(InstanceInvocation( - InstanceAccessKind.Instance, - VariableGet(arrayVar), - arrayCheckIndex.name, - Arguments([VariableGet(indexVar)]), - interfaceTarget: arrayCheckIndex, - functionType: arrayCheckIndex.getterType as FunctionType)), + InstanceAccessKind.Instance, + VariableGet(arrayVar), + arrayCheckIndex.name, + Arguments([VariableGet(indexVar)]), + interfaceTarget: arrayCheckIndex, + functionType: arrayCheckIndex.getterType as FunctionType, + )), singleElementSizeVar, elementSizeVar, offsetVar diff --git a/tests/ffi/inline_array_test.dart b/tests/ffi/inline_array_test.dart index fb920725cef..538b35f19f4 100644 --- a/tests/ffi/inline_array_test.dart +++ b/tests/ffi/inline_array_test.dart @@ -19,6 +19,8 @@ void main() { testToString(); testRange(); testRangeArrayOfPointer(); + testRangeArrayOfArray(); + testRangeArrayOfStruct(); } void testSizeOf() { @@ -109,3 +111,30 @@ final class StructWithArrayOfPointer extends Struct { @Array(8) external Array> a0; } + +void testRangeArrayOfArray() { + final pointer = calloc(); + final struct = pointer.ref; + final array = struct.a0; + array[0] = array[1]; + Expect.throws(() => array[-1]); + Expect.throws(() => array[-1] = array[1]); + Expect.throws(() => array[2]); + Expect.throws(() => array[2] = array[1]); + calloc.free(pointer); +} + +final class StructWithArrayArray extends Struct { + @Array(2, 2) + external Array> a0; +} + +void testRangeArrayOfStruct() { + final pointer = calloc(); + final struct = pointer.ref; + final array = struct.a0[0]; + print(array[0]); + Expect.throws(() => array[-1]); + Expect.throws(() => array[2]); + calloc.free(pointer); +}