diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart index e27e3f3dc70f..f18cd0d3483a 100644 --- a/pkg/vm/lib/transformations/ffi.dart +++ b/pkg/vm/lib/transformations/ffi.dart @@ -410,6 +410,8 @@ class FfiTransformer extends Transformer { return FunctionType(argumentTypes, returnType, Nullability.legacy); } + /// The [NativeType] corresponding to [c]. Returns `null` for user-defined + /// structs. NativeType getType(Class c) { final int index = nativeTypesClasses.indexOf(c); if (index == -1) { @@ -417,6 +419,23 @@ class FfiTransformer extends Transformer { } return NativeType.values[index]; } + + /// Expression that queries VM internals at runtime to figure out on which ABI + /// we are. + Expression runtimeBranchOnLayout(Map values) { + return MethodInvocation( + ConstantExpression( + ListConstant(InterfaceType(intClass, Nullability.legacy), [ + IntConstant(values[Abi.wordSize64]), + IntConstant(values[Abi.wordSize32Align32]), + IntConstant(values[Abi.wordSize32Align64]) + ]), + InterfaceType(listClass, Nullability.legacy, + [InterfaceType(intClass, Nullability.legacy)])), + Name("[]"), + Arguments([StaticInvocation(abiMethod, Arguments([]))]), + listElementAt); + } } /// Contains all information collected by _FfiDefinitionTransformer that is diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart index 853087ef0f41..b06c63fb26af 100644 --- a/pkg/vm/lib/transformations/ffi_definitions.dart +++ b/pkg/vm/lib/transformations/ffi_definitions.dart @@ -496,23 +496,6 @@ class _FfiDefinitionTransformer extends FfiTransformer { InterfaceType(pragmaClass, Nullability.nonNullable, []))); } - /// Expression that queries VM internals at runtime to figure out on which ABI - /// we are. - Expression _runtimeBranchOnLayout(Map values) { - return MethodInvocation( - ConstantExpression( - ListConstant(InterfaceType(intClass, Nullability.legacy), [ - IntConstant(values[Abi.wordSize64]), - IntConstant(values[Abi.wordSize32Align32]), - IntConstant(values[Abi.wordSize32Align64]) - ]), - InterfaceType(listClass, Nullability.legacy, - [InterfaceType(intClass, Nullability.legacy)])), - Name("[]"), - Arguments([StaticInvocation(abiMethod, Arguments([]))]), - listElementAt); - } - Statement _generateGetterStatement(DartType dartType, NativeType type, int fileOffset, Map offsets) { final bool isPointer = type == NativeType.kPointer; @@ -558,7 +541,7 @@ class _FfiDefinitionTransformer extends FfiTransformer { addressGetter) ..fileOffset = fileOffset, numAddition.name, - Arguments([_runtimeBranchOnLayout(offsets)]), + Arguments([runtimeBranchOnLayout(offsets)]), numAddition) ], types: [ dartType @@ -594,9 +577,9 @@ class _FfiDefinitionTransformer extends FfiTransformer { typedDataOffsetInBytesGetter) ..fileOffset = fileOffset, numAddition.name, - Arguments([_runtimeBranchOnLayout(offsets)]), + Arguments([runtimeBranchOnLayout(offsets)]), numAddition), - _runtimeBranchOnLayout(lengths) + runtimeBranchOnLayout(lengths) ]), byteBufferAsUint8List), InterfaceType(objectClass, Nullability.nonNullable)) @@ -610,7 +593,7 @@ class _FfiDefinitionTransformer extends FfiTransformer { Arguments([ PropertyGet(ThisExpression(), addressOfField.name, addressOfField) ..fileOffset = fileOffset, - _runtimeBranchOnLayout(offsets) + runtimeBranchOnLayout(offsets) ])) ..fileOffset = fileOffset; if (isPointer) { @@ -646,12 +629,12 @@ class _FfiDefinitionTransformer extends FfiTransformer { Arguments([ PropertyGet(ThisExpression(), addressOfField.name, addressOfField) ..fileOffset = fileOffset, - _runtimeBranchOnLayout(offsets), + runtimeBranchOnLayout(offsets), PropertyGet( VariableGet(argument), addressOfField.name, addressOfField) ..fileOffset = fileOffset, ConstantExpression(IntConstant(0)), - _runtimeBranchOnLayout(lengths), + runtimeBranchOnLayout(lengths), ])) ..fileOffset = fileOffset); } @@ -669,7 +652,7 @@ class _FfiDefinitionTransformer extends FfiTransformer { Arguments([ PropertyGet(ThisExpression(), addressOfField.name, addressOfField) ..fileOffset = fileOffset, - _runtimeBranchOnLayout(offsets), + runtimeBranchOnLayout(offsets), argumentExpression ])) ..fileOffset = fileOffset); @@ -719,7 +702,7 @@ class _FfiDefinitionTransformer extends FfiTransformer { final Field sizeOf = Field.immutable(name, isStatic: true, isFinal: true, - initializer: _runtimeBranchOnLayout(sizes), + initializer: runtimeBranchOnLayout(sizes), type: InterfaceType(intClass, Nullability.legacy), fileUri: struct.fileUri, getterReference: getterReference) diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart index e96307883120..052a4dde5f67 100644 --- a/pkg/vm/lib/transformations/ffi_use_sites.dart +++ b/pkg/vm/lib/transformations/ffi_use_sites.dart @@ -27,7 +27,15 @@ import 'package:kernel/target/targets.dart' show DiagnosticReporter; import 'package:kernel/type_environment.dart'; import 'ffi.dart' - show FfiTransformerData, NativeType, FfiTransformer, optimizedTypes; + show + FfiTransformerData, + NativeType, + FfiTransformer, + optimizedTypes, + nativeTypeSizes, + WORD_SIZE, + UNKNOWN, + wordSize; /// Checks and replaces calls to dart:ffi struct fields and methods. void transformLibraries( @@ -184,12 +192,18 @@ class _FfiUseSiteTransformer extends FfiTransformer { } else if (target == sizeOfMethod) { final DartType nativeType = node.arguments.types[0]; + // TODO(http://dartbug.com/38721): Change this to an error after + // package:ffi is no longer using sizeOf generically. if (!isFfiLibrary) { _warningNativeTypeValid(nativeType, node); } - // TODO(http://dartbug.com/38721): Replace calls with constant - // expressions. + if (nativeType is InterfaceType) { + Expression inlineSizeOf = _inlineSizeOf(nativeType); + if (inlineSizeOf != null) { + return inlineSizeOf; + } + } } else if (target == lookupFunctionMethod) { final DartType nativeType = InterfaceType( nativeFunctionClass, Nullability.legacy, [node.arguments.types[0]]); @@ -315,6 +329,28 @@ class _FfiUseSiteTransformer extends FfiTransformer { return node; } + Expression _inlineSizeOf(InterfaceType nativeType) { + final Class nativeClass = nativeType.classNode; + final NativeType nt = getType(nativeClass); + if (nt == null) { + // User-defined structs. + Field sizeOfField = nativeClass.fields.single; + return StaticGet(sizeOfField); + } + final int size = nativeTypeSizes[nt.index]; + if (size == WORD_SIZE) { + return runtimeBranchOnLayout(wordSize); + } + if (size != UNKNOWN) { + return ConstantExpression( + IntConstant(size), + InterfaceType(listClass, Nullability.legacy, + [InterfaceType(intClass, Nullability.legacy)])); + } + // Size unknown. + return null; + } + // We need to replace calls to 'DynamicLibrary.lookupFunction' with explicit // Kernel, because we cannot have a generic call to 'asFunction' in its body. // diff --git a/tests/ffi/sizeof_test.dart b/tests/ffi/sizeof_test.dart index fd02efccc79d..4fd42fd6f65a 100644 --- a/tests/ffi/sizeof_test.dart +++ b/tests/ffi/sizeof_test.dart @@ -8,6 +8,19 @@ import 'dart:ffi'; import "package:expect/expect.dart"; +import "coordinate.dart"; + +get is32Bit => 4 == sizeOf(); +get is64Bit => 8 == sizeOf(); + void main() async { - Expect.equals(true, 4 == sizeOf() || 8 == sizeOf()); + if (is32Bit) { + Expect.equals(4, sizeOf()); + Expect.equals(20, sizeOf()); + } + if (is64Bit) { + Expect.equals(8, sizeOf()); + Expect.equals(24, sizeOf()); + } + Expect.throws(() => sizeOf()); } diff --git a/tests/ffi_2/sizeof_test.dart b/tests/ffi_2/sizeof_test.dart index fd02efccc79d..4fd42fd6f65a 100644 --- a/tests/ffi_2/sizeof_test.dart +++ b/tests/ffi_2/sizeof_test.dart @@ -8,6 +8,19 @@ import 'dart:ffi'; import "package:expect/expect.dart"; +import "coordinate.dart"; + +get is32Bit => 4 == sizeOf(); +get is64Bit => 8 == sizeOf(); + void main() async { - Expect.equals(true, 4 == sizeOf() || 8 == sizeOf()); + if (is32Bit) { + Expect.equals(4, sizeOf()); + Expect.equals(20, sizeOf()); + } + if (is64Bit) { + Expect.equals(8, sizeOf()); + Expect.equals(24, sizeOf()); + } + Expect.throws(() => sizeOf()); }