From bb483f34a3d9787d2f891d2edf4438e36e2ad492 Mon Sep 17 00:00:00 2001 From: Halil Durmus Date: Mon, 9 Dec 2024 22:02:56 +0000 Subject: [PATCH] [vm/ffi] Allow configuring the variable dimension of variable-length arrays TEST=tests/ffi/* CoreLibraryReviewExempt: VM only Closes: https://github.com/dart-lang/sdk/issues/52366 Change-Id: I545a323f48d955b591cedf2dae7106d9004242e2 Cq-Include-Trybots: dart/try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-asan-linux-release-x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-msan-linux-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-tsan-linux-release-x64-try,vm-aot-ubsan-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64-try,vm-aot-win-debug-x64c-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-arm64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-arm64-try,vm-fuchsia-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-arm64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-tsan-linux-release-arm64-try,vm-tsan-linux-release-x64-try,vm-ubsan-linux-release-arm64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/398621 Reviewed-by: Johnni Winther Commit-Queue: Daco Harkes Reviewed-by: Daco Harkes Reviewed-by: Brian Wilkerson --- BUILD.gn | 3 +- .../lib/src/messages/codes_generated.dart | 11 + .../services/correction/error_fix_status.yaml | 4 +- .../lib/src/dart/error/ffi_code.g.dart | 7 + .../lib/src/error/error_code_values.g.dart | 1 + .../lib/src/generated/ffi_verifier.dart | 71 +- .../lib/src/test_utilities/mock_sdk.dart | 63 +- pkg/analyzer/messages.yaml | 75 +- .../test/src/diagnostics/ffi_array_test.dart | 204 +++ .../test/src/diagnostics/test_all.dart | 2 + pkg/analyzer/tool/diagnostics/diagnostics.md | 74 +- pkg/front_end/messages.status | 1 + pkg/front_end/messages.yaml | 5 + ...ffi_struct_inline_array.dart.strong.expect | 7 +- ...ct_inline_array.dart.strong.modular.expect | 7 +- ...ct_inline_array.dart.strong.outline.expect | 4 +- ...nline_array.dart.strong.transformed.expect | 32 +- ...array_multi_dimensional.dart.strong.expect | 13 +- ...lti_dimensional.dart.strong.modular.expect | 13 +- ...lti_dimensional.dart.strong.outline.expect | 4 +- ...dimensional.dart.strong.transformed.expect | 40 +- .../modular/transformations/ffi/common.dart | 48 +- .../transformations/ffi/definitions.dart | 11 +- .../modular/transformations/ffi/native.dart | 3 +- .../transformations/ffi/native_type_cfe.dart | 31 +- .../transformations/ffi/use_sites.dart | 7 + .../ffi/abi_specific_int.dart.aot.expect | 41 +- .../ffi/abi_specific_int.dart.expect | 16 +- ...bi_specific_int_incomplete.dart.aot.expect | 39 +- .../abi_specific_int_incomplete.dart.expect | 16 +- ...s_of_cast_compound_element.dart.aot.expect | 111 +- ...dress_of_cast_compound_element.dart.expect | 76 +- .../ffi/address_of_struct.dart.aot.expect | 93 +- .../ffi/address_of_struct.dart.expect | 44 +- .../address_of_struct_element.dart.aot.expect | 111 +- .../ffi/address_of_struct_element.dart.expect | 76 +- .../transformations/ffi/native_fields.dart | 20 + .../ffi/native_fields.dart.aot.expect | 10 +- .../ffi/native_fields.dart.expect | 252 +++- runtime/bin/ffi_test/ffi_test_functions.cc | 4 - .../ffi_test/ffi_test_functions_generated.cc | 1122 +++++++++++++++ runtime/vm/compiler/ffi/native_type.cc | 14 +- runtime/vm/symbols.h | 1 + sdk/lib/_internal/vm/lib/ffi_patch.dart | 17 +- .../_internal/vm/lib/ffi_struct_patch.dart | 5 +- sdk/lib/ffi/ffi.dart | 122 +- ...backs_structs_by_value_generated_test.dart | 61 + ..._value_native_callable_generated_test.dart | 61 + ...cts_by_value_generated_args_leaf_test.dart | 34 + ...value_generated_args_native_leaf_test.dart | 36 + ...s_by_value_generated_args_native_test.dart | 35 + ..._structs_by_value_generated_args_test.dart | 33 + ..._structs_by_value_generated_compounds.dart | 30 + ...value_generated_compounds_sizeof_test.dart | 1239 +++++++++++++++++ tests/ffi/generator/c_types.dart | 28 +- .../structs_by_value_tests_configuration.dart | 37 + .../structs_by_value_tests_generator.dart | 97 +- .../inline_array_variable_length_test.dart | 111 +- ..._sync_structs_by_value_generated_test.dart | 43 + .../vmspecific_static_checks_array_test.dart | 38 + 60 files changed, 4239 insertions(+), 575 deletions(-) create mode 100644 pkg/analyzer/test/src/diagnostics/ffi_array_test.dart create mode 100644 tests/ffi/function_structs_by_value_generated_compounds_sizeof_test.dart diff --git a/BUILD.gn b/BUILD.gn index 5ade150a003..557b395dcce 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1,6 +1,6 @@ # Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file # for details. All rights reserved. Use of this source code is governed by a -# BSD-style license that can be found in the LICENSE file. +# BSD-style license that can be found in the LICENSE file. import("build/config/gclient_args.gni") import("sdk_args.gni") @@ -258,6 +258,7 @@ if (is_fuchsia) { "tests/ffi/function_structs_by_value_generated_args_native_leaf_test.dart", "tests/ffi/function_structs_by_value_generated_args_native_test.dart", "tests/ffi/function_structs_by_value_generated_args_test.dart", + "tests/ffi/function_structs_by_value_generated_compounds_sizeof_test.dart", "tests/ffi/function_structs_by_value_generated_ret_arg_leaf_test.dart", "tests/ffi/function_structs_by_value_generated_ret_arg_native_leaf_test.dart", "tests/ffi/function_structs_by_value_generated_ret_arg_native_test.dart", diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart index b08f11ecd6e..b0cbf2f72be 100644 --- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart +++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart @@ -13365,6 +13365,17 @@ const MessageCode messageNativeClauseShouldBeAnnotation = const MessageCode( r"""Try removing this native clause and adding @native() or @native('native-name') before the declaration.""", ); +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Code codeNegativeVariableDimension = + messageNegativeVariableDimension; + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const MessageCode messageNegativeVariableDimension = const MessageCode( + "NegativeVariableDimension", + problemMessage: + r"""The variable dimension of a variable-length array must be non-negative.""", +); + // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. const Code codeNeverReachableSwitchDefaultError = messageNeverReachableSwitchDefaultError; diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml index 269a45fb4f7..69f79d95581 100644 --- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml +++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml @@ -1740,7 +1740,7 @@ FfiCode.FFI_NATIVE_MUST_BE_EXTERNAL: since: ~2.15 notes: |- The fix is to add the `external` keyword. -FfiCode.FFI_NATIVE_ONLY_CLASSES_EXTENDING_NATIVEFIELDWRAPPERCLASS1_CAN_BE_POINTER: +FfiCode.FFI_NATIVE_ONLY_CLASSES_EXTENDING_NATIVEFIELDWRAPPERCLASS1_CAN_BE_POINTER: status: noFix since: ~2.15 FfiCode.FFI_NATIVE_UNEXPECTED_NUMBER_OF_PARAMETERS: @@ -1790,6 +1790,8 @@ FfiCode.NATIVE_FIELD_MISSING_TYPE: status: needsEvaluation FfiCode.NATIVE_FIELD_NOT_STATIC: status: needsEvaluation +FfiCode.NEGATIVE_VARIABLE_DIMENSION: + status: noFix FfiCode.NON_CONSTANT_TYPE_ARGUMENT: status: noFix FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER: diff --git a/pkg/analyzer/lib/src/dart/error/ffi_code.g.dart b/pkg/analyzer/lib/src/dart/error/ffi_code.g.dart index 79c3737cd09..ea62295c9ea 100644 --- a/pkg/analyzer/lib/src/dart/error/ffi_code.g.dart +++ b/pkg/analyzer/lib/src/dart/error/ffi_code.g.dart @@ -386,6 +386,13 @@ class FfiCode extends ErrorCode { hasPublishedDocs: true, ); + /// No parameters. + static const FfiCode NEGATIVE_VARIABLE_DIMENSION = FfiCode( + 'NEGATIVE_VARIABLE_DIMENSION', + "The variable dimension of a variable-length array must be non-negative.", + correctionMessage: "Try using a value that is zero or greater.", + ); + /// Parameters: /// 0: the name of the function, method, or constructor having type arguments static const FfiCode NON_CONSTANT_TYPE_ARGUMENT = FfiCode( diff --git a/pkg/analyzer/lib/src/error/error_code_values.g.dart b/pkg/analyzer/lib/src/error/error_code_values.g.dart index 249399bee4a..95f1094acf9 100644 --- a/pkg/analyzer/lib/src/error/error_code_values.g.dart +++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart @@ -631,6 +631,7 @@ const List errorCodeValues = [ FfiCode.NATIVE_FIELD_INVALID_TYPE, FfiCode.NATIVE_FIELD_MISSING_TYPE, FfiCode.NATIVE_FIELD_NOT_STATIC, + FfiCode.NEGATIVE_VARIABLE_DIMENSION, FfiCode.NON_CONSTANT_TYPE_ARGUMENT, FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER, FfiCode.NON_POSITIVE_ARRAY_DIMENSION, diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart index 4435455e5ae..f9221eea543 100644 --- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart +++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart @@ -1991,28 +1991,54 @@ class FfiVerifier extends RecursiveAstVisitor { } } - // Check dimensions are positive. - List? getArgumentNodes() { - var arguments = annotation.arguments?.arguments; - if (arguments != null && arguments.length == 1) { - var firstArgument = arguments[0]; - if (firstArgument is ListLiteral) { - return firstArgument.elements; - } - } - return arguments; + // Check dimensions are valid. + (List? dimensionsNodes, AstNode? variableDimensionNode) + getArgumentNodes() { + return switch (annotation.arguments) { + // `@Array.variableMulti([..], variableDimension: ..)` + ArgumentList( + arguments: [ListLiteral dimensions, NamedExpression variableDimension] + ) => + (dimensions.elements, variableDimension.expression), + // `@Array.variableMulti([..])` + ArgumentList(arguments: [ListLiteral dimensions]) => ( + dimensions.elements, + null + ), + // `@Array(..)`, `@Array.variable(..)`, + // `@Array.variableWithVariableDimension(..)` + ArgumentList(arguments: NodeList dimensions) => ( + dimensions, + null + ), + _ => (null, null) + }; } + var (dimensionsNodes, variableDimensionNode) = getArgumentNodes(); + AstNode errorNode = variableDimensionNode ?? annotation; + for (int i = 0; i < dimensions.length; i++) { - if (i == 0 && variableLength) { - continue; // First dimension is variable. - } - if (dimensions[i] <= 0) { - AstNode errorNode = annotation; - var argumentNodes = getArgumentNodes(); - if (argumentNodes != null && argumentNodes.isNotEmpty) { - errorNode = argumentNodes[i]; + if (dimensionsNodes case var dimensionsNodes?) { + if (dimensionsNodes.length > i && variableDimensionNode == null) { + var node = dimensionsNodes[i]; + errorNode = node is NamedExpression ? node.expression : node; } + } + + // First dimension is variable. + if (i == 0 && variableLength) { + // Variable dimension can't be negative. + if (dimensions[0] < 0) { + _errorReporter.atNode( + errorNode, + FfiCode.NEGATIVE_VARIABLE_DIMENSION, + ); + } + continue; + } + + if (dimensions[i] <= 0) { _errorReporter.atNode( errorNode, FfiCode.NON_POSITIVE_ARRAY_DIMENSION, @@ -2093,8 +2119,8 @@ extension on ElementAnnotation { assert(isArray); var value = computeConstantValue(); - var variableLength = - value?.getField('variableLength')?.toBoolValue() ?? false; + var variableDimension = value?.getField('variableDimension')?.toIntValue(); + var variableLength = variableDimension != null; // Element of `@Array.multi([1, 2, 3])`. var listField = value?.getField('dimensions'); @@ -2105,7 +2131,10 @@ extension on ElementAnnotation { .whereType() .toList(); if (listValues != null) { - return ([if (variableLength) 0, ...listValues], variableLength); + return ( + [if (variableLength) variableDimension, ...listValues], + variableLength + ); } } diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart index 121345e4f56..2e899630f82 100644 --- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart +++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart @@ -902,20 +902,38 @@ final class DartRepresentationOf { @Since('2.13') final class Array extends _Compound { - const factory Array(int dimension1, - [int dimension2, - int dimension3, - int dimension4, - int dimension5]) = _ArraySize; + const factory Array( + int dimension1, [ + int dimension2, + int dimension3, + int dimension4, + int dimension5, + ]) = _ArraySize; const factory Array.multi(List dimensions) = _ArraySize.multi; @Since('3.6') - const factory Array.variable() = _ArraySize.variable; + const factory Array.variable([ + int dimension2, + int dimension3, + int dimension4, + int dimension5, + ]) = _ArraySize.variable; + + @Since('3.7') + const factory Array.variableWithVariableDimension([ + int dimension1, + int dimension2, + int dimension3, + int dimension4, + int dimension5, + ]) = _ArraySize.variableWithVariableDimension; @Since('3.6') - const factory Array.variableMulti(List dimensions) = - _ArraySize.variableMulti; + const factory Array.variableMulti( + List dimensions, { + @Since('3.7') int variableDimension, + }) = _ArraySize.variableMulti; } final class _ArraySize implements Array { @@ -927,7 +945,7 @@ final class _ArraySize implements Array { final List? dimensions; - final bool variableLength; + final int? variableDimension; const _ArraySize( this.dimension1, [ @@ -936,7 +954,7 @@ final class _ArraySize implements Array { this.dimension4, this.dimension5, ]) : dimensions = null, - variableLength = false; + variableDimension = null; const _ArraySize.multi(this.dimensions) : dimension1 = null, @@ -944,27 +962,36 @@ final class _ArraySize implements Array { dimension3 = null, dimension4 = null, dimension5 = null, - variableLength = false; - - static const variableLengthLength = 0; + variableDimension = null; const _ArraySize.variable([ this.dimension2, this.dimension3, this.dimension4, this.dimension5, - ]) : dimension1 = variableLengthLength, + ]) : dimension1 = 0, dimensions = null, - variableLength = true; + variableDimension = 0; - const _ArraySize.variableMulti(List nestedDimensions) - : dimensions = nestedDimensions, + const _ArraySize.variableWithVariableDimension([ + this.dimension1, + this.dimension2, + this.dimension3, + this.dimension4, + this.dimension5, + ]) : dimensions = null, + variableDimension = dimension1; + + const _ArraySize.variableMulti( + List nestedDimensions, { + int variableDimension = 0, + }) : dimensions = nestedDimensions, dimension1 = null, dimension2 = null, dimension3 = null, dimension4 = null, dimension5 = null, - variableLength = true; + variableDimension = variableDimension; } extension StructPointer on Pointer { diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml index f4b35ce7ecd..68bd3ca23df 100644 --- a/pkg/analyzer/messages.yaml +++ b/pkg/analyzer/messages.yaml @@ -20400,6 +20400,76 @@ FfiCode: NativeCallable.listener(f); } ``` + NEGATIVE_VARIABLE_DIMENSION: + problemMessage: The variable dimension of a variable-length array must be non-negative. + correctionMessage: Try using a value that is zero or greater. + hasPublishedDocs: false + comment: No parameters. + documentation: |- + #### Description + + The analyzer produces this diagnostic in two cases. + + The first is when the variable dimension given in an + `Array.variableWithVariableDimension` annotation is negative. The variable + dimension is the first argument in the annotation. + + The second is when the variable dimension given in an + `Array.variableMulti` annotation is negative. The variable dimension is + specified in the `variableDimension` argument of the annotation. + + For more information about FFI, see [C interop using dart:ffi][ffi]. + + #### Examples + + The following code produces this diagnostic because a variable dimension + of `-1` was provided in the `Array.variableWithVariableDimension` + annotation: + + ```dart + import 'dart:ffi'; + + final class MyStruct extends Struct { + @Array.variableWithVariableDimension([!-1!]) + external Array a0; + } + ``` + + The following code produces this diagnostic because a variable dimension + of `-1` was provided in the `Array.variableMulti` annotation: + + ```dart + import 'dart:ffi'; + + final class MyStruct2 extends Struct { + @Array.variableMulti(variableDimension: [!-1!], [1, 2]) + external Array>> a0; + } + ``` + + #### Common fixes + + Change the variable dimension with zero (`0`) or a positive number: + + ```dart + import 'dart:ffi'; + + final class MyStruct extends Struct { + @Array.variableWithVariableDimension(1) + external Array a0; + } + ``` + + Change the variable dimension with zero (`0`) or a positive number: + + ```dart + import 'dart:ffi'; + + final class MyStruct2 extends Struct { + @Array.variableMulti(variableDimension: 1, [1, 2]) + external Array>> a0; + } + ``` NON_CONSTANT_TYPE_ARGUMENT: problemMessage: "The type arguments to '{0}' must be known at compile time, so they can't be type parameters." correctionMessage: Try changing the type argument to be a constant type. @@ -20515,7 +20585,7 @@ FfiCode: #### Example The following code produces this diagnostic because an array dimension of - `-1` was provided: + `-8` was provided: ```dart import 'dart:ffi'; @@ -20539,7 +20609,8 @@ FfiCode: } ``` - If this is a variable length inline array, change the annotation to `Array.variable()`: + If this is a variable length inline array, change the annotation to + `Array.variable()`: ```dart import 'dart:ffi'; diff --git a/pkg/analyzer/test/src/diagnostics/ffi_array_test.dart b/pkg/analyzer/test/src/diagnostics/ffi_array_test.dart new file mode 100644 index 00000000000..aeae29081d4 --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/ffi_array_test.dart @@ -0,0 +1,204 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:analyzer/src/dart/error/ffi_code.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../dart/resolution/context_collection_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(InlineArrayTest); + }); +} + +@reflectiveTest +class InlineArrayTest extends PubPackageResolutionTest { + test_array_negativeDimension() async { + await assertErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array(-1) + external Array arr; +} +''', [error(FfiCode.NON_POSITIVE_ARRAY_DIMENSION, 67, 2)]); + } + + test_array_positiveDimension() async { + await assertNoErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array(1) + external Array arr; +} +'''); + } + + test_array_zeroDimension() async { + await assertErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array(0) + external Array arr; +} +''', [error(FfiCode.NON_POSITIVE_ARRAY_DIMENSION, 67, 1)]); + } + + test_multi_negativeDimension() async { + await assertErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.multi([-2, 2]) + external Array> arr; +} +''', [error(FfiCode.NON_POSITIVE_ARRAY_DIMENSION, 74, 2)]); + } + + test_multi_positiveDimension() async { + await assertNoErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.multi([2, 2]) + external Array> arr; +} +'''); + } + + test_multi_zeroDimension() async { + await assertErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.multi([0, 2]) + external Array> arr; +} +''', [error(FfiCode.NON_POSITIVE_ARRAY_DIMENSION, 74, 1)]); + } + + test_variable_negativeDimension() async { + await assertErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variable(-1) + external Array> arr; +} +''', [error(FfiCode.NON_POSITIVE_ARRAY_DIMENSION, 76, 2)]); + } + + test_variable_positiveDimension() async { + await assertNoErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variable(1) + external Array> arr; +} +'''); + } + + test_variable_valid() async { + await assertNoErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variable() + external Array arr; +} +'''); + } + + test_variable_zeroDimension() async { + await assertErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variable(0) + external Array> arr; +} +''', [error(FfiCode.NON_POSITIVE_ARRAY_DIMENSION, 76, 1)]); + } + + test_variableMulti_negativeDimension() async { + await assertErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variableMulti(variableDimension: -1, [2, 2]) + external Array>> arr; +} +''', [error(FfiCode.NEGATIVE_VARIABLE_DIMENSION, 100, 2)]); + } + + test_variableMulti_positiveDimension() async { + await assertNoErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variableMulti(variableDimension: 1, [2, 2]) + external Array>> arr; +} +'''); + } + + test_variableMulti_valid() async { + await assertNoErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variableMulti([2, 2]) + external Array>> arr; +} +'''); + } + + test_variableMulti_zeroDimension() async { + await assertNoErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variableMulti(variableDimension: 0, [2, 2]) + external Array>> arr; +} +'''); + } + + test_variableWithVariableDimension_negativeDimension() async { + await assertErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variableWithVariableDimension(-1) + external Array arr; +} +''', [error(FfiCode.NEGATIVE_VARIABLE_DIMENSION, 97, 2)]); + } + + test_variableWithVariableDimension_positiveDimension() async { + await assertNoErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variableWithVariableDimension(1) + external Array arr; +} +'''); + } + + test_variableWithVariableDimension_zeroDimension() async { + await assertNoErrorsInCode(r''' +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variableWithVariableDimension(0) + external Array arr; +} +'''); + } +} diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart index 324969bb59f..bcf07420ea4 100644 --- a/pkg/analyzer/test/src/diagnostics/test_all.dart +++ b/pkg/analyzer/test/src/diagnostics/test_all.dart @@ -308,6 +308,7 @@ import 'extra_positional_arguments_test.dart' as extra_positional_arguments; import 'extra_size_annotation_carray_test.dart' as extra_size_annotation_carray; import 'extraneous_modifier_test.dart' as extraneous_modifier; import 'ffi_address_of_cast_test.dart' as ffi_addresss_of_cast_test; +import 'ffi_array_test.dart' as ffi_array_test; import 'ffi_async_callback_test.dart' as ffi_async_callback_test; import 'ffi_leaf_call_must_not_use_handle_test.dart' as ffi_leaf_call_must_not_use_handle; @@ -1128,6 +1129,7 @@ main() { extra_size_annotation_carray.main(); extraneous_modifier.main(); ffi_addresss_of_cast_test.main(); + ffi_array_test.main(); ffi_async_callback_test.main(); ffi_leaf_call_must_not_use_handle.main(); ffi_native_test.main(); diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md index 5d2fa302a53..0ce095dc3d5 100644 --- a/pkg/analyzer/tool/diagnostics/diagnostics.md +++ b/pkg/analyzer/tool/diagnostics/diagnostics.md @@ -14424,6 +14424,75 @@ final class C extends Struct { } ``` +### negative_variable_dimension + +_The variable dimension of a variable-length array must be non-negative._ + +#### Description + +The analyzer produces this diagnostic in two cases. + +The first is when the variable dimension given in an +`Array.variableWithVariableDimension` annotation is negative. The variable +dimension is the first argument in the annotation. + +The second is when the variable dimension given in an +`Array.variableMulti` annotation is negative. The variable dimension is +specified in the `variableDimension` argument of the annotation. + +For more information about FFI, see [C interop using dart:ffi][ffi]. + +#### Examples + +The following code produces this diagnostic because a variable dimension +of `-1` was provided in the `Array.variableWithVariableDimension` +annotation: + +```dart +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variableWithVariableDimension([!-1!]) + external Array a0; +} +``` + +The following code produces this diagnostic because a variable dimension +of `-1` was provided in the `Array.variableMulti` annotation: + +```dart +import 'dart:ffi'; + +final class MyStruct2 extends Struct { + @Array.variableMulti(variableDimension: [!-1!], [1, 2]) + external Array>> a0; +} +``` + +#### Common fixes + +Change the variable dimension with zero (`0`) or a positive number: + +```dart +import 'dart:ffi'; + +final class MyStruct extends Struct { + @Array.variableWithVariableDimension(1) + external Array a0; +} +``` + +Change the variable dimension with zero (`0`) or a positive number: + +```dart +import 'dart:ffi'; + +final class MyStruct2 extends Struct { + @Array.variableMulti(variableDimension: 1, [1, 2]) + external Array>> a0; +} +``` + ### new_with_undefined_constructor_default _The class '{0}' doesn't have an unnamed constructor._ @@ -15718,7 +15787,7 @@ For more information about FFI, see [C interop using dart:ffi][ffi]. #### Example The following code produces this diagnostic because an array dimension of -`-1` was provided: +`-8` was provided: ```dart import 'dart:ffi'; @@ -15742,7 +15811,8 @@ final class MyStruct extends Struct { } ``` -If this is a variable length inline array, change the annotation to `Array.variable()`: +If this is a variable length inline array, change the annotation to +`Array.variable()`: ```dart import 'dart:ffi'; diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status index 4d32852ece9..0fdf3233c42 100644 --- a/pkg/front_end/messages.status +++ b/pkg/front_end/messages.status @@ -780,6 +780,7 @@ NamedMixinOverride/analyzerCode: Fail NamedMixinOverride/example: Fail NamedParametersInExtensionTypeDeclaration/analyzerCode: Fail NativeClauseShouldBeAnnotation/example: Fail +NegativeVariableDimension/analyzerCode: Fail NeverReachableSwitchDefaultError/analyzerCode: Fail NeverReachableSwitchDefaultError/example: Fail NeverReachableSwitchDefaultWarning/analyzerCode: Fail diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml index f592f4a3fe2..93e0b7b095c 100644 --- a/pkg/front_end/messages.yaml +++ b/pkg/front_end/messages.yaml @@ -5432,6 +5432,11 @@ NonNullAwareSpreadIsNull: [...null]; } +NegativeVariableDimension: + # Used by dart:ffi + problemMessage: "The variable dimension of a variable-length array must be non-negative." + external: test/ffi_test.dart + NonPositiveArrayDimensions: # Used by dart:ffi problemMessage: "Array dimensions must be positive numbers." diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect index 7d8879871dc..faccb90b269 100644 --- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect +++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect @@ -9,9 +9,9 @@ final class StructInlineArray extends ffi::Struct { synthetic constructor •() → self::StructInlineArray : super ffi::Struct::•() ; - @#C4 + @#C3 external get a0() → ffi::Array; - @#C4 + @#C3 external set a0(synthesized ffi::Array #externalFieldValue) → void; } static method main() → dynamic {} @@ -19,8 +19,7 @@ static method main() → dynamic {} constants { #C1 = 8 #C2 = null - #C3 = false - #C4 = ffi::_ArraySize {dimension1:#C1, dimension2:#C2, dimension3:#C2, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableLength:#C3} + #C3 = ffi::_ArraySize {dimension1:#C1, dimension2:#C2, dimension3:#C2, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableDimension:#C2} } diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.modular.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.modular.expect index 7d8879871dc..faccb90b269 100644 --- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.modular.expect +++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.modular.expect @@ -9,9 +9,9 @@ final class StructInlineArray extends ffi::Struct { synthetic constructor •() → self::StructInlineArray : super ffi::Struct::•() ; - @#C4 + @#C3 external get a0() → ffi::Array; - @#C4 + @#C3 external set a0(synthesized ffi::Array #externalFieldValue) → void; } static method main() → dynamic {} @@ -19,8 +19,7 @@ static method main() → dynamic {} constants { #C1 = 8 #C2 = null - #C3 = false - #C4 = ffi::_ArraySize {dimension1:#C1, dimension2:#C2, dimension3:#C2, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableLength:#C3} + #C3 = ffi::_ArraySize {dimension1:#C1, dimension2:#C2, dimension3:#C2, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableDimension:#C2} } diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.outline.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.outline.expect index 5eb6facdfbe..c7ca3800615 100644 --- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.outline.expect +++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.outline.expect @@ -18,6 +18,6 @@ static method main() → dynamic Extra constant evaluation status: -Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array.dart:10:4 -> InstanceConstant(const _ArraySize{_ArraySize.dimension1: 8, _ArraySize.dimension2: null, _ArraySize.dimension3: null, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null, _ArraySize.variableLength: false}) -Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array.dart:10:4 -> InstanceConstant(const _ArraySize{_ArraySize.dimension1: 8, _ArraySize.dimension2: null, _ArraySize.dimension3: null, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null, _ArraySize.variableLength: false}) +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array.dart:10:4 -> InstanceConstant(const _ArraySize{_ArraySize.dimension1: 8, _ArraySize.dimension2: null, _ArraySize.dimension3: null, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null, _ArraySize.variableDimension: null}) +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array.dart:10:4 -> InstanceConstant(const _ArraySize{_ArraySize.dimension1: 8, _ArraySize.dimension2: null, _ArraySize.dimension3: null, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null, _ArraySize.variableDimension: null}) Extra constant evaluation: evaluated: 2, effectively constant: 2 diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect index 5de6c77ab53..7654b416785 100644 --- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect @@ -7,7 +7,7 @@ import "dart:typed_data" as typ; import "dart:ffi"; import "package:ffi/ffi.dart"; -@#C8 +@#C9 final class StructInlineArray extends ffi::Struct { synthetic constructor •() → self::StructInlineArray : super ffi::Struct::•() @@ -15,22 +15,22 @@ final class StructInlineArray extends ffi::Struct { constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::StructInlineArray : super ffi::Struct::_fromTypedDataBase(#typedDataBase, #offsetInBytes) ; - @#C10 + @#C11 constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::StructInlineArray : super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes) ; @#C12 - @#C10 + @#C11 get a0() → ffi::Array - return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::StructInlineArray::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C13); + return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::StructInlineArray::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C13); @#C12 - @#C10 + @#C11 set a0(synthesized ffi::Array #externalFieldValue) → void return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::StructInlineArray::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C14.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); - @#C10 + @#C11 static get a0#offsetOf() → core::int return #C16.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C10 + @#C11 static get #sizeOf() → core::int return #C14.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } @@ -40,15 +40,15 @@ constants { #C1 = "vm:ffi:struct-fields" #C2 = TypeLiteralConstant(ffi::Uint8) #C3 = 8 - #C4 = ffi::_FfiInlineArray {elementType:#C2, length:#C3} - #C5 = [#C4] - #C6 = null - #C7 = ffi::_FfiStructLayout {fieldTypes:#C5, packing:#C6} - #C8 = core::pragma {name:#C1, options:#C7} - #C9 = "vm:prefer-inline" - #C10 = core::pragma {name:#C9, options:#C6} - #C11 = false - #C12 = ffi::_ArraySize {dimension1:#C3, dimension2:#C6, dimension3:#C6, dimension4:#C6, dimension5:#C6, dimensions:#C6, variableLength:#C11} + #C4 = false + #C5 = ffi::_FfiInlineArray {elementType:#C2, length:#C3, variableLength:#C4} + #C6 = [#C5] + #C7 = null + #C8 = ffi::_FfiStructLayout {fieldTypes:#C6, packing:#C7} + #C9 = core::pragma {name:#C1, options:#C8} + #C10 = "vm:prefer-inline" + #C11 = core::pragma {name:#C10, options:#C7} + #C12 = ffi::_ArraySize {dimension1:#C3, dimension2:#C7, dimension3:#C7, dimension4:#C7, dimension5:#C7, dimensions:#C7, variableDimension:#C7} #C13 = [] #C14 = [#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3] #C15 = 0 diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect index a0bcd8775c5..38d4baa1af3 100644 --- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect +++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect @@ -10,26 +10,25 @@ final class StructInlineArrayMultiDimensional extends ffi::Struct { synthetic constructor •() → self::StructInlineArrayMultiDimensional : super ffi::Struct::•() ; - @#C4 + @#C3 external get a0() → ffi::Array>>; - @#C4 + @#C3 external set a0(synthesized ffi::Array>> #externalFieldValue) → void; } static method main() → dynamic { - final ffi::Pointer pointer = ffi::AllocatorAlloc|call(#C5); + final ffi::Pointer pointer = ffi::AllocatorAlloc|call(#C4); final self::StructInlineArrayMultiDimensional struct = ffi::StructPointer|get#ref(pointer); final ffi::Array>> array = struct.{self::StructInlineArrayMultiDimensional::a0}{ffi::Array>>}; final ffi::Array> subArray = ffi::ArrayArray|[]>(array, 0); ffi::ArrayArray|[]=>(array, 1, subArray); - #C5.{all::CallocAllocator::free}(pointer){(ffi::Pointer) → void}; + #C4.{all::CallocAllocator::free}(pointer){(ffi::Pointer) → void}; } constants { #C1 = 2 #C2 = null - #C3 = false - #C4 = ffi::_ArraySize {dimension1:#C1, dimension2:#C1, dimension3:#C1, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableLength:#C3} - #C5 = all::CallocAllocator {} + #C3 = ffi::_ArraySize {dimension1:#C1, dimension2:#C1, dimension3:#C1, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableDimension:#C2} + #C4 = all::CallocAllocator {} } diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.modular.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.modular.expect index a0bcd8775c5..38d4baa1af3 100644 --- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.modular.expect +++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.modular.expect @@ -10,26 +10,25 @@ final class StructInlineArrayMultiDimensional extends ffi::Struct { synthetic constructor •() → self::StructInlineArrayMultiDimensional : super ffi::Struct::•() ; - @#C4 + @#C3 external get a0() → ffi::Array>>; - @#C4 + @#C3 external set a0(synthesized ffi::Array>> #externalFieldValue) → void; } static method main() → dynamic { - final ffi::Pointer pointer = ffi::AllocatorAlloc|call(#C5); + final ffi::Pointer pointer = ffi::AllocatorAlloc|call(#C4); final self::StructInlineArrayMultiDimensional struct = ffi::StructPointer|get#ref(pointer); final ffi::Array>> array = struct.{self::StructInlineArrayMultiDimensional::a0}{ffi::Array>>}; final ffi::Array> subArray = ffi::ArrayArray|[]>(array, 0); ffi::ArrayArray|[]=>(array, 1, subArray); - #C5.{all::CallocAllocator::free}(pointer){(ffi::Pointer) → void}; + #C4.{all::CallocAllocator::free}(pointer){(ffi::Pointer) → void}; } constants { #C1 = 2 #C2 = null - #C3 = false - #C4 = ffi::_ArraySize {dimension1:#C1, dimension2:#C1, dimension3:#C1, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableLength:#C3} - #C5 = all::CallocAllocator {} + #C3 = ffi::_ArraySize {dimension1:#C1, dimension2:#C1, dimension3:#C1, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableDimension:#C2} + #C4 = all::CallocAllocator {} } diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.outline.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.outline.expect index e0cfe940469..f333f6e3d97 100644 --- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.outline.expect +++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.outline.expect @@ -18,6 +18,6 @@ static method main() → dynamic Extra constant evaluation status: -Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:10:4 -> InstanceConstant(const _ArraySize{_ArraySize.dimension1: 2, _ArraySize.dimension2: 2, _ArraySize.dimension3: 2, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null, _ArraySize.variableLength: false}) -Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:10:4 -> InstanceConstant(const _ArraySize{_ArraySize.dimension1: 2, _ArraySize.dimension2: 2, _ArraySize.dimension3: 2, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null, _ArraySize.variableLength: false}) +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:10:4 -> InstanceConstant(const _ArraySize{_ArraySize.dimension1: 2, _ArraySize.dimension2: 2, _ArraySize.dimension3: 2, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null, _ArraySize.variableDimension: null}) +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:10:4 -> InstanceConstant(const _ArraySize{_ArraySize.dimension1: 2, _ArraySize.dimension2: 2, _ArraySize.dimension3: 2, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null, _ArraySize.variableDimension: null}) Extra constant evaluation: evaluated: 2, effectively constant: 2 diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect index b1cae798cf1..46629097753 100644 --- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect @@ -8,7 +8,7 @@ import "package:ffi/src/allocation.dart" as all; import "dart:ffi"; import "package:ffi/ffi.dart"; -@#C8 +@#C9 final class StructInlineArrayMultiDimensional extends ffi::Struct { synthetic constructor •() → self::StructInlineArrayMultiDimensional : super ffi::Struct::•() @@ -16,22 +16,22 @@ final class StructInlineArrayMultiDimensional extends ffi::Struct { constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::StructInlineArrayMultiDimensional : super ffi::Struct::_fromTypedDataBase(#typedDataBase, #offsetInBytes) ; - @#C10 + @#C11 constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::StructInlineArrayMultiDimensional : super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes) ; @#C13 - @#C10 + @#C11 get a0() → ffi::Array>> - return new ffi::Array::_>>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::StructInlineArrayMultiDimensional::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C11, #C14); + return new ffi::Array::_>>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::StructInlineArrayMultiDimensional::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C12, #C4, #C14); @#C13 - @#C10 + @#C11 set a0(synthesized ffi::Array>> #externalFieldValue) → void return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::StructInlineArrayMultiDimensional::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); - @#C10 + @#C11 static get a0#offsetOf() → core::int return #C17.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C10 + @#C11 static get #sizeOf() → core::int return #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } @@ -46,7 +46,7 @@ static method main() → dynamic { synthesized core::int #singleElementSize = #C19; synthesized core::int #elementSize = #singleElementSize.{core::num::*}(#array.{ffi::Array::_nestedDimensionsFlattened}{core::int}){(core::num) → core::num}; synthesized core::int #offset = #elementSize.{core::num::*}(#index){(core::num) → core::num}; - } =>new ffi::Array::_>(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, #array.{ffi::Array::_nestedDimensionsRest}{core::List}); + } =>new ffi::Array::_>(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, #array.{ffi::Array::_variableLength}{core::bool}, #array.{ffi::Array::_nestedDimensionsRest}{core::List}); block { synthesized ffi::Array #array = array!; synthesized core::int #index = 1!; @@ -63,17 +63,17 @@ constants { #C1 = "vm:ffi:struct-fields" #C2 = TypeLiteralConstant(ffi::Uint8) #C3 = 8 - #C4 = ffi::_FfiInlineArray {elementType:#C2, length:#C3} - #C5 = [#C4] - #C6 = null - #C7 = ffi::_FfiStructLayout {fieldTypes:#C5, packing:#C6} - #C8 = core::pragma {name:#C1, options:#C7} - #C9 = "vm:prefer-inline" - #C10 = core::pragma {name:#C9, options:#C6} - #C11 = 2 - #C12 = false - #C13 = ffi::_ArraySize {dimension1:#C11, dimension2:#C11, dimension3:#C11, dimension4:#C6, dimension5:#C6, dimensions:#C6, variableLength:#C12} - #C14 = [#C11, #C11] + #C4 = false + #C5 = ffi::_FfiInlineArray {elementType:#C2, length:#C3, variableLength:#C4} + #C6 = [#C5] + #C7 = null + #C8 = ffi::_FfiStructLayout {fieldTypes:#C6, packing:#C7} + #C9 = core::pragma {name:#C1, options:#C8} + #C10 = "vm:prefer-inline" + #C11 = core::pragma {name:#C10, options:#C7} + #C12 = 2 + #C13 = ffi::_ArraySize {dimension1:#C12, dimension2:#C12, dimension3:#C12, dimension4:#C7, dimension5:#C7, dimensions:#C7, variableDimension:#C7} + #C14 = [#C12, #C12] #C15 = [#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3] #C16 = 0 #C17 = [#C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16] @@ -84,7 +84,7 @@ constants { Extra constant evaluation status: Evaluated: NullCheck @ org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:18:25 -> IntConstant(0) Evaluated: NullCheck @ org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:19:8 -> IntConstant(1) -Extra constant evaluation: evaluated: 91, effectively constant: 2 +Extra constant evaluation: evaluated: 93, effectively constant: 2 Constructor coverage from constants: diff --git a/pkg/vm/lib/modular/transformations/ffi/common.dart b/pkg/vm/lib/modular/transformations/ffi/common.dart index 8c6c519d0a1..5b54bd34829 100644 --- a/pkg/vm/lib/modular/transformations/ffi/common.dart +++ b/pkg/vm/lib/modular/transformations/ffi/common.dart @@ -14,6 +14,7 @@ import 'package:front_end/src/codes/cfe_codes.dart' messageFfiLeafCallMustNotReturnHandle, messageFfiLeafCallMustNotTakeHandle, messageFfiVariableLengthArrayNotLast, + messageNegativeVariableDimension, messageNonPositiveArrayDimensions, templateFfiSizeAnnotation, templateFfiSizeAnnotationDimensions, @@ -224,7 +225,7 @@ class FfiTransformer extends Transformer { final Field arraySizeDimension4Field; final Field arraySizeDimension5Field; final Field arraySizeDimensionsField; - final Field arraySizeVariableLengthField; + final Field arraySizeVariableDimensionField; final Class pointerClass; final Class compoundClass; final Class structClass; @@ -241,6 +242,7 @@ class FfiTransformer extends Transformer { final Class ffiInlineArrayClass; final Field ffiInlineArrayElementTypeField; final Field ffiInlineArrayLengthField; + final Field ffiInlineArrayVariableLengthField; final Class packedClass; final Field packedMemberAlignmentField; final Procedure allocateMethod; @@ -286,6 +288,7 @@ class FfiTransformer extends Transformer { final Field compoundTypedDataBaseField; final Field compoundOffsetInBytesField; final Field arraySizeField; + final Field arrayVariableLengthField; final Field arrayNestedDimensionsField; final Procedure arrayCheckIndex; final Procedure arrayNestedDimensionsFlattened; @@ -415,8 +418,8 @@ class FfiTransformer extends Transformer { index.getField('dart:ffi', '_ArraySize', 'dimension5'), arraySizeDimensionsField = index.getField('dart:ffi', '_ArraySize', 'dimensions'), - arraySizeVariableLengthField = - index.getField('dart:ffi', '_ArraySize', 'variableLength'), + arraySizeVariableDimensionField = + index.getField('dart:ffi', '_ArraySize', 'variableDimension'), pointerClass = index.getClass('dart:ffi', 'Pointer'), compoundClass = index.getClass('dart:ffi', '_Compound'), structClass = index.getClass('dart:ffi', 'Struct'), @@ -442,6 +445,8 @@ class FfiTransformer extends Transformer { index.getField('dart:ffi', '_FfiInlineArray', 'elementType'), ffiInlineArrayLengthField = index.getField('dart:ffi', '_FfiInlineArray', 'length'), + ffiInlineArrayVariableLengthField = + index.getField('dart:ffi', '_FfiInlineArray', 'variableLength'), packedClass = index.getClass('dart:ffi', 'Packed'), packedMemberAlignmentField = index.getField('dart:ffi', 'Packed', 'memberAlignment'), @@ -458,6 +463,8 @@ class FfiTransformer extends Transformer { compoundOffsetInBytesField = index.getField('dart:ffi', '_Compound', '_offsetInBytes'), arraySizeField = index.getField('dart:ffi', 'Array', '_size'), + arrayVariableLengthField = + index.getField('dart:ffi', 'Array', '_variableLength'), arrayNestedDimensionsField = index.getField('dart:ffi', 'Array', '_nestedDimensions'), arrayCheckIndex = @@ -1025,10 +1032,19 @@ class FfiTransformer extends Transformer { node.fileUri, ); } - return dimensions; // Variable length single dimension. } - for (var dimension in dimensions) { - if (dimension <= 0) { + for (var i = 0; i < dimensions.length; i++) { + // First dimension is variable. + if (i == 0 && variableLength) { + // Variable dimension can't be negative. + if (dimensions[0] < 0) { + diagnosticReporter.report(messageNegativeVariableDimension, + node.fileOffset, node.name.text.length, node.fileUri); + } + continue; + } + + if (dimensions[i] <= 0) { diagnosticReporter.report(messageNonPositiveArrayDimensions, node.fileOffset, node.name.text.length, node.fileUri); success = false; @@ -1062,18 +1078,18 @@ class FfiTransformer extends Transformer { /// Reads the dimensions from a constant instance of `_ArraySize`. (List, bool) _arraySize(InstanceConstant constant) { - final variableLength = - (constant.fieldValues[arraySizeVariableLengthField.fieldReference] - as BoolConstant) - .value; + final variableDimension = + constant.fieldValues[arraySizeVariableDimensionField.fieldReference]; + final variableLength = variableDimension is IntConstant; final dimensions = constant.fieldValues[arraySizeDimensionsField.fieldReference]; - if (dimensions != null) { - if (dimensions is ListConstant) { - final result = - dimensions.entries.whereType().map((e) => e.value); - return ([if (variableLength) 0, ...result], variableLength); - } + if (dimensions is ListConstant) { + final result = + dimensions.entries.whereType().map((e) => e.value); + return ( + [if (variableLength) variableDimension.value, ...result], + variableLength, + ); } final dimensionFields = [ arraySizeDimension1Field, diff --git a/pkg/vm/lib/modular/transformations/ffi/definitions.dart b/pkg/vm/lib/modular/transformations/ffi/definitions.dart index 3d532e2965a..43da4f94870 100644 --- a/pkg/vm/lib/modular/transformations/ffi/definitions.dart +++ b/pkg/vm/lib/modular/transformations/ffi/definitions.dart @@ -683,6 +683,7 @@ class _FfiDefinitionTransformer extends FfiTransformer { final sizeAnnotations = getArraySizeAnnotations(m).toList(); if (sizeAnnotations.length == 1) { final arrayDimensions = sizeAnnotations.single.$1; + final variableLength = sizeAnnotations.single.$2; if (this.arrayDimensions(dartType) == arrayDimensions.length) { final elementType = arraySingleElementType(dartType); if (elementType is! InterfaceType) { @@ -691,7 +692,8 @@ class _FfiDefinitionTransformer extends FfiTransformer { } else { type = NativeTypeCfe(this, dartType, compoundCache: compoundCache, - arrayDimensions: arrayDimensions); + arrayDimensions: arrayDimensions, + variableLength: variableLength); } } else { type = InvalidNativeTypeCfe("Invalid array dimensions."); @@ -903,7 +905,12 @@ class _FfiDefinitionTransformer extends FfiTransformer { fieldType.fieldValues[ffiInlineArrayLengthField.fieldReference] as IntConstant; final arrayLength = arrayLengthConstant.value; - members.add(ArrayNativeTypeCfe(singleElementType, arrayLength)); + final variableLengthConstant = fieldType + .fieldValues[ffiInlineArrayVariableLengthField.fieldReference] + as BoolConstant; + final variableLength = variableLengthConstant.value; + members.add( + ArrayNativeTypeCfe(singleElementType, arrayLength, variableLength)); } } if (compoundClass.superclass == structClass) { diff --git a/pkg/vm/lib/modular/transformations/ffi/native.dart b/pkg/vm/lib/modular/transformations/ffi/native.dart index 3143afe1f7e..5dee1ed02e0 100644 --- a/pkg/vm/lib/modular/transformations/ffi/native.dart +++ b/pkg/vm/lib/modular/transformations/ffi/native.dart @@ -767,7 +767,8 @@ class FfiNativeTransformer extends FfiTransformer { final dimensions = ensureArraySizeAnnotation(node, ffiType, false); return ( ffiType, - NativeTypeCfe.withoutLayout(this, dartType, arrayDimensions: dimensions) + NativeTypeCfe.withoutLayout(this, dartType, + arrayDimensions: dimensions, variableLength: false) ); } diff --git a/pkg/vm/lib/modular/transformations/ffi/native_type_cfe.dart b/pkg/vm/lib/modular/transformations/ffi/native_type_cfe.dart index 272352cb65b..14f3a9c7c32 100644 --- a/pkg/vm/lib/modular/transformations/ffi/native_type_cfe.dart +++ b/pkg/vm/lib/modular/transformations/ffi/native_type_cfe.dart @@ -22,13 +22,14 @@ sealed class NativeTypeCfe { FfiTransformer transformer, DartType dartType, { List? arrayDimensions, + bool? variableLength, }) { if (transformer.isStructOrUnionSubtype(dartType)) { return ReferencedCompoundSubtypeCfe( (dartType as InterfaceType).classNode); } else { return NativeTypeCfe(transformer, dartType, - arrayDimensions: arrayDimensions); + arrayDimensions: arrayDimensions, variableLength: variableLength); } } @@ -36,6 +37,7 @@ sealed class NativeTypeCfe { FfiTransformer transformer, DartType dartType, { List? arrayDimensions, + bool? variableLength, Map compoundCache = const {}, bool alreadyInAbiSpecificType = false, }) { @@ -62,13 +64,17 @@ sealed class NativeTypeCfe { if (arrayDimensions.isEmpty) { throw "Must have a size for this array dimension."; } + if (variableLength == null) { + throw "Must have variable length for ArrayType."; + } final elementType = transformer.arraySingleElementType(dartType); - final elementCfeType = - NativeTypeCfe(transformer, elementType, compoundCache: compoundCache); + final elementCfeType = NativeTypeCfe(transformer, elementType, + compoundCache: compoundCache, variableLength: variableLength); if (elementCfeType is InvalidNativeTypeCfe) { return elementCfeType; } - return ArrayNativeTypeCfe.multi(elementCfeType, arrayDimensions); + return ArrayNativeTypeCfe.multi( + elementCfeType, arrayDimensions, variableLength); } if (transformer.isAbiSpecificIntegerSubtype(dartType)) { final clazz = (dartType as InterfaceType).classNode; @@ -741,17 +747,21 @@ class ReferencedCompoundSubtypeCfe extends NativeTypeCfe class ArrayNativeTypeCfe extends NativeTypeCfe { final NativeTypeCfe elementType; final int length; + final bool variableLength; - ArrayNativeTypeCfe(this.elementType, this.length) : super._(); + ArrayNativeTypeCfe(this.elementType, this.length, this.variableLength) + : super._(); factory ArrayNativeTypeCfe.multi( - NativeTypeCfe elementType, List dimensions) { + NativeTypeCfe elementType, List dimensions, bool variableLength) { if (dimensions.length == 1) { - return ArrayNativeTypeCfe(elementType, dimensions.single); + return ArrayNativeTypeCfe(elementType, dimensions.single, variableLength); } return ArrayNativeTypeCfe( - ArrayNativeTypeCfe.multi(elementType, dimensions.sublist(1)), + ArrayNativeTypeCfe.multi( + elementType, dimensions.sublist(1), variableLength), dimensions.first, + variableLength, ); } @@ -798,7 +808,9 @@ class ArrayNativeTypeCfe extends NativeTypeCfe { transformer.ffiInlineArrayElementTypeField.fieldReference: singleElementType.generateConstant(transformer), transformer.ffiInlineArrayLengthField.fieldReference: - IntConstant(dimensionsFlattened) + IntConstant(dimensionsFlattened), + transformer.ffiInlineArrayVariableLengthField.fieldReference: + BoolConstant(variableLength), }, ); @@ -830,6 +842,7 @@ class ArrayNativeTypeCfe extends NativeTypeCfe { typedDataBase, offsetInBytes, ConstantExpression(IntConstant(length)), + ConstantExpression(BoolConstant(variableLength)), transformer.intListConstantExpression( nestedDimensions, Nullability.nonNullable) ], diff --git a/pkg/vm/lib/modular/transformations/ffi/use_sites.dart b/pkg/vm/lib/modular/transformations/ffi/use_sites.dart index 96dfb9e7510..42b4cc73163 100644 --- a/pkg/vm/lib/modular/transformations/ffi/use_sites.dart +++ b/pkg/vm/lib/modular/transformations/ffi/use_sites.dart @@ -1217,6 +1217,13 @@ mixin _FfiUseSiteTransformer on FfiTransformer { arrayNestedDimensionsFirst.name, interfaceTarget: arrayNestedDimensionsFirst, resultType: arrayNestedDimensionsFirst.getterType), + InstanceGet( + InstanceAccessKind.Instance, + VariableGet(arrayVar), + arrayVariableLengthField.name, + interfaceTarget: arrayVariableLengthField, + resultType: arrayVariableLengthField.type, + ), InstanceGet(InstanceAccessKind.Instance, VariableGet(arrayVar), arrayNestedDimensionsRest.name, interfaceTarget: arrayNestedDimensionsRest, diff --git a/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart.aot.expect b/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart.aot.expect index 930f4151d59..15ecd474585 100644 --- a/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart.aot.expect +++ b/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart.aot.expect @@ -46,7 +46,7 @@ final class WCharStruct extends ffi::Struct { static get #sizeOf() → core::int return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } -@#C27 +@#C28 final class WCharArrayStruct extends ffi::Struct { constructor #fromTypedDataBase([@vm.inferred-arg-type.metadata=dart.ffi::Pointer] synthesized core::Object #typedDataBase) → self::WCharArrayStruct : super ffi::Struct::_fromTypedDataBase(#typedDataBase) @@ -56,7 +56,7 @@ final class WCharArrayStruct extends ffi::Struct { [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:3] @#C10 get a0() → ffi::Array - return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::WCharArrayStruct::a0#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C23, #C28); + return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::WCharArrayStruct::a0#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C23, #C24, #C29); [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 0)] [@vm.unboxing-info.metadata=()->i] @@ -68,7 +68,7 @@ final class WCharArrayStruct extends ffi::Struct { [@vm.unboxing-info.metadata=()->i] @#C10 static get #sizeOf() → core::int - return #C31.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C32.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } class _DummyAllocator extends core::Object implements ffi::Allocator /*hasConstConstructor*/ { @@ -100,35 +100,35 @@ static method testSizeOf() → void { [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] static method testStoreLoad() → void { - final ffi::Pointer p = let final core::int #t1 = [@vm.inferred-type.metadata=dart.core::_Smi] self::WChar::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C32.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; + final ffi::Pointer p = let final core::int #t1 = [@vm.inferred-type.metadata=dart.core::_Smi] self::WChar::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C33.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; ffi::_storeAbiSpecificInt(p, #C19, 10); core::print([@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificInt(p, #C19)); - [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C32.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; + [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C33.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; } [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] static method testStoreLoadIndexed() → void { - final ffi::Pointer p = let final core::num #t2 = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] 2.{core::num::*}([@vm.inferred-type.metadata=dart.core::_Smi] self::WChar::#sizeOf){(core::num) → core::num} in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C32.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; + final ffi::Pointer p = let final core::num #t2 = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] 2.{core::num::*}([@vm.inferred-type.metadata=dart.core::_Smi] self::WChar::#sizeOf){(core::num) → core::num} in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C33.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; ffi::_storeAbiSpecificIntAtIndex(p, #C19, 0, 10); ffi::_storeAbiSpecificIntAtIndex(p, #C19, 1, 3); core::print([@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificIntAtIndex(p, #C19, 0)); core::print([@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificIntAtIndex(p, #C19, 1)); - [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C32.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; + [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C33.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; } [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] static method testStruct() → void { - final ffi::Pointer p = let final core::int #t3 = [@vm.inferred-type.metadata=dart.core::_Smi] self::WCharStruct::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C32.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; + final ffi::Pointer p = let final core::int #t3 = [@vm.inferred-type.metadata=dart.core::_Smi] self::WCharStruct::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C33.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; [@vm.direct-call.metadata=#lib::WCharStruct.a0] [@vm.inferred-type.metadata=!? (skip check)] new self::WCharStruct::#fromTypedDataBase(_in::unsafeCast>(p)).{self::WCharStruct::a0} = 1; core::print([@vm.direct-call.metadata=#lib::WCharStruct.a0] [@vm.inferred-type.metadata=int] new self::WCharStruct::#fromTypedDataBase(_in::unsafeCast>(p)).{self::WCharStruct::a0}{core::int}); [@vm.direct-call.metadata=#lib::WCharStruct.a0] [@vm.inferred-type.metadata=!? (skip check)] new self::WCharStruct::#fromTypedDataBase(_in::unsafeCast>(p)).{self::WCharStruct::a0} = 2; core::print([@vm.direct-call.metadata=#lib::WCharStruct.a0] [@vm.inferred-type.metadata=int] new self::WCharStruct::#fromTypedDataBase(_in::unsafeCast>(p)).{self::WCharStruct::a0}{core::int}); - [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C32.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; + [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C33.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; } [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] static method testInlineArray() → void { - final ffi::Pointer p = let final core::int #t4 = [@vm.inferred-type.metadata=dart.core::_Smi] self::WCharArrayStruct::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C32.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; + final ffi::Pointer p = let final core::int #t4 = [@vm.inferred-type.metadata=dart.core::_Smi] self::WCharArrayStruct::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C33.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; final ffi::Array array = [@vm.direct-call.metadata=#lib::WCharArrayStruct.a0] [@vm.inferred-type.metadata=dart.ffi::Array<#lib::WChar>] new self::WCharArrayStruct::#fromTypedDataBase(_in::unsafeCast>(p)).{self::WCharArrayStruct::a0}{ffi::Array}; for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation.<] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i.{core::num::<}(100){(core::num) → core::bool}; i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1){(core::num) → core::int}) { block { @@ -144,7 +144,7 @@ static method testInlineArray() → void { [@vm.direct-call.metadata=dart.ffi::Array._checkIndex] [@vm.inferred-type.metadata=!? (skip check)] #array.{ffi::Array::_checkIndex}(#index){(core::int) → void}; } =>[@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificIntAtIndex([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}, #index)); } - [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C32.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; + [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C33.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; } constants { #C1 = "vm:ffi:abi-specific-mapping" @@ -170,13 +170,14 @@ constants { #C21 = 8 #C22 = [#C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C11, #C11, #C11] #C23 = 100 - #C24 = ffi::_FfiInlineArray {elementType:#C15, length:#C23} - #C25 = [#C24] - #C26 = ffi::_FfiStructLayout {fieldTypes:#C25, packing:#C9} - #C27 = core::pragma {name:#C14, options:#C26} - #C28 = [] - #C29 = 400 - #C30 = 200 - #C31 = [#C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C29, #C30, #C30, #C30] - #C32 = self::_DummyAllocator {} + #C24 = false + #C25 = ffi::_FfiInlineArray {elementType:#C15, length:#C23, variableLength:#C24} + #C26 = [#C25] + #C27 = ffi::_FfiStructLayout {fieldTypes:#C26, packing:#C9} + #C28 = core::pragma {name:#C14, options:#C27} + #C29 = [] + #C30 = 400 + #C31 = 200 + #C32 = [#C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C30, #C31, #C31, #C31] + #C33 = self::_DummyAllocator {} } diff --git a/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart.expect b/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart.expect index b4d92ca10f7..5ab8da5a1e5 100644 --- a/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart.expect +++ b/pkg/vm/testcases/transformations/ffi/abi_specific_int.dart.expect @@ -54,7 +54,7 @@ final class WCharStruct extends ffi::Struct { static get #sizeOf() → core::int return #C77.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } -@#C82 +@#C83 final class WCharArrayStruct extends ffi::Struct { synthetic constructor •() → self::WCharArrayStruct : super ffi::Struct::•() @@ -69,7 +69,7 @@ final class WCharArrayStruct extends ffi::Struct { @#C84 @#C67 get a0() → ffi::Array - return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::WCharArrayStruct::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C78, #C85); + return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::WCharArrayStruct::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C78, #C79, #C85); @#C84 @#C67 set a0(synthesized ffi::Array #externalFieldValue) → void @@ -224,12 +224,12 @@ constants { #C76 = 8 #C77 = [#C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C76, #C41, #C41, #C41] #C78 = 100 - #C79 = ffi::_FfiInlineArray {elementType:#C70, length:#C78} - #C80 = [#C79] - #C81 = ffi::_FfiStructLayout {fieldTypes:#C80, packing:#C66} - #C82 = core::pragma {name:#C69, options:#C81} - #C83 = false - #C84 = ffi::_ArraySize {dimension1:#C78, dimension2:#C66, dimension3:#C66, dimension4:#C66, dimension5:#C66, dimensions:#C66, variableLength:#C83} + #C79 = false + #C80 = ffi::_FfiInlineArray {elementType:#C70, length:#C78, variableLength:#C79} + #C81 = [#C80] + #C82 = ffi::_FfiStructLayout {fieldTypes:#C81, packing:#C66} + #C83 = core::pragma {name:#C69, options:#C82} + #C84 = ffi::_ArraySize {dimension1:#C78, dimension2:#C66, dimension3:#C66, dimension4:#C66, dimension5:#C66, dimensions:#C66, variableDimension:#C66} #C85 = [] #C86 = 400 #C87 = 200 diff --git a/pkg/vm/testcases/transformations/ffi/abi_specific_int_incomplete.dart.aot.expect b/pkg/vm/testcases/transformations/ffi/abi_specific_int_incomplete.dart.aot.expect index 30589ce7d4a..9f6f63d8f41 100644 --- a/pkg/vm/testcases/transformations/ffi/abi_specific_int_incomplete.dart.aot.expect +++ b/pkg/vm/testcases/transformations/ffi/abi_specific_int_incomplete.dart.aot.expect @@ -46,7 +46,7 @@ final class IncompleteStruct extends ffi::Struct { static get #sizeOf() → core::int return [@vm.inferred-type.metadata=dart.core::_Smi (value: 8)] ffi::_checkAbiSpecificIntegerMapping(#C19.{core::List::[]}(ffi::_abi()){(core::int) → core::int?}); } -@#C24 +@#C25 final class IncompleteArrayStruct extends ffi::Struct { constructor #fromTypedDataBase([@vm.inferred-arg-type.metadata=dart.ffi::Pointer] synthesized core::Object #typedDataBase) → self::IncompleteArrayStruct : super ffi::Struct::_fromTypedDataBase(#typedDataBase) @@ -56,7 +56,7 @@ final class IncompleteArrayStruct extends ffi::Struct { [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:3] @#C8 get a0() → ffi::Array - return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::IncompleteArrayStruct::a0#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C20, #C25); + return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::IncompleteArrayStruct::a0#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C20, #C21, #C26); [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 0)] [@vm.unboxing-info.metadata=()->i] @@ -68,7 +68,7 @@ final class IncompleteArrayStruct extends ffi::Struct { [@vm.unboxing-info.metadata=()->i] @#C8 static get #sizeOf() → core::int - return [@vm.inferred-type.metadata=dart.core::_Smi (value: 400)] ffi::_checkAbiSpecificIntegerMapping(#C27.{core::List::[]}(ffi::_abi()){(core::int) → core::int?}); + return [@vm.inferred-type.metadata=dart.core::_Smi (value: 400)] ffi::_checkAbiSpecificIntegerMapping(#C28.{core::List::[]}(ffi::_abi()){(core::int) → core::int?}); } class _DummyAllocator extends core::Object implements ffi::Allocator /*hasConstConstructor*/ { @@ -100,35 +100,35 @@ static method testSizeOf() → void { [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] static method testStoreLoad() → void { - final ffi::Pointer p = let final core::int #t1 = [@vm.inferred-type.metadata=dart.core::_Smi (value: 4)] self::Incomplete::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C28.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; + final ffi::Pointer p = let final core::int #t1 = [@vm.inferred-type.metadata=dart.core::_Smi (value: 4)] self::Incomplete::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C29.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; ffi::_storeAbiSpecificInt(p, #C16, 10); core::print([@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificInt(p, #C16)); - [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C28.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; + [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C29.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; } [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] static method testStoreLoadIndexed() → void { - final ffi::Pointer p = let final core::num #t2 = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] 2.{core::num::*}([@vm.inferred-type.metadata=dart.core::_Smi (value: 4)] self::Incomplete::#sizeOf){(core::num) → core::num} in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C28.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; + final ffi::Pointer p = let final core::num #t2 = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] 2.{core::num::*}([@vm.inferred-type.metadata=dart.core::_Smi (value: 4)] self::Incomplete::#sizeOf){(core::num) → core::num} in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C29.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; ffi::_storeAbiSpecificIntAtIndex(p, #C16, 0, 10); ffi::_storeAbiSpecificIntAtIndex(p, #C16, 1, 3); core::print([@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificIntAtIndex(p, #C16, 0)); core::print([@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificIntAtIndex(p, #C16, 1)); - [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C28.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; + [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C29.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; } [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] static method testStruct() → void { - final ffi::Pointer p = let final core::int #t3 = [@vm.inferred-type.metadata=dart.core::_Smi (value: 8)] self::IncompleteStruct::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C28.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; + final ffi::Pointer p = let final core::int #t3 = [@vm.inferred-type.metadata=dart.core::_Smi (value: 8)] self::IncompleteStruct::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C29.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; [@vm.direct-call.metadata=#lib::IncompleteStruct.a0] [@vm.inferred-type.metadata=!? (skip check)] new self::IncompleteStruct::#fromTypedDataBase(_in::unsafeCast>(p)).{self::IncompleteStruct::a0} = 1; core::print([@vm.direct-call.metadata=#lib::IncompleteStruct.a0] [@vm.inferred-type.metadata=int] new self::IncompleteStruct::#fromTypedDataBase(_in::unsafeCast>(p)).{self::IncompleteStruct::a0}{core::int}); [@vm.direct-call.metadata=#lib::IncompleteStruct.a0] [@vm.inferred-type.metadata=!? (skip check)] new self::IncompleteStruct::#fromTypedDataBase(_in::unsafeCast>(p)).{self::IncompleteStruct::a0} = 2; core::print([@vm.direct-call.metadata=#lib::IncompleteStruct.a0] [@vm.inferred-type.metadata=int] new self::IncompleteStruct::#fromTypedDataBase(_in::unsafeCast>(p)).{self::IncompleteStruct::a0}{core::int}); - [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C28.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; + [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C29.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; } [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] static method testInlineArray() → void { - final ffi::Pointer p = let final core::int #t4 = [@vm.inferred-type.metadata=dart.core::_Smi (value: 400)] self::IncompleteArrayStruct::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C28.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; + final ffi::Pointer p = let final core::int #t4 = [@vm.inferred-type.metadata=dart.core::_Smi (value: 400)] self::IncompleteArrayStruct::#sizeOf in [@vm.direct-call.metadata=#lib::_DummyAllocator.allocate] [@vm.inferred-type.metadata=dart.ffi::Pointer (skip check)] #C29.{ffi::Allocator::allocate}(){(core::int, {alignment: core::int?}) → ffi::Pointer}; final ffi::Array array = [@vm.direct-call.metadata=#lib::IncompleteArrayStruct.a0] [@vm.inferred-type.metadata=dart.ffi::Array<#lib::Incomplete>] new self::IncompleteArrayStruct::#fromTypedDataBase(_in::unsafeCast>(p)).{self::IncompleteArrayStruct::a0}{ffi::Array}; for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation.<] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i.{core::num::<}(100){(core::num) → core::bool}; i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1){(core::num) → core::int}) { block { @@ -144,7 +144,7 @@ static method testInlineArray() → void { [@vm.direct-call.metadata=dart.ffi::Array._checkIndex] [@vm.inferred-type.metadata=!? (skip check)] #array.{ffi::Array::_checkIndex}(#index){(core::int) → void}; } =>[@vm.inferred-type.metadata=int] ffi::_loadAbiSpecificIntAtIndex([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}, #index)); } - [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C28.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; + [@vm.direct-call.metadata=#lib::_DummyAllocator.free] [@vm.inferred-type.metadata=!? (skip check)] #C29.{self::_DummyAllocator::free}(){(ffi::Pointer) → void}; } constants { #C1 = "vm:ffi:abi-specific-mapping" @@ -167,12 +167,13 @@ constants { #C18 = 8 #C19 = [#C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C18, #C18, #C18, #C18, #C2, #C2, #C2, #C2, #C2, #C2, #C2] #C20 = 100 - #C21 = ffi::_FfiInlineArray {elementType:#C12, length:#C20} - #C22 = [#C21] - #C23 = ffi::_FfiStructLayout {fieldTypes:#C22, packing:#C2} - #C24 = core::pragma {name:#C11, options:#C23} - #C25 = [] - #C26 = 400 - #C27 = [#C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C26, #C26, #C26, #C26, #C2, #C2, #C2, #C2, #C2, #C2, #C2] - #C28 = self::_DummyAllocator {} + #C21 = false + #C22 = ffi::_FfiInlineArray {elementType:#C12, length:#C20, variableLength:#C21} + #C23 = [#C22] + #C24 = ffi::_FfiStructLayout {fieldTypes:#C23, packing:#C2} + #C25 = core::pragma {name:#C11, options:#C24} + #C26 = [] + #C27 = 400 + #C28 = [#C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C2, #C27, #C27, #C27, #C27, #C2, #C2, #C2, #C2, #C2, #C2, #C2] + #C29 = self::_DummyAllocator {} } diff --git a/pkg/vm/testcases/transformations/ffi/abi_specific_int_incomplete.dart.expect b/pkg/vm/testcases/transformations/ffi/abi_specific_int_incomplete.dart.expect index 24d0ae04888..7a2b075fee4 100644 --- a/pkg/vm/testcases/transformations/ffi/abi_specific_int_incomplete.dart.expect +++ b/pkg/vm/testcases/transformations/ffi/abi_specific_int_incomplete.dart.expect @@ -54,7 +54,7 @@ final class IncompleteStruct extends ffi::Struct { static get #sizeOf() → core::int return ffi::_checkAbiSpecificIntegerMapping(#C40.{core::List::[]}(ffi::_abi()){(core::int) → core::int?}); } -@#C45 +@#C46 final class IncompleteArrayStruct extends ffi::Struct { synthetic constructor •() → self::IncompleteArrayStruct : super ffi::Struct::•() @@ -69,7 +69,7 @@ final class IncompleteArrayStruct extends ffi::Struct { @#C47 @#C29 get a0() → ffi::Array - return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::IncompleteArrayStruct::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C41, #C48); + return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::IncompleteArrayStruct::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C41, #C42, #C48); @#C47 @#C29 set a0(synthesized ffi::Array #externalFieldValue) → void @@ -187,12 +187,12 @@ constants { #C39 = 8 #C40 = [#C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C39, #C39, #C39, #C39, #C23, #C23, #C23, #C23, #C23, #C23, #C23] #C41 = 100 - #C42 = ffi::_FfiInlineArray {elementType:#C33, length:#C41} - #C43 = [#C42] - #C44 = ffi::_FfiStructLayout {fieldTypes:#C43, packing:#C23} - #C45 = core::pragma {name:#C32, options:#C44} - #C46 = false - #C47 = ffi::_ArraySize {dimension1:#C41, dimension2:#C23, dimension3:#C23, dimension4:#C23, dimension5:#C23, dimensions:#C23, variableLength:#C46} + #C42 = false + #C43 = ffi::_FfiInlineArray {elementType:#C33, length:#C41, variableLength:#C42} + #C44 = [#C43] + #C45 = ffi::_FfiStructLayout {fieldTypes:#C44, packing:#C23} + #C46 = core::pragma {name:#C32, options:#C45} + #C47 = ffi::_ArraySize {dimension1:#C41, dimension2:#C23, dimension3:#C23, dimension4:#C23, dimension5:#C23, dimensions:#C23, variableDimension:#C23} #C48 = [] #C49 = 400 #C50 = [#C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C49, #C49, #C49, #C49, #C23, #C23, #C23, #C23, #C23, #C23, #C23] diff --git a/pkg/vm/testcases/transformations/ffi/address_of_cast_compound_element.dart.aot.expect b/pkg/vm/testcases/transformations/ffi/address_of_cast_compound_element.dart.aot.expect index bcb23c7d9c1..c01b3bb4295 100644 --- a/pkg/vm/testcases/transformations/ffi/address_of_cast_compound_element.dart.aot.expect +++ b/pkg/vm/testcases/transformations/ffi/address_of_cast_compound_element.dart.aot.expect @@ -6,7 +6,7 @@ import "dart:typed_data" as typ; import "dart:ffi"; -@#C10 +@#C11 final class MyStruct extends ffi::Struct { constructor #fromTypedDataBase([@vm.inferred-arg-type.metadata=dart.typed_data::_Uint8List] synthesized core::Object #typedDataBase) → self::MyStruct : super ffi::Struct::_fromTypedDataBase(#typedDataBase) @@ -14,47 +14,47 @@ final class MyStruct extends ffi::Struct { [@vm.inferred-return-type.metadata=dart.ffi::Array] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:1] - @#C12 + @#C13 get array() → ffi::Array - return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 2)] self::MyStruct::array#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C13); + return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 2)] self::MyStruct::array#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C14); [@vm.inferred-return-type.metadata=dart.ffi::Array] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:2] - @#C12 + @#C13 get array2() → ffi::Array - return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi] self::MyStruct::array2#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C13); + return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi] self::MyStruct::array2#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C14); [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 0)] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get a#offsetOf() → core::int - return #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C16.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 1)] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get b#offsetOf() → core::int - return #C17.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C18.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 2)] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get array#offsetOf() → core::int - return #C19.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C20.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; [@vm.inferred-return-type.metadata=dart.core::_Smi] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get array2#offsetOf() → core::int - return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C23.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; [@vm.inferred-return-type.metadata=dart.core::_Smi] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get #sizeOf() → core::int - return #C25.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C26.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } -@#C28 +@#C29 final class MyUnion extends ffi::Union { constructor #fromTypedDataBase([@vm.inferred-arg-type.metadata=dart.typed_data::_Uint8List] synthesized core::Object #typedDataBase) → self::MyUnion : super ffi::Union::_fromTypedDataBase(#typedDataBase) @@ -62,9 +62,9 @@ final class MyUnion extends ffi::Union { [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 1)] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get #sizeOf() → core::int - return #C17.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C18.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] @@ -79,53 +79,54 @@ static method main() → void { self::myNative#CC(myUnion, myUnion); self::myNative#CC( block { synthesized ffi::_Compound pointer#value = [@vm.direct-call.metadata=#lib::MyStruct.array] [@vm.inferred-type.metadata=dart.ffi::Array] myStruct.{self::MyStruct::array}{ffi::Array}; - } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #C16.{core::num::*}(3){(core::num) → core::num}){(core::num) → core::num}), block { + } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #C17.{core::num::*}(3){(core::num) → core::num}){(core::num) → core::num}), block { synthesized ffi::_Compound pointer2#value = [@vm.direct-call.metadata=#lib::MyStruct.array] [@vm.inferred-type.metadata=dart.ffi::Array] myStruct.{self::MyStruct::array}{ffi::Array}; - } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer2#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer2#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #C16.{core::num::*}(4){(core::num) → core::num}){(core::num) → core::num})); + } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer2#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer2#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #C17.{core::num::*}(4){(core::num) → core::num}){(core::num) → core::num})); self::myNative#CC( block { synthesized ffi::_Compound pointer#value = [@vm.direct-call.metadata=#lib::MyStruct.array2] [@vm.inferred-type.metadata=dart.ffi::Array] myStruct.{self::MyStruct::array2}{ffi::Array}; } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi] ffi::UnsignedLong::#sizeOf.{core::num::*}(3){(core::num) → core::num}){(core::num) → core::num}), block { synthesized ffi::_Compound pointer2#value = [@vm.direct-call.metadata=#lib::MyStruct.array2] [@vm.inferred-type.metadata=dart.ffi::Array] myStruct.{self::MyStruct::array2}{ffi::Array}; } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer2#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer2#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi] ffi::UnsignedLong::#sizeOf.{core::num::*}(4){(core::num) → core::num}){(core::num) → core::num})); } -@#C34 -@#C36 +@#C35 +@#C37 external static method myNative#CC([@vm.inferred-arg-type.metadata=!] ffi::_Compound pointer, [@vm.inferred-arg-type.metadata=!] ffi::_Compound pointer2) → void; constants { #C1 = "vm:ffi:struct-fields" #C2 = TypeLiteralConstant(ffi::Int8) #C3 = 10 - #C4 = ffi::_FfiInlineArray {elementType:#C2, length:#C3} - #C5 = TypeLiteralConstant(ffi::UnsignedLong) - #C6 = ffi::_FfiInlineArray {elementType:#C5, length:#C3} - #C7 = [#C2, #C2, #C4, #C6] - #C8 = null - #C9 = ffi::_FfiStructLayout {fieldTypes:#C7, packing:#C8} - #C10 = core::pragma {name:#C1, options:#C9} - #C11 = "vm:prefer-inline" - #C12 = core::pragma {name:#C11, options:#C8} - #C13 = [] - #C14 = 0 - #C15 = [#C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14] - #C16 = 1 - #C17 = [#C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16] - #C18 = 2 - #C19 = [#C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18] - #C20 = 12 - #C21 = 16 - #C22 = [#C20, #C21, #C20, #C21, #C21, #C21, #C21, #C21, #C20, #C21, #C21, #C20, #C21, #C20, #C21, #C20, #C21, #C21, #C21, #C20, #C20, #C20] - #C23 = 52 - #C24 = 96 - #C25 = [#C23, #C24, #C23, #C24, #C24, #C24, #C24, #C24, #C23, #C24, #C24, #C23, #C24, #C23, #C24, #C23, #C24, #C24, #C24, #C23, #C23, #C23] - #C26 = [#C2, #C2] - #C27 = ffi::_FfiStructLayout {fieldTypes:#C26, packing:#C8} - #C28 = core::pragma {name:#C1, options:#C27} - #C29 = "cfe:ffi:native-marker" - #C30 = "myNative" - #C31 = "#lib" - #C32 = true - #C33 = ffi::Native<(ffi::Pointer, ffi::Pointer) → ffi::Void> {symbol:#C30, assetId:#C31, isLeaf:#C32} - #C34 = core::pragma {name:#C29, options:#C33} - #C35 = "vm:ffi:native" - #C36 = core::pragma {name:#C35, options:#C33} + #C4 = false + #C5 = ffi::_FfiInlineArray {elementType:#C2, length:#C3, variableLength:#C4} + #C6 = TypeLiteralConstant(ffi::UnsignedLong) + #C7 = ffi::_FfiInlineArray {elementType:#C6, length:#C3, variableLength:#C4} + #C8 = [#C2, #C2, #C5, #C7] + #C9 = null + #C10 = ffi::_FfiStructLayout {fieldTypes:#C8, packing:#C9} + #C11 = core::pragma {name:#C1, options:#C10} + #C12 = "vm:prefer-inline" + #C13 = core::pragma {name:#C12, options:#C9} + #C14 = [] + #C15 = 0 + #C16 = [#C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15] + #C17 = 1 + #C18 = [#C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17] + #C19 = 2 + #C20 = [#C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19] + #C21 = 12 + #C22 = 16 + #C23 = [#C21, #C22, #C21, #C22, #C22, #C22, #C22, #C22, #C21, #C22, #C22, #C21, #C22, #C21, #C22, #C21, #C22, #C22, #C22, #C21, #C21, #C21] + #C24 = 52 + #C25 = 96 + #C26 = [#C24, #C25, #C24, #C25, #C25, #C25, #C25, #C25, #C24, #C25, #C25, #C24, #C25, #C24, #C25, #C24, #C25, #C25, #C25, #C24, #C24, #C24] + #C27 = [#C2, #C2] + #C28 = ffi::_FfiStructLayout {fieldTypes:#C27, packing:#C9} + #C29 = core::pragma {name:#C1, options:#C28} + #C30 = "cfe:ffi:native-marker" + #C31 = "myNative" + #C32 = "#lib" + #C33 = true + #C34 = ffi::Native<(ffi::Pointer, ffi::Pointer) → ffi::Void> {symbol:#C31, assetId:#C32, isLeaf:#C33} + #C35 = core::pragma {name:#C30, options:#C34} + #C36 = "vm:ffi:native" + #C37 = core::pragma {name:#C36, options:#C34} } diff --git a/pkg/vm/testcases/transformations/ffi/address_of_cast_compound_element.dart.expect b/pkg/vm/testcases/transformations/ffi/address_of_cast_compound_element.dart.expect index b0edfe9065e..4d16b4aa5aa 100644 --- a/pkg/vm/testcases/transformations/ffi/address_of_cast_compound_element.dart.expect +++ b/pkg/vm/testcases/transformations/ffi/address_of_cast_compound_element.dart.expect @@ -6,7 +6,7 @@ import "dart:typed_data" as typ; import "dart:ffi"; -@#C10 +@#C11 final class MyStruct extends ffi::Struct { synthetic constructor •() → self::MyStruct : super ffi::Struct::•() @@ -14,55 +14,55 @@ final class MyStruct extends ffi::Struct { constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::MyStruct : super ffi::Struct::_fromTypedDataBase(#typedDataBase, #offsetInBytes) ; - @#C12 + @#C13 constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyStruct : super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes) ; + @#C14 @#C13 - @#C12 get a() → core::int return ffi::_loadInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}); + @#C14 @#C13 - @#C12 set a(synthesized core::int #externalFieldValue) → void return ffi::_storeInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue); + @#C14 @#C13 - @#C12 get b() → core::int return ffi::_loadInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::b#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}); + @#C14 @#C13 - @#C12 set b(synthesized core::int #externalFieldValue) → void return ffi::_storeInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::b#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue); @#C15 - @#C12 + @#C13 get array() → ffi::Array - return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C16); + return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C16); @#C15 - @#C12 + @#C13 set array(synthesized ffi::Array #externalFieldValue) → void return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C17.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); @#C15 - @#C12 + @#C13 get array2() → ffi::Array - return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array2#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C16); + return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array2#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C16); @#C15 - @#C12 + @#C13 set array2(synthesized ffi::Array #externalFieldValue) → void return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array2#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C20.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); - @#C12 + @#C13 static get a#offsetOf() → core::int return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get b#offsetOf() → core::int return #C24.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get array#offsetOf() → core::int return #C26.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get array2#offsetOf() → core::int return #C29.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get #sizeOf() → core::int return #C32.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } @@ -74,33 +74,33 @@ final class MyUnion extends ffi::Union { constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::MyUnion : super ffi::Union::_fromTypedDataBase(#typedDataBase, #offsetInBytes) ; - @#C12 + @#C13 constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyUnion : super ffi::Union::_fromTypedData(#typedData, #offset, #sizeInBytes) ; + @#C14 @#C13 - @#C12 get a() → core::int return ffi::_loadInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyUnion::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}); + @#C14 @#C13 - @#C12 set a(synthesized core::int #externalFieldValue) → void return ffi::_storeInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyUnion::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue); + @#C14 @#C13 - @#C12 get b() → core::int return ffi::_loadInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyUnion::b#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}); + @#C14 @#C13 - @#C12 set b(synthesized core::int #externalFieldValue) → void return ffi::_storeInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyUnion::b#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue); - @#C12 + @#C13 static get a#offsetOf() → core::int return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get b#offsetOf() → core::int return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get #sizeOf() → core::int return #C24.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } @@ -134,18 +134,18 @@ constants { #C1 = "vm:ffi:struct-fields" #C2 = TypeLiteralConstant(ffi::Int8) #C3 = 10 - #C4 = ffi::_FfiInlineArray {elementType:#C2, length:#C3} - #C5 = TypeLiteralConstant(ffi::UnsignedLong) - #C6 = ffi::_FfiInlineArray {elementType:#C5, length:#C3} - #C7 = [#C2, #C2, #C4, #C6] - #C8 = null - #C9 = ffi::_FfiStructLayout {fieldTypes:#C7, packing:#C8} - #C10 = core::pragma {name:#C1, options:#C9} - #C11 = "vm:prefer-inline" - #C12 = core::pragma {name:#C11, options:#C8} - #C13 = ffi::Int8 {} - #C14 = false - #C15 = ffi::_ArraySize {dimension1:#C3, dimension2:#C8, dimension3:#C8, dimension4:#C8, dimension5:#C8, dimensions:#C8, variableLength:#C14} + #C4 = false + #C5 = ffi::_FfiInlineArray {elementType:#C2, length:#C3, variableLength:#C4} + #C6 = TypeLiteralConstant(ffi::UnsignedLong) + #C7 = ffi::_FfiInlineArray {elementType:#C6, length:#C3, variableLength:#C4} + #C8 = [#C2, #C2, #C5, #C7] + #C9 = null + #C10 = ffi::_FfiStructLayout {fieldTypes:#C8, packing:#C9} + #C11 = core::pragma {name:#C1, options:#C10} + #C12 = "vm:prefer-inline" + #C13 = core::pragma {name:#C12, options:#C9} + #C14 = ffi::Int8 {} + #C15 = ffi::_ArraySize {dimension1:#C3, dimension2:#C9, dimension3:#C9, dimension4:#C9, dimension5:#C9, dimensions:#C9, variableDimension:#C9} #C16 = [] #C17 = [#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3] #C18 = 40 @@ -164,7 +164,7 @@ constants { #C31 = 96 #C32 = [#C30, #C31, #C30, #C31, #C31, #C31, #C31, #C31, #C30, #C31, #C31, #C30, #C31, #C30, #C31, #C30, #C31, #C31, #C31, #C30, #C30, #C30] #C33 = [#C2, #C2] - #C34 = ffi::_FfiStructLayout {fieldTypes:#C33, packing:#C8} + #C34 = ffi::_FfiStructLayout {fieldTypes:#C33, packing:#C9} #C35 = core::pragma {name:#C1, options:#C34} #C36 = "cfe:ffi:native-marker" #C37 = "myNative" diff --git a/pkg/vm/testcases/transformations/ffi/address_of_struct.dart.aot.expect b/pkg/vm/testcases/transformations/ffi/address_of_struct.dart.aot.expect index aed711db00c..ffb680d39d5 100644 --- a/pkg/vm/testcases/transformations/ffi/address_of_struct.dart.aot.expect +++ b/pkg/vm/testcases/transformations/ffi/address_of_struct.dart.aot.expect @@ -6,7 +6,7 @@ import "dart:typed_data" as typ; import "dart:ffi"; -@#C8 +@#C9 final class MyStruct extends ffi::Struct { constructor #fromTypedDataBase([@vm.inferred-arg-type.metadata=dart.typed_data::_Uint8List] synthesized core::Object #typedDataBase) → self::MyStruct : super ffi::Struct::_fromTypedDataBase(#typedDataBase) @@ -14,23 +14,23 @@ final class MyStruct extends ffi::Struct { [@vm.inferred-return-type.metadata=dart.ffi::Array] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:1] - @#C10 + @#C11 get a() → ffi::Array - return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::MyStruct::a#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C11); + return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] self::MyStruct::a#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C12); [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 0)] [@vm.unboxing-info.metadata=()->i] - @#C10 + @#C11 static get a#offsetOf() → core::int - return #C13.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C14.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 10)] [@vm.unboxing-info.metadata=()->i] - @#C10 + @#C11 static get #sizeOf() → core::int - return #C14.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } -@#C17 +@#C18 final class MyUnion extends ffi::Union { constructor #fromTypedDataBase([@vm.inferred-arg-type.metadata=dart.typed_data::_Uint8List] synthesized core::Object #typedDataBase) → self::MyUnion : super ffi::Union::_fromTypedDataBase(#typedDataBase) @@ -38,9 +38,9 @@ final class MyUnion extends ffi::Union { [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 1)] [@vm.unboxing-info.metadata=()->i] - @#C10 + @#C11 static get #sizeOf() → core::int - return #C19.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C20.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] @@ -51,49 +51,50 @@ static method main() → void { self::myNative2#C(myUnion); self::myNative3#C([@vm.direct-call.metadata=#lib::MyStruct.a] [@vm.inferred-type.metadata=dart.ffi::Array] myStruct.{self::MyStruct::a}{ffi::Array}); } -@#C25 -@#C27 +@#C26 +@#C28 external static method myNative#C([@vm.inferred-arg-type.metadata=#lib::MyStruct] ffi::_Compound pointer) → void; -@#C30 @#C31 +@#C32 external static method myNative2#C([@vm.inferred-arg-type.metadata=#lib::MyUnion] ffi::_Compound pointer) → void; -@#C34 @#C35 +@#C36 external static method myNative3#C([@vm.inferred-arg-type.metadata=dart.ffi::Array] ffi::_Compound pointer) → void; constants { #C1 = "vm:ffi:struct-fields" #C2 = TypeLiteralConstant(ffi::Int8) #C3 = 10 - #C4 = ffi::_FfiInlineArray {elementType:#C2, length:#C3} - #C5 = [#C4] - #C6 = null - #C7 = ffi::_FfiStructLayout {fieldTypes:#C5, packing:#C6} - #C8 = core::pragma {name:#C1, options:#C7} - #C9 = "vm:prefer-inline" - #C10 = core::pragma {name:#C9, options:#C6} - #C11 = [] - #C12 = 0 - #C13 = [#C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12] - #C14 = [#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3] - #C15 = [#C2] - #C16 = ffi::_FfiStructLayout {fieldTypes:#C15, packing:#C6} - #C17 = core::pragma {name:#C1, options:#C16} - #C18 = 1 - #C19 = [#C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18] - #C20 = "cfe:ffi:native-marker" - #C21 = "myNative" - #C22 = "#lib" - #C23 = true - #C24 = ffi::Native<(ffi::Pointer) → ffi::Void> {symbol:#C21, assetId:#C22, isLeaf:#C23} - #C25 = core::pragma {name:#C20, options:#C24} - #C26 = "vm:ffi:native" - #C27 = core::pragma {name:#C26, options:#C24} - #C28 = "myNative2" - #C29 = ffi::Native<(ffi::Pointer) → ffi::Void> {symbol:#C28, assetId:#C22, isLeaf:#C23} - #C30 = core::pragma {name:#C20, options:#C29} - #C31 = core::pragma {name:#C26, options:#C29} - #C32 = "myNative3" - #C33 = ffi::Native<(ffi::Pointer) → ffi::Void> {symbol:#C32, assetId:#C22, isLeaf:#C23} - #C34 = core::pragma {name:#C20, options:#C33} - #C35 = core::pragma {name:#C26, options:#C33} + #C4 = false + #C5 = ffi::_FfiInlineArray {elementType:#C2, length:#C3, variableLength:#C4} + #C6 = [#C5] + #C7 = null + #C8 = ffi::_FfiStructLayout {fieldTypes:#C6, packing:#C7} + #C9 = core::pragma {name:#C1, options:#C8} + #C10 = "vm:prefer-inline" + #C11 = core::pragma {name:#C10, options:#C7} + #C12 = [] + #C13 = 0 + #C14 = [#C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13, #C13] + #C15 = [#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3] + #C16 = [#C2] + #C17 = ffi::_FfiStructLayout {fieldTypes:#C16, packing:#C7} + #C18 = core::pragma {name:#C1, options:#C17} + #C19 = 1 + #C20 = [#C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19] + #C21 = "cfe:ffi:native-marker" + #C22 = "myNative" + #C23 = "#lib" + #C24 = true + #C25 = ffi::Native<(ffi::Pointer) → ffi::Void> {symbol:#C22, assetId:#C23, isLeaf:#C24} + #C26 = core::pragma {name:#C21, options:#C25} + #C27 = "vm:ffi:native" + #C28 = core::pragma {name:#C27, options:#C25} + #C29 = "myNative2" + #C30 = ffi::Native<(ffi::Pointer) → ffi::Void> {symbol:#C29, assetId:#C23, isLeaf:#C24} + #C31 = core::pragma {name:#C21, options:#C30} + #C32 = core::pragma {name:#C27, options:#C30} + #C33 = "myNative3" + #C34 = ffi::Native<(ffi::Pointer) → ffi::Void> {symbol:#C33, assetId:#C23, isLeaf:#C24} + #C35 = core::pragma {name:#C21, options:#C34} + #C36 = core::pragma {name:#C27, options:#C34} } diff --git a/pkg/vm/testcases/transformations/ffi/address_of_struct.dart.expect b/pkg/vm/testcases/transformations/ffi/address_of_struct.dart.expect index a9d69ca0a11..75b235d9b9b 100644 --- a/pkg/vm/testcases/transformations/ffi/address_of_struct.dart.expect +++ b/pkg/vm/testcases/transformations/ffi/address_of_struct.dart.expect @@ -6,7 +6,7 @@ import "dart:typed_data" as typ; import "dart:ffi"; -@#C8 +@#C9 final class MyStruct extends ffi::Struct { synthetic constructor •() → self::MyStruct : super ffi::Struct::•() @@ -14,22 +14,22 @@ final class MyStruct extends ffi::Struct { constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::MyStruct : super ffi::Struct::_fromTypedDataBase(#typedDataBase, #offsetInBytes) ; - @#C10 + @#C11 constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyStruct : super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes) ; @#C12 - @#C10 + @#C11 get a() → ffi::Array - return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C13); + return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C13); @#C12 - @#C10 + @#C11 set a(synthesized ffi::Array #externalFieldValue) → void return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C14.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); - @#C10 + @#C11 static get a#offsetOf() → core::int return #C16.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C10 + @#C11 static get #sizeOf() → core::int return #C14.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } @@ -41,22 +41,22 @@ final class MyUnion extends ffi::Union { constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::MyUnion : super ffi::Union::_fromTypedDataBase(#typedDataBase, #offsetInBytes) ; - @#C10 + @#C11 constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyUnion : super ffi::Union::_fromTypedData(#typedData, #offset, #sizeInBytes) ; @#C20 - @#C10 + @#C11 get a() → core::int return ffi::_loadInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyUnion::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}); @#C20 - @#C10 + @#C11 set a(synthesized core::int #externalFieldValue) → void return ffi::_storeInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyUnion::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue); - @#C10 + @#C11 static get a#offsetOf() → core::int return #C16.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C10 + @#C11 static get #sizeOf() → core::int return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } @@ -89,21 +89,21 @@ constants { #C1 = "vm:ffi:struct-fields" #C2 = TypeLiteralConstant(ffi::Int8) #C3 = 10 - #C4 = ffi::_FfiInlineArray {elementType:#C2, length:#C3} - #C5 = [#C4] - #C6 = null - #C7 = ffi::_FfiStructLayout {fieldTypes:#C5, packing:#C6} - #C8 = core::pragma {name:#C1, options:#C7} - #C9 = "vm:prefer-inline" - #C10 = core::pragma {name:#C9, options:#C6} - #C11 = false - #C12 = ffi::_ArraySize {dimension1:#C3, dimension2:#C6, dimension3:#C6, dimension4:#C6, dimension5:#C6, dimensions:#C6, variableLength:#C11} + #C4 = false + #C5 = ffi::_FfiInlineArray {elementType:#C2, length:#C3, variableLength:#C4} + #C6 = [#C5] + #C7 = null + #C8 = ffi::_FfiStructLayout {fieldTypes:#C6, packing:#C7} + #C9 = core::pragma {name:#C1, options:#C8} + #C10 = "vm:prefer-inline" + #C11 = core::pragma {name:#C10, options:#C7} + #C12 = ffi::_ArraySize {dimension1:#C3, dimension2:#C7, dimension3:#C7, dimension4:#C7, dimension5:#C7, dimensions:#C7, variableDimension:#C7} #C13 = [] #C14 = [#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3] #C15 = 0 #C16 = [#C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15] #C17 = [#C2] - #C18 = ffi::_FfiStructLayout {fieldTypes:#C17, packing:#C6} + #C18 = ffi::_FfiStructLayout {fieldTypes:#C17, packing:#C7} #C19 = core::pragma {name:#C1, options:#C18} #C20 = ffi::Int8 {} #C21 = 1 diff --git a/pkg/vm/testcases/transformations/ffi/address_of_struct_element.dart.aot.expect b/pkg/vm/testcases/transformations/ffi/address_of_struct_element.dart.aot.expect index 94a5fac550a..a289086f8da 100644 --- a/pkg/vm/testcases/transformations/ffi/address_of_struct_element.dart.aot.expect +++ b/pkg/vm/testcases/transformations/ffi/address_of_struct_element.dart.aot.expect @@ -6,7 +6,7 @@ import "dart:typed_data" as typ; import "dart:ffi"; -@#C10 +@#C11 final class MyStruct extends ffi::Struct { constructor #fromTypedDataBase([@vm.inferred-arg-type.metadata=dart.typed_data::_Uint8List] synthesized core::Object #typedDataBase) → self::MyStruct : super ffi::Struct::_fromTypedDataBase(#typedDataBase) @@ -14,47 +14,47 @@ final class MyStruct extends ffi::Struct { [@vm.inferred-return-type.metadata=dart.ffi::Array] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:1] - @#C12 + @#C13 get array() → ffi::Array - return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 2)] self::MyStruct::array#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C13); + return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi (value: 2)] self::MyStruct::array#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C14); [@vm.inferred-return-type.metadata=dart.ffi::Array] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:2] - @#C12 + @#C13 get array2() → ffi::Array - return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi] self::MyStruct::array2#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C13); + return new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] this.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi] self::MyStruct::array2#offsetOf.{core::num::+}([@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C14); [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 0)] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get a#offsetOf() → core::int - return #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C16.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 1)] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get b#offsetOf() → core::int - return #C17.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C18.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 2)] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get array#offsetOf() → core::int - return #C19.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C20.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; [@vm.inferred-return-type.metadata=dart.core::_Smi] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get array2#offsetOf() → core::int - return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C23.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; [@vm.inferred-return-type.metadata=dart.core::_Smi] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get #sizeOf() → core::int - return #C25.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C26.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } -@#C28 +@#C29 final class MyUnion extends ffi::Union { constructor #fromTypedDataBase([@vm.inferred-arg-type.metadata=dart.typed_data::_Uint8List] synthesized core::Object #typedDataBase) → self::MyUnion : super ffi::Union::_fromTypedDataBase(#typedDataBase) @@ -62,9 +62,9 @@ final class MyUnion extends ffi::Union { [@vm.inferred-return-type.metadata=dart.core::_Smi (value: 1)] [@vm.unboxing-info.metadata=()->i] - @#C12 + @#C13 static get #sizeOf() → core::int - return #C17.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + return #C18.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } [@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] @@ -79,53 +79,54 @@ static method main() → void { self::myNative#CC(myUnion, myUnion); self::myNative#CC( block { synthesized ffi::_Compound pointer#value = [@vm.direct-call.metadata=#lib::MyStruct.array] [@vm.inferred-type.metadata=dart.ffi::Array] myStruct.{self::MyStruct::array}{ffi::Array}; - } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #C16.{core::num::*}(3){(core::num) → core::num}){(core::num) → core::num}), block { + } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #C17.{core::num::*}(3){(core::num) → core::num}){(core::num) → core::num}), block { synthesized ffi::_Compound pointer2#value = [@vm.direct-call.metadata=#lib::MyStruct.array] [@vm.inferred-type.metadata=dart.ffi::Array] myStruct.{self::MyStruct::array}{ffi::Array}; - } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer2#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer2#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #C16.{core::num::*}(4){(core::num) → core::num}){(core::num) → core::num})); + } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer2#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer2#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #C17.{core::num::*}(4){(core::num) → core::num}){(core::num) → core::num})); self::myNative#CC( block { synthesized ffi::_Compound pointer#value = [@vm.direct-call.metadata=#lib::MyStruct.array2] [@vm.inferred-type.metadata=dart.ffi::Array] myStruct.{self::MyStruct::array2}{ffi::Array}; } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi] ffi::UnsignedLong::#sizeOf.{core::num::*}(3){(core::num) → core::num}){(core::num) → core::num}), block { synthesized ffi::_Compound pointer2#value = [@vm.direct-call.metadata=#lib::MyStruct.array2] [@vm.inferred-type.metadata=dart.ffi::Array] myStruct.{self::MyStruct::array2}{ffi::Array}; } =>new ffi::_Compound::_fromTypedDataBase([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] pointer2#value.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] pointer2#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] [@vm.inferred-type.metadata=dart.core::_Smi] ffi::UnsignedLong::#sizeOf.{core::num::*}(4){(core::num) → core::num}){(core::num) → core::num})); } -@#C34 -@#C36 +@#C35 +@#C37 external static method myNative#CC([@vm.inferred-arg-type.metadata=!] ffi::_Compound pointer, [@vm.inferred-arg-type.metadata=!] ffi::_Compound pointer2) → void; constants { #C1 = "vm:ffi:struct-fields" #C2 = TypeLiteralConstant(ffi::Int8) #C3 = 10 - #C4 = ffi::_FfiInlineArray {elementType:#C2, length:#C3} - #C5 = TypeLiteralConstant(ffi::UnsignedLong) - #C6 = ffi::_FfiInlineArray {elementType:#C5, length:#C3} - #C7 = [#C2, #C2, #C4, #C6] - #C8 = null - #C9 = ffi::_FfiStructLayout {fieldTypes:#C7, packing:#C8} - #C10 = core::pragma {name:#C1, options:#C9} - #C11 = "vm:prefer-inline" - #C12 = core::pragma {name:#C11, options:#C8} - #C13 = [] - #C14 = 0 - #C15 = [#C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14] - #C16 = 1 - #C17 = [#C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16] - #C18 = 2 - #C19 = [#C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18, #C18] - #C20 = 12 - #C21 = 16 - #C22 = [#C20, #C21, #C20, #C21, #C21, #C21, #C21, #C21, #C20, #C21, #C21, #C20, #C21, #C20, #C21, #C20, #C21, #C21, #C21, #C20, #C20, #C20] - #C23 = 52 - #C24 = 96 - #C25 = [#C23, #C24, #C23, #C24, #C24, #C24, #C24, #C24, #C23, #C24, #C24, #C23, #C24, #C23, #C24, #C23, #C24, #C24, #C24, #C23, #C23, #C23] - #C26 = [#C2, #C2] - #C27 = ffi::_FfiStructLayout {fieldTypes:#C26, packing:#C8} - #C28 = core::pragma {name:#C1, options:#C27} - #C29 = "cfe:ffi:native-marker" - #C30 = "myNative" - #C31 = "#lib" - #C32 = true - #C33 = ffi::Native<(ffi::Pointer, ffi::Pointer) → ffi::Void> {symbol:#C30, assetId:#C31, isLeaf:#C32} - #C34 = core::pragma {name:#C29, options:#C33} - #C35 = "vm:ffi:native" - #C36 = core::pragma {name:#C35, options:#C33} + #C4 = false + #C5 = ffi::_FfiInlineArray {elementType:#C2, length:#C3, variableLength:#C4} + #C6 = TypeLiteralConstant(ffi::UnsignedLong) + #C7 = ffi::_FfiInlineArray {elementType:#C6, length:#C3, variableLength:#C4} + #C8 = [#C2, #C2, #C5, #C7] + #C9 = null + #C10 = ffi::_FfiStructLayout {fieldTypes:#C8, packing:#C9} + #C11 = core::pragma {name:#C1, options:#C10} + #C12 = "vm:prefer-inline" + #C13 = core::pragma {name:#C12, options:#C9} + #C14 = [] + #C15 = 0 + #C16 = [#C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15] + #C17 = 1 + #C18 = [#C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17, #C17] + #C19 = 2 + #C20 = [#C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19, #C19] + #C21 = 12 + #C22 = 16 + #C23 = [#C21, #C22, #C21, #C22, #C22, #C22, #C22, #C22, #C21, #C22, #C22, #C21, #C22, #C21, #C22, #C21, #C22, #C22, #C22, #C21, #C21, #C21] + #C24 = 52 + #C25 = 96 + #C26 = [#C24, #C25, #C24, #C25, #C25, #C25, #C25, #C25, #C24, #C25, #C25, #C24, #C25, #C24, #C25, #C24, #C25, #C25, #C25, #C24, #C24, #C24] + #C27 = [#C2, #C2] + #C28 = ffi::_FfiStructLayout {fieldTypes:#C27, packing:#C9} + #C29 = core::pragma {name:#C1, options:#C28} + #C30 = "cfe:ffi:native-marker" + #C31 = "myNative" + #C32 = "#lib" + #C33 = true + #C34 = ffi::Native<(ffi::Pointer, ffi::Pointer) → ffi::Void> {symbol:#C31, assetId:#C32, isLeaf:#C33} + #C35 = core::pragma {name:#C30, options:#C34} + #C36 = "vm:ffi:native" + #C37 = core::pragma {name:#C36, options:#C34} } diff --git a/pkg/vm/testcases/transformations/ffi/address_of_struct_element.dart.expect b/pkg/vm/testcases/transformations/ffi/address_of_struct_element.dart.expect index a298e7fdcfa..3c37e6bfae4 100644 --- a/pkg/vm/testcases/transformations/ffi/address_of_struct_element.dart.expect +++ b/pkg/vm/testcases/transformations/ffi/address_of_struct_element.dart.expect @@ -6,7 +6,7 @@ import "dart:typed_data" as typ; import "dart:ffi"; -@#C10 +@#C11 final class MyStruct extends ffi::Struct { synthetic constructor •() → self::MyStruct : super ffi::Struct::•() @@ -14,55 +14,55 @@ final class MyStruct extends ffi::Struct { constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::MyStruct : super ffi::Struct::_fromTypedDataBase(#typedDataBase, #offsetInBytes) ; - @#C12 + @#C13 constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyStruct : super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes) ; + @#C14 @#C13 - @#C12 get a() → core::int return ffi::_loadInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}); + @#C14 @#C13 - @#C12 set a(synthesized core::int #externalFieldValue) → void return ffi::_storeInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue); + @#C14 @#C13 - @#C12 get b() → core::int return ffi::_loadInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::b#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}); + @#C14 @#C13 - @#C12 set b(synthesized core::int #externalFieldValue) → void return ffi::_storeInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::b#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue); @#C15 - @#C12 + @#C13 get array() → ffi::Array - return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C16); + return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C16); @#C15 - @#C12 + @#C13 set array(synthesized ffi::Array #externalFieldValue) → void return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C17.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); @#C15 - @#C12 + @#C13 get array2() → ffi::Array - return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array2#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C16); + return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array2#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C4, #C16); @#C15 - @#C12 + @#C13 set array2(synthesized ffi::Array #externalFieldValue) → void return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array2#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C20.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); - @#C12 + @#C13 static get a#offsetOf() → core::int return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get b#offsetOf() → core::int return #C24.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get array#offsetOf() → core::int return #C26.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get array2#offsetOf() → core::int return #C29.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get #sizeOf() → core::int return #C32.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } @@ -74,33 +74,33 @@ final class MyUnion extends ffi::Union { constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::MyUnion : super ffi::Union::_fromTypedDataBase(#typedDataBase, #offsetInBytes) ; - @#C12 + @#C13 constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyUnion : super ffi::Union::_fromTypedData(#typedData, #offset, #sizeInBytes) ; + @#C14 @#C13 - @#C12 get a() → core::int return ffi::_loadInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyUnion::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}); + @#C14 @#C13 - @#C12 set a(synthesized core::int #externalFieldValue) → void return ffi::_storeInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyUnion::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue); + @#C14 @#C13 - @#C12 get b() → core::int return ffi::_loadInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyUnion::b#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}); + @#C14 @#C13 - @#C12 set b(synthesized core::int #externalFieldValue) → void return ffi::_storeInt8(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyUnion::b#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue); - @#C12 + @#C13 static get a#offsetOf() → core::int return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get b#offsetOf() → core::int return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; - @#C12 + @#C13 static get #sizeOf() → core::int return #C24.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } @@ -134,18 +134,18 @@ constants { #C1 = "vm:ffi:struct-fields" #C2 = TypeLiteralConstant(ffi::Int8) #C3 = 10 - #C4 = ffi::_FfiInlineArray {elementType:#C2, length:#C3} - #C5 = TypeLiteralConstant(ffi::UnsignedLong) - #C6 = ffi::_FfiInlineArray {elementType:#C5, length:#C3} - #C7 = [#C2, #C2, #C4, #C6] - #C8 = null - #C9 = ffi::_FfiStructLayout {fieldTypes:#C7, packing:#C8} - #C10 = core::pragma {name:#C1, options:#C9} - #C11 = "vm:prefer-inline" - #C12 = core::pragma {name:#C11, options:#C8} - #C13 = ffi::Int8 {} - #C14 = false - #C15 = ffi::_ArraySize {dimension1:#C3, dimension2:#C8, dimension3:#C8, dimension4:#C8, dimension5:#C8, dimensions:#C8, variableLength:#C14} + #C4 = false + #C5 = ffi::_FfiInlineArray {elementType:#C2, length:#C3, variableLength:#C4} + #C6 = TypeLiteralConstant(ffi::UnsignedLong) + #C7 = ffi::_FfiInlineArray {elementType:#C6, length:#C3, variableLength:#C4} + #C8 = [#C2, #C2, #C5, #C7] + #C9 = null + #C10 = ffi::_FfiStructLayout {fieldTypes:#C8, packing:#C9} + #C11 = core::pragma {name:#C1, options:#C10} + #C12 = "vm:prefer-inline" + #C13 = core::pragma {name:#C12, options:#C9} + #C14 = ffi::Int8 {} + #C15 = ffi::_ArraySize {dimension1:#C3, dimension2:#C9, dimension3:#C9, dimension4:#C9, dimension5:#C9, dimensions:#C9, variableDimension:#C9} #C16 = [] #C17 = [#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3] #C18 = 40 @@ -164,7 +164,7 @@ constants { #C31 = 96 #C32 = [#C30, #C31, #C30, #C31, #C31, #C31, #C31, #C31, #C30, #C31, #C31, #C30, #C31, #C30, #C31, #C30, #C31, #C31, #C31, #C30, #C30, #C30] #C33 = [#C2, #C2] - #C34 = ffi::_FfiStructLayout {fieldTypes:#C33, packing:#C8} + #C34 = ffi::_FfiStructLayout {fieldTypes:#C33, packing:#C9} #C35 = core::pragma {name:#C1, options:#C34} #C36 = "cfe:ffi:native-marker" #C37 = "myNative" diff --git a/pkg/vm/testcases/transformations/ffi/native_fields.dart b/pkg/vm/testcases/transformations/ffi/native_fields.dart index 4e09112ffca..b1b8638f261 100644 --- a/pkg/vm/testcases/transformations/ffi/native_fields.dart +++ b/pkg/vm/testcases/transformations/ffi/native_fields.dart @@ -16,6 +16,26 @@ final class Vec2d extends Struct { external double y; } +final class MyStruct extends Struct { + @Array.variable() + external Array array; +} + +final class MyStruct2 extends Struct { + @Array.variableWithVariableDimension(1) + external Array array; +} + +final class MyStruct3 extends Struct { + @Array.variableMulti([1, 2]) + external Array>> array; +} + +final class MyStruct4 extends Struct { + @Array.variableMulti(variableDimension: 1, [1, 2]) + external Array>> array; +} + final class MyUnion extends Union { external Vec2d vector; external Pointer indirectVector; diff --git a/pkg/vm/testcases/transformations/ffi/native_fields.dart.aot.expect b/pkg/vm/testcases/transformations/ffi/native_fields.dart.aot.expect index 61db693eae7..3ca53aaaeaf 100644 --- a/pkg/vm/testcases/transformations/ffi/native_fields.dart.aot.expect +++ b/pkg/vm/testcases/transformations/ffi/native_fields.dart.aot.expect @@ -86,7 +86,7 @@ static get union() → self::MyUnion [@vm.inferred-return-type.metadata=dart.ffi::Array>>] @#C35 static get manyNumbers() → ffi::Array>> - return new ffi::Array::_>>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::Native::_addressOf>>>(#C34), #C9, #C36, #C39); + return new ffi::Array::_>>([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::Native::_addressOf>>>(#C34), #C9, #C36, #C21, #C39); static set manyNumbers([@vm.inferred-arg-type.metadata=dart.ffi::Array>>] synthesized ffi::Array>> #externalFieldValue) → void ffi::_memCopy([@vm.inferred-type.metadata=dart.ffi::Pointer] ffi::Native::_addressOf>>>(#C34), #C9, [@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C41.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); @@ -111,13 +111,13 @@ static method main() → void { synthesized core::int #singleElementSize = #C11; synthesized core::int #elementSize = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #singleElementSize.{core::num::*}([@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFlattened] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFlattened}{core::int}){(core::num) → core::num}; synthesized core::int #offset = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #elementSize.{core::num::*}(#index){(core::num) → core::num}; - } =>new ffi::Array::_>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFirst] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsRest] [@vm.inferred-type.metadata=!] #array.{ffi::Array::_nestedDimensionsRest}{core::List})); + } =>new ffi::Array::_>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFirst] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, [@vm.direct-call.metadata=dart.ffi::Array._variableLength] [@vm.inferred-type.metadata=dart.core::bool] #array.{ffi::Array::_variableLength}{core::bool}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsRest] [@vm.inferred-type.metadata=!] #array.{ffi::Array::_nestedDimensionsRest}{core::List})); synthesized core::int #index = _in::unsafeCast(1); [@vm.direct-call.metadata=dart.ffi::Array._checkIndex] [@vm.inferred-type.metadata=!? (skip check)] #array.{ffi::Array::_checkIndex}(#index){(core::int) → void}; synthesized core::int #singleElementSize = #C11; synthesized core::int #elementSize = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #singleElementSize.{core::num::*}([@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFlattened] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFlattened}{core::int}){(core::num) → core::num}; synthesized core::int #offset = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #elementSize.{core::num::*}(#index){(core::num) → core::num}; - } =>new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFirst] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsRest] [@vm.inferred-type.metadata=!] #array.{ffi::Array::_nestedDimensionsRest}{core::List}), 2, 123.45); + } =>new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFirst] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, [@vm.direct-call.metadata=dart.ffi::Array._variableLength] [@vm.inferred-type.metadata=dart.core::bool] #array.{ffi::Array::_variableLength}{core::bool}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsRest] [@vm.inferred-type.metadata=!] #array.{ffi::Array::_nestedDimensionsRest}{core::List}), 2, 123.45); self::manyNumbers = wholeArray; ffi::DoubleArray|[]=( block { synthesized ffi::Array #array = _in::unsafeCast>>( block { @@ -127,13 +127,13 @@ static method main() → void { synthesized core::int #singleElementSize = #C11; synthesized core::int #elementSize = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #singleElementSize.{core::num::*}([@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFlattened] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFlattened}{core::int}){(core::num) → core::num}; synthesized core::int #offset = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #elementSize.{core::num::*}(#index){(core::num) → core::num}; - } =>new ffi::Array::_>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFirst] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsRest] [@vm.inferred-type.metadata=!] #array.{ffi::Array::_nestedDimensionsRest}{core::List})); + } =>new ffi::Array::_>([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFirst] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, [@vm.direct-call.metadata=dart.ffi::Array._variableLength] [@vm.inferred-type.metadata=dart.core::bool] #array.{ffi::Array::_variableLength}{core::bool}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsRest] [@vm.inferred-type.metadata=!] #array.{ffi::Array::_nestedDimensionsRest}{core::List})); synthesized core::int #index = _in::unsafeCast(0); [@vm.direct-call.metadata=dart.ffi::Array._checkIndex] [@vm.inferred-type.metadata=!? (skip check)] #array.{ffi::Array::_checkIndex}(#index){(core::int) → void}; synthesized core::int #singleElementSize = #C11; synthesized core::int #elementSize = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #singleElementSize.{core::num::*}([@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFlattened] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFlattened}{core::int}){(core::num) → core::num}; synthesized core::int #offset = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.*] [@vm.inferred-type.metadata=int (skip check)] #elementSize.{core::num::*}(#index){(core::num) → core::num}; - } =>new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFirst] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsRest] [@vm.inferred-type.metadata=!] #array.{ffi::Array::_nestedDimensionsRest}{core::List}), 0, 54.321); + } =>new ffi::Array::_([@vm.direct-call.metadata=dart.ffi::_Compound._typedDataBase] #array.{ffi::_Compound::_typedDataBase}{core::Object}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+??] [@vm.inferred-type.metadata=int (skip check)] [@vm.direct-call.metadata=dart.ffi::_Compound._offsetInBytes] [@vm.inferred-type.metadata=int?] #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsFirst] [@vm.inferred-type.metadata=int] #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, [@vm.direct-call.metadata=dart.ffi::Array._variableLength] [@vm.inferred-type.metadata=dart.core::bool] #array.{ffi::Array::_variableLength}{core::bool}, [@vm.direct-call.metadata=dart.ffi::Array._nestedDimensionsRest] [@vm.inferred-type.metadata=!] #array.{ffi::Array::_nestedDimensionsRest}{core::List}), 0, 54.321); } constants { #C1 = "vm:ffi:struct-fields" diff --git a/pkg/vm/testcases/transformations/ffi/native_fields.dart.expect b/pkg/vm/testcases/transformations/ffi/native_fields.dart.expect index 986069d1b25..c8d9426c78c 100644 --- a/pkg/vm/testcases/transformations/ffi/native_fields.dart.expect +++ b/pkg/vm/testcases/transformations/ffi/native_fields.dart.expect @@ -44,7 +44,115 @@ final class Vec2d extends ffi::Struct { static get #sizeOf() → core::int return #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } -@#C20 +@#C21 +final class MyStruct extends ffi::Struct { + synthetic constructor •() → self::MyStruct + : super ffi::Struct::•() + ; + constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::MyStruct + : super ffi::Struct::_fromTypedDataBase(#typedDataBase, #offsetInBytes) + ; + @#C8 + constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyStruct + : super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes) + ; + @#C22 + @#C8 + get array() → ffi::Array + return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C10, #C17, #C23); + @#C22 + @#C8 + set array(synthesized ffi::Array #externalFieldValue) → void + return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); + @#C8 + static get array#offsetOf() → core::int + return #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + @#C8 + static get #sizeOf() → core::int + return #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; +} +@#C28 +final class MyStruct2 extends ffi::Struct { + synthetic constructor •() → self::MyStruct2 + : super ffi::Struct::•() + ; + constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::MyStruct2 + : super ffi::Struct::_fromTypedDataBase(#typedDataBase, #offsetInBytes) + ; + @#C8 + constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyStruct2 + : super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes) + ; + @#C29 + @#C8 + get array() → ffi::Array + return new ffi::Array::_(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct2::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C24, #C17, #C23); + @#C29 + @#C8 + set array(synthesized ffi::Array #externalFieldValue) → void + return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct2::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C30.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); + @#C8 + static get array#offsetOf() → core::int + return #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + @#C8 + static get #sizeOf() → core::int + return #C30.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; +} +@#C21 +final class MyStruct3 extends ffi::Struct { + synthetic constructor •() → self::MyStruct3 + : super ffi::Struct::•() + ; + constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::MyStruct3 + : super ffi::Struct::_fromTypedDataBase(#typedDataBase, #offsetInBytes) + ; + @#C8 + constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyStruct3 + : super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes) + ; + @#C33 + @#C8 + get array() → ffi::Array>> + return new ffi::Array::_>>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct3::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C10, #C17, #C32); + @#C33 + @#C8 + set array(synthesized ffi::Array>> #externalFieldValue) → void + return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct3::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); + @#C8 + static get array#offsetOf() → core::int + return #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + @#C8 + static get #sizeOf() → core::int + return #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; +} +@#C37 +final class MyStruct4 extends ffi::Struct { + synthetic constructor •() → self::MyStruct4 + : super ffi::Struct::•() + ; + constructor #fromTypedDataBase(synthesized core::Object #typedDataBase, synthesized core::int #offsetInBytes) → self::MyStruct4 + : super ffi::Struct::_fromTypedDataBase(#typedDataBase, #offsetInBytes) + ; + @#C8 + constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyStruct4 + : super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes) + ; + @#C38 + @#C8 + get array() → ffi::Array>> + return new ffi::Array::_>>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct4::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C24, #C17, #C32); + @#C38 + @#C8 + set array(synthesized ffi::Array>> #externalFieldValue) → void + return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct4::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C39.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); + @#C8 + static get array#offsetOf() → core::int + return #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; + @#C8 + static get #sizeOf() → core::int + return #C39.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; +} +@#C44 final class MyUnion extends ffi::Union { synthetic constructor •() → self::MyUnion : super ffi::Union::•() @@ -78,36 +186,36 @@ final class MyUnion extends ffi::Union { static get #sizeOf() → core::int return #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int}; } -@#C26 +@#C50 static get aString() → ffi::Pointer - return ffi::_loadPointer(ffi::Native::_addressOf>(#C25), #C10); + return ffi::_loadPointer(ffi::Native::_addressOf>(#C49), #C10); static set aString(synthesized ffi::Pointer #externalFieldValue) → void - ffi::_storePointer(ffi::Native::_addressOf>(#C25), #C10, #externalFieldValue); -@#C29 + ffi::_storePointer(ffi::Native::_addressOf>(#C49), #C10, #externalFieldValue); +@#C53 static get anInt() → core::int - return ffi::_loadInt32(ffi::Native::_addressOf(#C28), #C10); + return ffi::_loadInt32(ffi::Native::_addressOf(#C52), #C10); static set anInt(synthesized core::int #externalFieldValue) → void - ffi::_storeInt32(ffi::Native::_addressOf(#C28), #C10, #externalFieldValue); -@#C32 + ffi::_storeInt32(ffi::Native::_addressOf(#C52), #C10, #externalFieldValue); +@#C56 static get anotherInt() → core::int - return ffi::_loadAbiSpecificInt(ffi::Native::_addressOf(#C31), #C10); + return ffi::_loadAbiSpecificInt(ffi::Native::_addressOf(#C55), #C10); static set anotherInt(synthesized core::int #externalFieldValue) → void - ffi::_storeAbiSpecificInt(ffi::Native::_addressOf(#C31), #C10, #externalFieldValue); -@#C35 + ffi::_storeAbiSpecificInt(ffi::Native::_addressOf(#C55), #C10, #externalFieldValue); +@#C59 static get vector() → self::Vec2d - return new self::Vec2d::#fromTypedDataBase(ffi::Native::_addressOf(#C34), #C10); -@#C38 + return new self::Vec2d::#fromTypedDataBase(ffi::Native::_addressOf(#C58), #C10); +@#C62 static get union() → self::MyUnion - return new self::MyUnion::#fromTypedDataBase(ffi::Native::_addressOf(#C37), #C10); + return new self::MyUnion::#fromTypedDataBase(ffi::Native::_addressOf(#C61), #C10); static set union(synthesized self::MyUnion #externalFieldValue) → void - ffi::_memCopy(ffi::Native::_addressOf(#C37), #C10, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, self::MyUnion::#sizeOf); -@#C42 -@#C45 + ffi::_memCopy(ffi::Native::_addressOf(#C61), #C10, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, self::MyUnion::#sizeOf); +@#C64 +@#C67 static get manyNumbers() → ffi::Array>> - return new ffi::Array::_>>(ffi::Native::_addressOf>>>(#C44), #C10, #C39, #C46); -@#C42 + return new ffi::Array::_>>(ffi::Native::_addressOf>>>(#C66), #C10, #C24, #C48, #C68); +@#C64 static set manyNumbers(synthesized ffi::Array>> #externalFieldValue) → void - ffi::_memCopy(ffi::Native::_addressOf>>>(#C44), #C10, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C48.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); + ffi::_memCopy(ffi::Native::_addressOf>>>(#C66), #C10, #externalFieldValue.{ffi::_Compound::_typedDataBase}{core::Object}, #externalFieldValue.{ffi::_Compound::_offsetInBytes}{core::int}, #C70.{core::List::[]}(ffi::_abi()){(core::int) → core::int}); static method main() → void { core::print("first char of string: ${ffi::_loadAbiSpecificInt(self::aString, #C10)}"); core::print("global int: {${self::anInt}}"); @@ -115,10 +223,10 @@ static method main() → void { self::anInt = self::anInt.{core::num::+}(1){(core::num) → core::int}; final self::Vec2d vec = self::vector; core::print("(${vec.{self::Vec2d::x}{core::double}}, ${vec.{self::Vec2d::y}{core::double}})"); - self::union.{self::MyUnion::indirectVector} = ffi::Native::_addressOf(#C34); - core::print(ffi::Native::_addressOf(#C31)); - core::print(ffi::Native::_addressOf(#C34)); - core::print(ffi::Native::_addressOf(#C37)); + self::union.{self::MyUnion::indirectVector} = ffi::Native::_addressOf(#C58); + core::print(ffi::Native::_addressOf(#C55)); + core::print(ffi::Native::_addressOf(#C58)); + core::print(ffi::Native::_addressOf(#C61)); final ffi::Array>> wholeArray = self::manyNumbers; ffi::DoubleArray|[]=( block { synthesized ffi::Array #array = ( block { @@ -128,13 +236,13 @@ static method main() → void { synthesized core::int #singleElementSize = #C12; synthesized core::int #elementSize = #singleElementSize.{core::num::*}(#array.{ffi::Array::_nestedDimensionsFlattened}{core::int}){(core::num) → core::num}; synthesized core::int #offset = #elementSize.{core::num::*}(#index){(core::num) → core::num}; - } =>new ffi::Array::_>(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, #array.{ffi::Array::_nestedDimensionsRest}{core::List}))!; + } =>new ffi::Array::_>(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, #array.{ffi::Array::_variableLength}{core::bool}, #array.{ffi::Array::_nestedDimensionsRest}{core::List}))!; synthesized core::int #index = 1!; #array.{ffi::Array::_checkIndex}(#index){(core::int) → void}; synthesized core::int #singleElementSize = #C12; synthesized core::int #elementSize = #singleElementSize.{core::num::*}(#array.{ffi::Array::_nestedDimensionsFlattened}{core::int}){(core::num) → core::num}; synthesized core::int #offset = #elementSize.{core::num::*}(#index){(core::num) → core::num}; - } =>new ffi::Array::_(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, #array.{ffi::Array::_nestedDimensionsRest}{core::List}), 2, 123.45); + } =>new ffi::Array::_(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, #array.{ffi::Array::_variableLength}{core::bool}, #array.{ffi::Array::_nestedDimensionsRest}{core::List}), 2, 123.45); self::manyNumbers = wholeArray; ffi::DoubleArray|[]=( block { synthesized ffi::Array #array = ( block { @@ -144,13 +252,13 @@ static method main() → void { synthesized core::int #singleElementSize = #C12; synthesized core::int #elementSize = #singleElementSize.{core::num::*}(#array.{ffi::Array::_nestedDimensionsFlattened}{core::int}){(core::num) → core::num}; synthesized core::int #offset = #elementSize.{core::num::*}(#index){(core::num) → core::num}; - } =>new ffi::Array::_>(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, #array.{ffi::Array::_nestedDimensionsRest}{core::List}))!; + } =>new ffi::Array::_>(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, #array.{ffi::Array::_variableLength}{core::bool}, #array.{ffi::Array::_nestedDimensionsRest}{core::List}))!; synthesized core::int #index = 0!; #array.{ffi::Array::_checkIndex}(#index){(core::int) → void}; synthesized core::int #singleElementSize = #C12; synthesized core::int #elementSize = #singleElementSize.{core::num::*}(#array.{ffi::Array::_nestedDimensionsFlattened}{core::int}){(core::num) → core::num}; synthesized core::int #offset = #elementSize.{core::num::*}(#index){(core::num) → core::num}; - } =>new ffi::Array::_(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, #array.{ffi::Array::_nestedDimensionsRest}{core::List}), 0, 54.321); + } =>new ffi::Array::_(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #array.{ffi::Array::_nestedDimensionsFirst}{core::int}, #array.{ffi::Array::_variableLength}{core::bool}, #array.{ffi::Array::_nestedDimensionsRest}{core::List}), 0, 54.321); } constants { #C1 = "vm:ffi:struct-fields" @@ -168,37 +276,59 @@ constants { #C13 = [#C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12, #C12] #C14 = 16 #C15 = [#C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14] - #C16 = TypeLiteralConstant(self::Vec2d) - #C17 = TypeLiteralConstant(ffi::Pointer) - #C18 = [#C16, #C17] - #C19 = ffi::_FfiStructLayout {fieldTypes:#C18, packing:#C4} - #C20 = core::pragma {name:#C1, options:#C19} - #C21 = "cfe:ffi:native-marker" - #C22 = "aString" - #C23 = "#lib" - #C24 = false - #C25 = ffi::Native> {symbol:#C22, assetId:#C23, isLeaf:#C24} - #C26 = core::pragma {name:#C21, options:#C25} - #C27 = "anInt" - #C28 = ffi::Native {symbol:#C27, assetId:#C23, isLeaf:#C24} - #C29 = core::pragma {name:#C21, options:#C28} - #C30 = "anotherInt" - #C31 = ffi::Native {symbol:#C30, assetId:#C23, isLeaf:#C24} - #C32 = core::pragma {name:#C21, options:#C31} - #C33 = "vector" - #C34 = ffi::Native {symbol:#C33, assetId:#C23, isLeaf:#C24} - #C35 = core::pragma {name:#C21, options:#C34} - #C36 = "union" - #C37 = ffi::Native {symbol:#C36, assetId:#C23, isLeaf:#C24} - #C38 = core::pragma {name:#C21, options:#C37} - #C39 = 1 - #C40 = 2 - #C41 = 3 - #C42 = ffi::_ArraySize {dimension1:#C39, dimension2:#C40, dimension3:#C41, dimension4:#C4, dimension5:#C4, dimensions:#C4, variableLength:#C24} - #C43 = "manyNumbers" - #C44 = ffi::Native>>> {symbol:#C43, assetId:#C23, isLeaf:#C24} - #C45 = core::pragma {name:#C21, options:#C44} - #C46 = [#C40, #C41] - #C47 = 48 - #C48 = [#C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47, #C47] + #C16 = TypeLiteralConstant(ffi::Uint8) + #C17 = true + #C18 = ffi::_FfiInlineArray {elementType:#C16, length:#C10, variableLength:#C17} + #C19 = [#C18] + #C20 = ffi::_FfiStructLayout {fieldTypes:#C19, packing:#C4} + #C21 = core::pragma {name:#C1, options:#C20} + #C22 = ffi::_ArraySize {dimension1:#C10, dimension2:#C4, dimension3:#C4, dimension4:#C4, dimension5:#C4, dimensions:#C4, variableDimension:#C10} + #C23 = [] + #C24 = 1 + #C25 = ffi::_FfiInlineArray {elementType:#C16, length:#C24, variableLength:#C17} + #C26 = [#C25] + #C27 = ffi::_FfiStructLayout {fieldTypes:#C26, packing:#C4} + #C28 = core::pragma {name:#C1, options:#C27} + #C29 = ffi::_ArraySize {dimension1:#C24, dimension2:#C4, dimension3:#C4, dimension4:#C4, dimension5:#C4, dimensions:#C4, variableDimension:#C24} + #C30 = [#C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24] + #C31 = 2 + #C32 = [#C24, #C31] + #C33 = ffi::_ArraySize {dimension1:#C4, dimension2:#C4, dimension3:#C4, dimension4:#C4, dimension5:#C4, dimensions:#C32, variableDimension:#C10} + #C34 = ffi::_FfiInlineArray {elementType:#C16, length:#C31, variableLength:#C17} + #C35 = [#C34] + #C36 = ffi::_FfiStructLayout {fieldTypes:#C35, packing:#C4} + #C37 = core::pragma {name:#C1, options:#C36} + #C38 = ffi::_ArraySize {dimension1:#C4, dimension2:#C4, dimension3:#C4, dimension4:#C4, dimension5:#C4, dimensions:#C32, variableDimension:#C24} + #C39 = [#C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31, #C31] + #C40 = TypeLiteralConstant(self::Vec2d) + #C41 = TypeLiteralConstant(ffi::Pointer) + #C42 = [#C40, #C41] + #C43 = ffi::_FfiStructLayout {fieldTypes:#C42, packing:#C4} + #C44 = core::pragma {name:#C1, options:#C43} + #C45 = "cfe:ffi:native-marker" + #C46 = "aString" + #C47 = "#lib" + #C48 = false + #C49 = ffi::Native> {symbol:#C46, assetId:#C47, isLeaf:#C48} + #C50 = core::pragma {name:#C45, options:#C49} + #C51 = "anInt" + #C52 = ffi::Native {symbol:#C51, assetId:#C47, isLeaf:#C48} + #C53 = core::pragma {name:#C45, options:#C52} + #C54 = "anotherInt" + #C55 = ffi::Native {symbol:#C54, assetId:#C47, isLeaf:#C48} + #C56 = core::pragma {name:#C45, options:#C55} + #C57 = "vector" + #C58 = ffi::Native {symbol:#C57, assetId:#C47, isLeaf:#C48} + #C59 = core::pragma {name:#C45, options:#C58} + #C60 = "union" + #C61 = ffi::Native {symbol:#C60, assetId:#C47, isLeaf:#C48} + #C62 = core::pragma {name:#C45, options:#C61} + #C63 = 3 + #C64 = ffi::_ArraySize {dimension1:#C24, dimension2:#C31, dimension3:#C63, dimension4:#C4, dimension5:#C4, dimensions:#C4, variableDimension:#C4} + #C65 = "manyNumbers" + #C66 = ffi::Native>>> {symbol:#C65, assetId:#C47, isLeaf:#C48} + #C67 = core::pragma {name:#C45, options:#C66} + #C68 = [#C31, #C63] + #C69 = 48 + #C70 = [#C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69, #C69] } diff --git a/runtime/bin/ffi_test/ffi_test_functions.cc b/runtime/bin/ffi_test/ffi_test_functions.cc index 5a98d15a106..d3b3a2e4d59 100644 --- a/runtime/bin/ffi_test/ffi_test_functions.cc +++ b/runtime/bin/ffi_test/ffi_test_functions.cc @@ -1238,10 +1238,6 @@ struct Struct3BytesPackedIntCopy { }; #pragma pack(pop) -DART_EXPORT uint64_t SizeOfStruct3BytesPackedInt() { - return sizeof(Struct3BytesPackedIntCopy); -} - // Define ssize_t for Windows as intptr_t. #if defined(_WIN32) typedef intptr_t ssize_t; diff --git a/runtime/bin/ffi_test/ffi_test_functions_generated.cc b/runtime/bin/ffi_test/ffi_test_functions_generated.cc index bc03f0b1f58..3c58f72786a 100644 --- a/runtime/bin/ffi_test/ffi_test_functions_generated.cc +++ b/runtime/bin/ffi_test/ffi_test_functions_generated.cc @@ -598,6 +598,996 @@ struct StructInlineArrayVariableAlign { uint32_t a1[]; }; +struct StructInlineArrayVariable2 { + uint32_t a0; + uint8_t a1[1]; +}; + +struct StructInlineArrayVariableNested2 { + uint32_t a0; + uint8_t a1[1][2][2]; +}; + +struct StructInlineArrayVariableNestedDeep2 { + uint32_t a0; + uint8_t a1[1][2][2][2][2][2][2]; +}; + +// Used for testing the size of Struct1ByteBool. +DART_EXPORT uint64_t SizeOfStruct1ByteBool() { + std::cout << "SizeOfStruct1ByteBool" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct1ByteBool); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct1ByteInt. +DART_EXPORT uint64_t SizeOfStruct1ByteInt() { + std::cout << "SizeOfStruct1ByteInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct1ByteInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct3BytesHomogeneousUint8. +DART_EXPORT uint64_t SizeOfStruct3BytesHomogeneousUint8() { + std::cout << "SizeOfStruct3BytesHomogeneousUint8" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct3BytesHomogeneousUint8); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct3BytesInt2ByteAligned. +DART_EXPORT uint64_t SizeOfStruct3BytesInt2ByteAligned() { + std::cout << "SizeOfStruct3BytesInt2ByteAligned" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct3BytesInt2ByteAligned); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct4BytesHomogeneousInt16. +DART_EXPORT uint64_t SizeOfStruct4BytesHomogeneousInt16() { + std::cout << "SizeOfStruct4BytesHomogeneousInt16" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct4BytesHomogeneousInt16); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct4BytesFloat. +DART_EXPORT uint64_t SizeOfStruct4BytesFloat() { + std::cout << "SizeOfStruct4BytesFloat" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct4BytesFloat); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct7BytesHomogeneousUint8. +DART_EXPORT uint64_t SizeOfStruct7BytesHomogeneousUint8() { + std::cout << "SizeOfStruct7BytesHomogeneousUint8" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct7BytesHomogeneousUint8); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct7BytesInt4ByteAligned. +DART_EXPORT uint64_t SizeOfStruct7BytesInt4ByteAligned() { + std::cout << "SizeOfStruct7BytesInt4ByteAligned" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct7BytesInt4ByteAligned); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesInt. +DART_EXPORT uint64_t SizeOfStruct8BytesInt() { + std::cout << "SizeOfStruct8BytesInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesHomogeneousFloat. +DART_EXPORT uint64_t SizeOfStruct8BytesHomogeneousFloat() { + std::cout << "SizeOfStruct8BytesHomogeneousFloat" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesHomogeneousFloat); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesFloat. +DART_EXPORT uint64_t SizeOfStruct8BytesFloat() { + std::cout << "SizeOfStruct8BytesFloat" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesFloat); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesMixed. +DART_EXPORT uint64_t SizeOfStruct8BytesMixed() { + std::cout << "SizeOfStruct8BytesMixed" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesMixed); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct9BytesHomogeneousUint8. +DART_EXPORT uint64_t SizeOfStruct9BytesHomogeneousUint8() { + std::cout << "SizeOfStruct9BytesHomogeneousUint8" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct9BytesHomogeneousUint8); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct9BytesInt4Or8ByteAligned. +DART_EXPORT uint64_t SizeOfStruct9BytesInt4Or8ByteAligned() { + std::cout << "SizeOfStruct9BytesInt4Or8ByteAligned" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct9BytesInt4Or8ByteAligned); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct10BytesHomogeneousBool. +DART_EXPORT uint64_t SizeOfStruct10BytesHomogeneousBool() { + std::cout << "SizeOfStruct10BytesHomogeneousBool" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct10BytesHomogeneousBool); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct12BytesHomogeneousFloat. +DART_EXPORT uint64_t SizeOfStruct12BytesHomogeneousFloat() { + std::cout << "SizeOfStruct12BytesHomogeneousFloat" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct12BytesHomogeneousFloat); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct12BytesHomogeneousInt32. +DART_EXPORT uint64_t SizeOfStruct12BytesHomogeneousInt32() { + std::cout << "SizeOfStruct12BytesHomogeneousInt32" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct12BytesHomogeneousInt32); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct16BytesHomogeneousFloat. +DART_EXPORT uint64_t SizeOfStruct16BytesHomogeneousFloat() { + std::cout << "SizeOfStruct16BytesHomogeneousFloat" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct16BytesHomogeneousFloat); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct16BytesMixed. +DART_EXPORT uint64_t SizeOfStruct16BytesMixed() { + std::cout << "SizeOfStruct16BytesMixed" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct16BytesMixed); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct16BytesMixed2. +DART_EXPORT uint64_t SizeOfStruct16BytesMixed2() { + std::cout << "SizeOfStruct16BytesMixed2" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct16BytesMixed2); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct17BytesInt. +DART_EXPORT uint64_t SizeOfStruct17BytesInt() { + std::cout << "SizeOfStruct17BytesInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct17BytesInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct19BytesHomogeneousUint8. +DART_EXPORT uint64_t SizeOfStruct19BytesHomogeneousUint8() { + std::cout << "SizeOfStruct19BytesHomogeneousUint8" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct19BytesHomogeneousUint8); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct20BytesHomogeneousInt32. +DART_EXPORT uint64_t SizeOfStruct20BytesHomogeneousInt32() { + std::cout << "SizeOfStruct20BytesHomogeneousInt32" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct20BytesHomogeneousInt32); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct20BytesHomogeneousFloat. +DART_EXPORT uint64_t SizeOfStruct20BytesHomogeneousFloat() { + std::cout << "SizeOfStruct20BytesHomogeneousFloat" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct20BytesHomogeneousFloat); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct32BytesHomogeneousDouble. +DART_EXPORT uint64_t SizeOfStruct32BytesHomogeneousDouble() { + std::cout << "SizeOfStruct32BytesHomogeneousDouble" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct32BytesHomogeneousDouble); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct40BytesHomogeneousDouble. +DART_EXPORT uint64_t SizeOfStruct40BytesHomogeneousDouble() { + std::cout << "SizeOfStruct40BytesHomogeneousDouble" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct40BytesHomogeneousDouble); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct1024BytesHomogeneousUint64. +DART_EXPORT uint64_t SizeOfStruct1024BytesHomogeneousUint64() { + std::cout << "SizeOfStruct1024BytesHomogeneousUint64" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct1024BytesHomogeneousUint64); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructAlignmentInt16. +DART_EXPORT uint64_t SizeOfStructAlignmentInt16() { + std::cout << "SizeOfStructAlignmentInt16" + << "()" + << "\n"; + + uint64_t result = sizeof(StructAlignmentInt16); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructAlignmentInt32. +DART_EXPORT uint64_t SizeOfStructAlignmentInt32() { + std::cout << "SizeOfStructAlignmentInt32" + << "()" + << "\n"; + + uint64_t result = sizeof(StructAlignmentInt32); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructAlignmentInt64. +DART_EXPORT uint64_t SizeOfStructAlignmentInt64() { + std::cout << "SizeOfStructAlignmentInt64" + << "()" + << "\n"; + + uint64_t result = sizeof(StructAlignmentInt64); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesNestedInt. +DART_EXPORT uint64_t SizeOfStruct8BytesNestedInt() { + std::cout << "SizeOfStruct8BytesNestedInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesNestedInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesNestedFloat. +DART_EXPORT uint64_t SizeOfStruct8BytesNestedFloat() { + std::cout << "SizeOfStruct8BytesNestedFloat" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesNestedFloat); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesNestedFloat2. +DART_EXPORT uint64_t SizeOfStruct8BytesNestedFloat2() { + std::cout << "SizeOfStruct8BytesNestedFloat2" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesNestedFloat2); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesNestedMixed. +DART_EXPORT uint64_t SizeOfStruct8BytesNestedMixed() { + std::cout << "SizeOfStruct8BytesNestedMixed" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesNestedMixed); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct16BytesNestedInt. +DART_EXPORT uint64_t SizeOfStruct16BytesNestedInt() { + std::cout << "SizeOfStruct16BytesNestedInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct16BytesNestedInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct32BytesNestedInt. +DART_EXPORT uint64_t SizeOfStruct32BytesNestedInt() { + std::cout << "SizeOfStruct32BytesNestedInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct32BytesNestedInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructNestedIntStructAlignmentInt16. +DART_EXPORT uint64_t SizeOfStructNestedIntStructAlignmentInt16() { + std::cout << "SizeOfStructNestedIntStructAlignmentInt16" + << "()" + << "\n"; + + uint64_t result = sizeof(StructNestedIntStructAlignmentInt16); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructNestedIntStructAlignmentInt32. +DART_EXPORT uint64_t SizeOfStructNestedIntStructAlignmentInt32() { + std::cout << "SizeOfStructNestedIntStructAlignmentInt32" + << "()" + << "\n"; + + uint64_t result = sizeof(StructNestedIntStructAlignmentInt32); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructNestedIntStructAlignmentInt64. +DART_EXPORT uint64_t SizeOfStructNestedIntStructAlignmentInt64() { + std::cout << "SizeOfStructNestedIntStructAlignmentInt64" + << "()" + << "\n"; + + uint64_t result = sizeof(StructNestedIntStructAlignmentInt64); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructNestedIrregularBig. +DART_EXPORT uint64_t SizeOfStructNestedIrregularBig() { + std::cout << "SizeOfStructNestedIrregularBig" + << "()" + << "\n"; + + uint64_t result = sizeof(StructNestedIrregularBig); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructNestedIrregularBigger. +DART_EXPORT uint64_t SizeOfStructNestedIrregularBigger() { + std::cout << "SizeOfStructNestedIrregularBigger" + << "()" + << "\n"; + + uint64_t result = sizeof(StructNestedIrregularBigger); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructNestedIrregularEvenBigger. +DART_EXPORT uint64_t SizeOfStructNestedIrregularEvenBigger() { + std::cout << "SizeOfStructNestedIrregularEvenBigger" + << "()" + << "\n"; + + uint64_t result = sizeof(StructNestedIrregularEvenBigger); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesInlineArrayInt. +DART_EXPORT uint64_t SizeOfStruct8BytesInlineArrayInt() { + std::cout << "SizeOfStruct8BytesInlineArrayInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesInlineArrayInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct10BytesInlineArrayBool. +DART_EXPORT uint64_t SizeOfStruct10BytesInlineArrayBool() { + std::cout << "SizeOfStruct10BytesInlineArrayBool" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct10BytesInlineArrayBool); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArrayIrregular. +DART_EXPORT uint64_t SizeOfStructInlineArrayIrregular() { + std::cout << "SizeOfStructInlineArrayIrregular" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArrayIrregular); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArray100Bytes. +DART_EXPORT uint64_t SizeOfStructInlineArray100Bytes() { + std::cout << "SizeOfStructInlineArray100Bytes" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArray100Bytes); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArrayBig. +DART_EXPORT uint64_t SizeOfStructInlineArrayBig() { + std::cout << "SizeOfStructInlineArrayBig" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArrayBig); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructStruct16BytesHomogeneousFloat2. +DART_EXPORT uint64_t SizeOfStructStruct16BytesHomogeneousFloat2() { + std::cout << "SizeOfStructStruct16BytesHomogeneousFloat2" + << "()" + << "\n"; + + uint64_t result = sizeof(StructStruct16BytesHomogeneousFloat2); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructStruct32BytesHomogeneousDouble2. +DART_EXPORT uint64_t SizeOfStructStruct32BytesHomogeneousDouble2() { + std::cout << "SizeOfStructStruct32BytesHomogeneousDouble2" + << "()" + << "\n"; + + uint64_t result = sizeof(StructStruct32BytesHomogeneousDouble2); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructStruct16BytesMixed3. +DART_EXPORT uint64_t SizeOfStructStruct16BytesMixed3() { + std::cout << "SizeOfStructStruct16BytesMixed3" + << "()" + << "\n"; + + uint64_t result = sizeof(StructStruct16BytesMixed3); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesInlineArrayMultiDimensionalInt. +DART_EXPORT uint64_t SizeOfStruct8BytesInlineArrayMultiDimensionalInt() { + std::cout << "SizeOfStruct8BytesInlineArrayMultiDimensionalInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesInlineArrayMultiDimensionalInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct32BytesInlineArrayMultiDimensionalInt. +DART_EXPORT uint64_t SizeOfStruct32BytesInlineArrayMultiDimensionalInt() { + std::cout << "SizeOfStruct32BytesInlineArrayMultiDimensionalInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct32BytesInlineArrayMultiDimensionalInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct64BytesInlineArrayMultiDimensionalInt. +DART_EXPORT uint64_t SizeOfStruct64BytesInlineArrayMultiDimensionalInt() { + std::cout << "SizeOfStruct64BytesInlineArrayMultiDimensionalInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct64BytesInlineArrayMultiDimensionalInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct4BytesInlineArrayMultiDimensionalInt. +DART_EXPORT uint64_t SizeOfStruct4BytesInlineArrayMultiDimensionalInt() { + std::cout << "SizeOfStruct4BytesInlineArrayMultiDimensionalInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct4BytesInlineArrayMultiDimensionalInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct3BytesPackedInt. +DART_EXPORT uint64_t SizeOfStruct3BytesPackedInt() { + std::cout << "SizeOfStruct3BytesPackedInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct3BytesPackedInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct3BytesPackedIntMembersAligned. +DART_EXPORT uint64_t SizeOfStruct3BytesPackedIntMembersAligned() { + std::cout << "SizeOfStruct3BytesPackedIntMembersAligned" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct3BytesPackedIntMembersAligned); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct5BytesPackedMixed. +DART_EXPORT uint64_t SizeOfStruct5BytesPackedMixed() { + std::cout << "SizeOfStruct5BytesPackedMixed" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct5BytesPackedMixed); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructNestedAlignmentStruct5BytesPackedMixed. +DART_EXPORT uint64_t SizeOfStructNestedAlignmentStruct5BytesPackedMixed() { + std::cout << "SizeOfStructNestedAlignmentStruct5BytesPackedMixed" + << "()" + << "\n"; + + uint64_t result = sizeof(StructNestedAlignmentStruct5BytesPackedMixed); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct6BytesInlineArrayInt. +DART_EXPORT uint64_t SizeOfStruct6BytesInlineArrayInt() { + std::cout << "SizeOfStruct6BytesInlineArrayInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct6BytesInlineArrayInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct8BytesPackedInt. +DART_EXPORT uint64_t SizeOfStruct8BytesPackedInt() { + std::cout << "SizeOfStruct8BytesPackedInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct8BytesPackedInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct9BytesPackedMixed. +DART_EXPORT uint64_t SizeOfStruct9BytesPackedMixed() { + std::cout << "SizeOfStruct9BytesPackedMixed" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct9BytesPackedMixed); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Struct15BytesInlineArrayMixed. +DART_EXPORT uint64_t SizeOfStruct15BytesInlineArrayMixed() { + std::cout << "SizeOfStruct15BytesInlineArrayMixed" + << "()" + << "\n"; + + uint64_t result = sizeof(Struct15BytesInlineArrayMixed); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Union4BytesMixed. +DART_EXPORT uint64_t SizeOfUnion4BytesMixed() { + std::cout << "SizeOfUnion4BytesMixed" + << "()" + << "\n"; + + uint64_t result = sizeof(Union4BytesMixed); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Union8BytesNestedFloat. +DART_EXPORT uint64_t SizeOfUnion8BytesNestedFloat() { + std::cout << "SizeOfUnion8BytesNestedFloat" + << "()" + << "\n"; + + uint64_t result = sizeof(Union8BytesNestedFloat); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Union9BytesNestedInt. +DART_EXPORT uint64_t SizeOfUnion9BytesNestedInt() { + std::cout << "SizeOfUnion9BytesNestedInt" + << "()" + << "\n"; + + uint64_t result = sizeof(Union9BytesNestedInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Union16BytesNestedInlineArrayFloat. +DART_EXPORT uint64_t SizeOfUnion16BytesNestedInlineArrayFloat() { + std::cout << "SizeOfUnion16BytesNestedInlineArrayFloat" + << "()" + << "\n"; + + uint64_t result = sizeof(Union16BytesNestedInlineArrayFloat); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of Union16BytesNestedFloat. +DART_EXPORT uint64_t SizeOfUnion16BytesNestedFloat() { + std::cout << "SizeOfUnion16BytesNestedFloat" + << "()" + << "\n"; + + uint64_t result = sizeof(Union16BytesNestedFloat); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArrayInt. +DART_EXPORT uint64_t SizeOfStructInlineArrayInt() { + std::cout << "SizeOfStructInlineArrayInt" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArrayInt); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArrayVariable. +DART_EXPORT uint64_t SizeOfStructInlineArrayVariable() { + std::cout << "SizeOfStructInlineArrayVariable" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArrayVariable); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArrayVariableNested. +DART_EXPORT uint64_t SizeOfStructInlineArrayVariableNested() { + std::cout << "SizeOfStructInlineArrayVariableNested" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArrayVariableNested); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArrayVariableNestedDeep. +DART_EXPORT uint64_t SizeOfStructInlineArrayVariableNestedDeep() { + std::cout << "SizeOfStructInlineArrayVariableNestedDeep" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArrayVariableNestedDeep); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArrayVariableAlign. +DART_EXPORT uint64_t SizeOfStructInlineArrayVariableAlign() { + std::cout << "SizeOfStructInlineArrayVariableAlign" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArrayVariableAlign); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArrayVariable2. +DART_EXPORT uint64_t SizeOfStructInlineArrayVariable2() { + std::cout << "SizeOfStructInlineArrayVariable2" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArrayVariable2); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArrayVariableNested2. +DART_EXPORT uint64_t SizeOfStructInlineArrayVariableNested2() { + std::cout << "SizeOfStructInlineArrayVariableNested2" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArrayVariableNested2); + + std::cout << "result = " << result << "\n"; + + return result; +} + +// Used for testing the size of StructInlineArrayVariableNestedDeep2. +DART_EXPORT uint64_t SizeOfStructInlineArrayVariableNestedDeep2() { + std::cout << "SizeOfStructInlineArrayVariableNestedDeep2" + << "()" + << "\n"; + + uint64_t result = sizeof(StructInlineArrayVariableNestedDeep2); + + std::cout << "result = " << result << "\n"; + + return result; +} + // Used for testing structs and unions by value. // Smallest struct with data. // 10 struct arguments will exhaust available registers. @@ -4903,6 +5893,42 @@ PassPointerStructInlineArrayVariableAlign(StructInlineArrayVariableAlign* a0) { return result; } +// Used for testing structs and unions by value. +// Variable length array with variable dimension of 1. +DART_EXPORT int64_t +PassPointerStructInlineArrayVariable2(StructInlineArrayVariable2* a0) { + std::cout << "PassPointerStructInlineArrayVariable2" + << "((" << a0->a0 << ", [" << static_cast(a0->a1[0]) << ", " + << static_cast(a0->a1[1]) << ", " + << static_cast(a0->a1[2]) << ", " + << static_cast(a0->a1[3]) << ", " + << static_cast(a0->a1[4]) << ", " + << static_cast(a0->a1[5]) << ", " + << static_cast(a0->a1[6]) << ", " + << static_cast(a0->a1[7]) << ", " + << static_cast(a0->a1[8]) << ", " + << static_cast(a0->a1[9]) << "]))" + << "\n"; + + int64_t result = 0; + + result += a0->a0; + result += a0->a1[0]; + result += a0->a1[1]; + result += a0->a1[2]; + result += a0->a1[3]; + result += a0->a1[4]; + result += a0->a1[5]; + result += a0->a1[6]; + result += a0->a1[7]; + result += a0->a1[8]; + result += a0->a1[9]; + + std::cout << "result = " << result << "\n"; + + return result; +} + // Used for testing structs and unions by value. // Smallest struct with data. DART_EXPORT Struct1ByteInt ReturnStruct1ByteInt(int8_t a0) { @@ -12579,6 +13605,64 @@ DART_EXPORT intptr_t TestPassPointerStructInlineArrayVariableAlign( return 0; } +// Used for testing structs and unions by value. +// Variable length array with variable dimension of 1. +DART_EXPORT intptr_t TestPassPointerStructInlineArrayVariable2( + // NOLINTNEXTLINE(whitespace/parens) + int64_t (*f)(StructInlineArrayVariable2* a0)) { + StructInlineArrayVariable2* a0 = static_cast( + calloc(1, sizeof(StructInlineArrayVariable2) + 10 * sizeof(uint8_t))); + + a0->a0 = 1; + a0->a1[0] = 2; + a0->a1[1] = 3; + a0->a1[2] = 4; + a0->a1[3] = 5; + a0->a1[4] = 6; + a0->a1[5] = 7; + a0->a1[6] = 8; + a0->a1[7] = 9; + a0->a1[8] = 10; + a0->a1[9] = 11; + + std::cout << "Calling TestPassPointerStructInlineArrayVariable2(" + << "((" << a0->a0 << ", [" << static_cast(a0->a1[0]) << ", " + << static_cast(a0->a1[1]) << ", " + << static_cast(a0->a1[2]) << ", " + << static_cast(a0->a1[3]) << ", " + << static_cast(a0->a1[4]) << ", " + << static_cast(a0->a1[5]) << ", " + << static_cast(a0->a1[6]) << ", " + << static_cast(a0->a1[7]) << ", " + << static_cast(a0->a1[8]) << ", " + << static_cast(a0->a1[9]) << "]))" + << ")\n"; + + int64_t result = f(a0); + + std::cout << "result = " << result << "\n"; + + CHECK_EQ(66, result); + + // Pass argument that will make the Dart callback throw. + a0->a0 = 42; + + result = f(a0); + + CHECK_EQ(0, result); + + // Pass argument that will make the Dart callback return null. + a0->a0 = 84; + + result = f(a0); + + CHECK_EQ(0, result); + + free(a0); + + return 0; +} + // Used for testing structs and unions by value. // Smallest struct with data. DART_EXPORT intptr_t TestReturnStruct1ByteInt( @@ -21098,6 +22182,44 @@ DART_EXPORT void TestAsyncPassPointerStructInlineArrayVariableAlign( free(a0); } +// Used for testing structs and unions by value. +// Variable length array with variable dimension of 1. +DART_EXPORT void TestAsyncPassPointerStructInlineArrayVariable2( + // NOLINTNEXTLINE(whitespace/parens) + void (*f)(StructInlineArrayVariable2* a0)) { + StructInlineArrayVariable2* a0 = static_cast( + calloc(1, sizeof(StructInlineArrayVariable2) + 10 * sizeof(uint8_t))); + + a0->a0 = 1; + a0->a1[0] = 2; + a0->a1[1] = 3; + a0->a1[2] = 4; + a0->a1[3] = 5; + a0->a1[4] = 6; + a0->a1[5] = 7; + a0->a1[6] = 8; + a0->a1[7] = 9; + a0->a1[8] = 10; + a0->a1[9] = 11; + + std::cout << "Calling TestAsyncPassPointerStructInlineArrayVariable2(" + << "((" << a0->a0 << ", [" << static_cast(a0->a1[0]) << ", " + << static_cast(a0->a1[1]) << ", " + << static_cast(a0->a1[2]) << ", " + << static_cast(a0->a1[3]) << ", " + << static_cast(a0->a1[4]) << ", " + << static_cast(a0->a1[5]) << ", " + << static_cast(a0->a1[6]) << ", " + << static_cast(a0->a1[7]) << ", " + << static_cast(a0->a1[8]) << ", " + << static_cast(a0->a1[9]) << "]))" + << ")\n"; + + f(a0); + + free(a0); +} + // Used for testing structs and unions by value. // Smallest struct with data. DART_EXPORT void TestAsyncReturnStruct1ByteInt( diff --git a/runtime/vm/compiler/ffi/native_type.cc b/runtime/vm/compiler/ffi/native_type.cc index c632313bb1c..8f77a2c6138 100644 --- a/runtime/vm/compiler/ffi/native_type.cc +++ b/runtime/vm/compiler/ffi/native_type.cc @@ -488,7 +488,7 @@ static const NativeType* CompoundFromPragma(Zone* zone, .Equals(Symbols::FfiStructLayoutArray())); const auto& struct_layout_array_fields = Array::Handle(zone, struct_layout_array_class.fields()); - ASSERT(struct_layout_array_fields.Length() == 2); + ASSERT(struct_layout_array_fields.Length() == 3); const auto& element_type_field = Field::Handle(zone, Field::RawCast(struct_layout_array_fields.At(0))); ASSERT(String::Handle(zone, element_type_field.UserVisibleName()) @@ -505,6 +505,18 @@ static const NativeType* CompoundFromPragma(Zone* zone, if (*error != nullptr) { return nullptr; } + +#if defined(DEBUG) + const auto& variable_length_field = + Field::Handle(zone, Field::RawCast(struct_layout_array_fields.At(2))); + ASSERT(String::Handle(zone, variable_length_field.UserVisibleName()) + .Equals(Symbols::VariableLength())); + const auto& variable_length = Bool::Handle( + zone, Bool::RawCast(field_instance.GetField(variable_length_field))); + ASSERT(variable_length.value() == true || + variable_length.value() == false); +#endif + const auto field_native_type = new (zone) NativeArrayType(*element_type, length.Value()); field_native_types.Add(field_native_type); diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index 8a26f385fad..dfc59c17ded 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -281,6 +281,7 @@ class ObjectPointerVisitor; V(Value, "value") \ V(Values, "values") \ V(VarArgs, "VarArgs") \ + V(VariableLength, "variableLength") \ V(WeakArray, "WeakArray") \ V(WeakSerializationReference, "WeakSerializationReference") \ V(_AsyncStarStreamController, "_AsyncStarStreamController") \ diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart index 4d2ca4701af..2862e45790a 100644 --- a/sdk/lib/_internal/vm/lib/ffi_patch.dart +++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart @@ -332,9 +332,16 @@ final class _NativeCallableListener @patch @pragma("vm:entry-point") final class Array extends _Compound { + /// The size of the current dimension. + /// + /// This is variable if [_variableLength] is true. @pragma("vm:entry-point") final int _size; + /// Whether the current dimension is variable. + @pragma("vm:entry-point") + final bool _variableLength; + @pragma("vm:entry-point") final List _nestedDimensions; @@ -347,6 +354,7 @@ final class Array extends _Compound { super._typedDataBase, super._offsetInBytes, this._size, + this._variableLength, this._nestedDimensions, ) : super._fromTypedDataBase(); @@ -362,13 +370,9 @@ final class Array extends _Compound { List get _nestedDimensionsRest => _nestedDimensionsRestCache ??= _nestedDimensions.sublist(1); - static const _variableLengthLength = 0; - @pragma('vm:prefer-inline') void _checkIndex(int index) { - if (_size == _variableLengthLength) { - return; - } + if (_variableLength) return; if (index < 0 || index >= _size) { throw RangeError.range(index, 0, _size - 1); } @@ -1520,6 +1524,9 @@ final class _ArraySize implements Array { int get _size => throw UnsupportedError('_ArraySize._size'); + bool get _variableLength => + throw UnsupportedError('_ArraySize._variableLength'); + Object get _typedDataBase => throw UnsupportedError('_ArraySize._typedDataBase'); diff --git a/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart b/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart index ecea89500f3..91d6c130801 100644 --- a/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart +++ b/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart @@ -45,6 +45,9 @@ final class _FfiInlineArray { @pragma("vm:entry-point") @pragma("wasm:entry-point") final int length; + @pragma("vm:entry-point") + @pragma("wasm:entry-point") + final bool variableLength; - const _FfiInlineArray(this.elementType, this.length); + const _FfiInlineArray(this.elementType, this.length, this.variableLength); } diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart index c316846d373..fd3afa81b3d 100644 --- a/sdk/lib/ffi/ffi.dart +++ b/sdk/lib/ffi/ffi.dart @@ -157,7 +157,7 @@ final class Array extends _Compound { /// } /// ``` /// - /// The variable lenght is always the outermost dimension of the array. + /// The variable length is always the outermost dimension of the array. /// /// ```dart /// import 'dart:ffi'; @@ -195,6 +195,51 @@ final class Array extends _Compound { int dimension5, ]) = _ArraySize.variable; + /// Annotation to specify a variable length [Array] with a configurable + /// variable dimension ([dimension1]) in [Struct]s. + /// + /// Can only be used on the last field of a struct. When [dimension1] is set + /// to a value greater than zero (`0`), the last field of the struct is taken + /// into account in [sizeOf] and [AllocatorAlloc.call]. This is particularly + /// useful when working with Windows APIs, where most structs with variable + /// length arrays are defined to have an initial dimension of one (`1`). + /// + /// ```dart + /// import 'dart:ffi'; + /// import 'package:ffi/ffi.dart'; + /// + /// final class MyStruct extends Struct { + /// @Size() + /// external int length; + /// + /// @Array.variableWithVariableDimension(1) + /// external Array inlineArray; + /// + /// static Pointer allocate(Allocator allocator, int length) { + /// final lengthInBytes = sizeOf() + sizeOf() * (length - 1); + /// final result = allocator.allocate(lengthInBytes); + /// result.ref.length = length; + /// return result; + /// } + /// } + /// + /// void main() { + /// final myStruct = MyStruct.allocate(calloc, 10); + /// } + /// ``` + /// + /// The variable length is always the outermost dimension of the array. + /// + /// Do not invoke in normal code. + @Since('3.7') + const factory Array.variableWithVariableDimension([ + int dimension1, + int dimension2, + int dimension3, + int dimension4, + int dimension5, + ]) = _ArraySize.variableWithVariableDimension; + /// Annotation to a variable length [Array] in [Struct]s. /// /// ```dart @@ -204,17 +249,29 @@ final class Array extends _Compound { /// } /// /// final class MyStruct2 extends Struct { + /// @Array.variableMulti(variableDimension: 1, [2, 2, 2]) + /// external Array>>> fourDimensionalInlineArray; + /// } + /// + /// final class MyStruct3 extends Struct { /// @Array.variableMulti([2, 2, 2, 2, 2, 2, 2]) /// external Array>>>>>>> eightDimensionalInlineArray; /// } /// ``` /// - /// The variable lenght is always the outermost dimension of the array. + /// The variable length is always the outermost dimension of the array. + /// + /// [variableDimension] is the outermost dimension of the variable length + /// array (defaults to zero (`0`)). When [variableDimension] is set to a value + /// greater than zero (`0`), the last field of the struct is taken into + /// account in [sizeOf] and [AllocatorAlloc.call]. /// /// Do not invoke in normal code. @Since('3.6') - const factory Array.variableMulti(List dimensions) = - _ArraySize.variableMulti; + const factory Array.variableMulti( + List dimensions, { + @Since('3.7') int variableDimension, + }) = _ArraySize.variableMulti; } final class _ArraySize implements Array { @@ -226,9 +283,9 @@ final class _ArraySize implements Array { final List? dimensions; - // When `true`, [dimension1] is [variableLengthLength], or [dimensions] - // should be prepended with [variableLengthLength]. - final bool variableLength; + // When non-null, [dimension1] is equal to this value, or [dimensions] should + // be prepended with this value. + final int? variableDimension; const _ArraySize( this.dimension1, [ @@ -237,7 +294,7 @@ final class _ArraySize implements Array { this.dimension4, this.dimension5, ]) : dimensions = null, - variableLength = false; + variableDimension = null; const _ArraySize.multi(this.dimensions) : dimension1 = null, @@ -245,40 +302,37 @@ final class _ArraySize implements Array { dimension3 = null, dimension4 = null, dimension5 = null, - variableLength = false; - - // Inline arrays in C of length 0 are undefined. - // - // GNU uses 0 to signal variable length arrays. - // https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html - // - // Some Windows APIs use an inline array length of 1 for variable length - // inline arrays. - // https://devblogs.microsoft.com/oldnewthing/20040826-00/?p=38043 - // However, this is perfectly valid C code. - // - // We follow the GNU standard here. This follows the behavior of structs - // with variable length arrays when malloc'ed and passed by value (the - // variable length array is ignored). - static const variableLengthLength = 0; + variableDimension = null; const _ArraySize.variable([ this.dimension2, this.dimension3, this.dimension4, this.dimension5, - ]) : dimension1 = variableLengthLength, + ]) : dimension1 = 0, dimensions = null, - variableLength = true; + variableDimension = 0; - const _ArraySize.variableMulti(List nestedDimensions) - : dimensions = nestedDimensions, // Should be `[0, ...nestedDimensions]`. - dimension1 = null, - dimension2 = null, - dimension3 = null, - dimension4 = null, - dimension5 = null, - variableLength = true; + const _ArraySize.variableWithVariableDimension([ + this.dimension1, + this.dimension2, + this.dimension3, + this.dimension4, + this.dimension5, + ]) : dimensions = null, + variableDimension = dimension1; + + const _ArraySize.variableMulti( + List nestedDimensions, { + int variableDimension = 0, + }) : // Should be `[variableDimension, ...nestedDimensions]`. + dimensions = nestedDimensions, + dimension1 = null, + dimension2 = null, + dimension3 = null, + dimension4 = null, + dimension5 = null, + variableDimension = variableDimension; } /// Extension on [Pointer] specialized for the type argument [NativeFunction]. diff --git a/tests/ffi/function_callbacks_structs_by_value_generated_test.dart b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart index b37e1f3742d..97f37f6cafd 100644 --- a/tests/ffi/function_callbacks_structs_by_value_generated_test.dart +++ b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart @@ -580,6 +580,14 @@ final testCases = [ ), noChecks, ), + CallbackTest.withCheck( + "PassPointerStructInlineArrayVariable2", + Pointer.fromFunction( + passPointerStructInlineArrayVariable2, + 0, + ), + noChecks, + ), CallbackTest.withCheck( "ReturnStruct1ByteInt", Pointer.fromFunction(returnStruct1ByteInt), @@ -8629,6 +8637,59 @@ int passPointerStructInlineArrayVariableAlign( return result; } +typedef PassPointerStructInlineArrayVariable2Type = + Int64 Function(Pointer); + +// Global variables to be able to test inputs after callback returned. +Pointer passPointerStructInlineArrayVariable2_a0 = + nullptr; + +// Result variable also global, so we can delete it after the callback. +int passPointerStructInlineArrayVariable2Result = 0; + +int passPointerStructInlineArrayVariable2CalculateResult() { + int result = 0; + + result += passPointerStructInlineArrayVariable2_a0.ref.a0; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[0]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[1]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[2]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[3]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[4]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[5]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[6]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[7]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[8]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[9]; + + passPointerStructInlineArrayVariable2Result = result; + + return result; +} + +/// Variable length array with variable dimension of 1. +int passPointerStructInlineArrayVariable2( + Pointer a0, +) { + print("passPointerStructInlineArrayVariable2(${a0})"); + + // Possibly throw. + if (a0.ref.a0 == 42 || a0.ref.a0 == 84) { + print("throwing!"); + throw Exception( + "PassPointerStructInlineArrayVariable2 throwing on purpose!", + ); + } + + passPointerStructInlineArrayVariable2_a0 = a0; + + final result = passPointerStructInlineArrayVariable2CalculateResult(); + + print("result = $result"); + + return result; +} + typedef ReturnStruct1ByteIntType = Struct1ByteInt Function(Int8); // Global variables to be able to test inputs after callback returned. diff --git a/tests/ffi/function_callbacks_structs_by_value_native_callable_generated_test.dart b/tests/ffi/function_callbacks_structs_by_value_native_callable_generated_test.dart index bc275a5f5b1..123f1a5917a 100644 --- a/tests/ffi/function_callbacks_structs_by_value_native_callable_generated_test.dart +++ b/tests/ffi/function_callbacks_structs_by_value_native_callable_generated_test.dart @@ -620,6 +620,14 @@ final testCases = [ ), noChecks, ), + CallbackTest.withCheck( + "PassPointerStructInlineArrayVariable2", + NativeCallable.isolateLocal( + passPointerStructInlineArrayVariable2, + exceptionalReturn: 0, + ), + noChecks, + ), CallbackTest.withCheck( "ReturnStruct1ByteInt", NativeCallable.isolateLocal(returnStruct1ByteInt), @@ -8677,6 +8685,59 @@ int passPointerStructInlineArrayVariableAlign( return result; } +typedef PassPointerStructInlineArrayVariable2Type = + Int64 Function(Pointer); + +// Global variables to be able to test inputs after callback returned. +Pointer passPointerStructInlineArrayVariable2_a0 = + nullptr; + +// Result variable also global, so we can delete it after the callback. +int passPointerStructInlineArrayVariable2Result = 0; + +int passPointerStructInlineArrayVariable2CalculateResult() { + int result = 0; + + result += passPointerStructInlineArrayVariable2_a0.ref.a0; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[0]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[1]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[2]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[3]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[4]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[5]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[6]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[7]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[8]; + result += passPointerStructInlineArrayVariable2_a0.ref.a1[9]; + + passPointerStructInlineArrayVariable2Result = result; + + return result; +} + +/// Variable length array with variable dimension of 1. +int passPointerStructInlineArrayVariable2( + Pointer a0, +) { + print("passPointerStructInlineArrayVariable2(${a0})"); + + // Possibly throw. + if (a0.ref.a0 == 42 || a0.ref.a0 == 84) { + print("throwing!"); + throw Exception( + "PassPointerStructInlineArrayVariable2 throwing on purpose!", + ); + } + + passPointerStructInlineArrayVariable2_a0 = a0; + + final result = passPointerStructInlineArrayVariable2CalculateResult(); + + print("result = $result"); + + return result; +} + typedef ReturnStruct1ByteIntType = Struct1ByteInt Function(Int8); // Global variables to be able to test inputs after callback returned. diff --git a/tests/ffi/function_structs_by_value_generated_args_leaf_test.dart b/tests/ffi/function_structs_by_value_generated_args_leaf_test.dart index 7ce46f41301..a9b12160457 100644 --- a/tests/ffi/function_structs_by_value_generated_args_leaf_test.dart +++ b/tests/ffi/function_structs_by_value_generated_args_leaf_test.dart @@ -95,6 +95,7 @@ void main() { testPassPointerStruct12BytesHomogeneousInt32Leaf(); testPassPointerStructInlineArrayVariableLeaf(); testPassPointerStructInlineArrayVariableAlignLeaf(); + testPassPointerStructInlineArrayVariable2Leaf(); } } @@ -6149,3 +6150,36 @@ void testPassPointerStructInlineArrayVariableAlignLeaf() { calloc.free(a0); } + +final passPointerStructInlineArrayVariable2Leaf = ffiTestFunctions + .lookupFunction< + Int64 Function(Pointer), + int Function(Pointer) + >("PassPointerStructInlineArrayVariable2", isLeaf: true); + +/// Variable length array with variable dimension of 1. +void testPassPointerStructInlineArrayVariable2Leaf() { + final a0 = calloc.allocate( + sizeOf() + 9 * sizeOf(), + ); + + a0.ref.a0 = 1; + a0.ref.a1[0] = 2; + a0.ref.a1[1] = 3; + a0.ref.a1[2] = 4; + a0.ref.a1[3] = 5; + a0.ref.a1[4] = 6; + a0.ref.a1[5] = 7; + a0.ref.a1[6] = 8; + a0.ref.a1[7] = 9; + a0.ref.a1[8] = 10; + a0.ref.a1[9] = 11; + + final result = passPointerStructInlineArrayVariable2Leaf(a0); + + print("result = $result"); + + Expect.equals(66, result); + + calloc.free(a0); +} diff --git a/tests/ffi/function_structs_by_value_generated_args_native_leaf_test.dart b/tests/ffi/function_structs_by_value_generated_args_native_leaf_test.dart index 34747c6c946..7006127295e 100644 --- a/tests/ffi/function_structs_by_value_generated_args_native_leaf_test.dart +++ b/tests/ffi/function_structs_by_value_generated_args_native_leaf_test.dart @@ -98,6 +98,7 @@ void main() { testPassPointerStruct12BytesHomogeneousInt32NativeLeaf(); testPassPointerStructInlineArrayVariableNativeLeaf(); testPassPointerStructInlineArrayVariableAlignNativeLeaf(); + testPassPointerStructInlineArrayVariable2NativeLeaf(); } } @@ -6204,3 +6205,38 @@ void testPassPointerStructInlineArrayVariableAlignNativeLeaf() { calloc.free(a0); } + +@Native)>( + symbol: 'PassPointerStructInlineArrayVariable2', + isLeaf: true, +) +external int passPointerStructInlineArrayVariable2NativeLeaf( + Pointer a0, +); + +/// Variable length array with variable dimension of 1. +void testPassPointerStructInlineArrayVariable2NativeLeaf() { + final a0 = calloc.allocate( + sizeOf() + 9 * sizeOf(), + ); + + a0.ref.a0 = 1; + a0.ref.a1[0] = 2; + a0.ref.a1[1] = 3; + a0.ref.a1[2] = 4; + a0.ref.a1[3] = 5; + a0.ref.a1[4] = 6; + a0.ref.a1[5] = 7; + a0.ref.a1[6] = 8; + a0.ref.a1[7] = 9; + a0.ref.a1[8] = 10; + a0.ref.a1[9] = 11; + + final result = passPointerStructInlineArrayVariable2NativeLeaf(a0); + + print("result = $result"); + + Expect.equals(66, result); + + calloc.free(a0); +} diff --git a/tests/ffi/function_structs_by_value_generated_args_native_test.dart b/tests/ffi/function_structs_by_value_generated_args_native_test.dart index 49dfb401e96..866b849e84f 100644 --- a/tests/ffi/function_structs_by_value_generated_args_native_test.dart +++ b/tests/ffi/function_structs_by_value_generated_args_native_test.dart @@ -98,6 +98,7 @@ void main() { testPassPointerStruct12BytesHomogeneousInt32Native(); testPassPointerStructInlineArrayVariableNative(); testPassPointerStructInlineArrayVariableAlignNative(); + testPassPointerStructInlineArrayVariable2Native(); } } @@ -6163,3 +6164,37 @@ void testPassPointerStructInlineArrayVariableAlignNative() { calloc.free(a0); } + +@Native)>( + symbol: 'PassPointerStructInlineArrayVariable2', +) +external int passPointerStructInlineArrayVariable2Native( + Pointer a0, +); + +/// Variable length array with variable dimension of 1. +void testPassPointerStructInlineArrayVariable2Native() { + final a0 = calloc.allocate( + sizeOf() + 9 * sizeOf(), + ); + + a0.ref.a0 = 1; + a0.ref.a1[0] = 2; + a0.ref.a1[1] = 3; + a0.ref.a1[2] = 4; + a0.ref.a1[3] = 5; + a0.ref.a1[4] = 6; + a0.ref.a1[5] = 7; + a0.ref.a1[6] = 8; + a0.ref.a1[7] = 9; + a0.ref.a1[8] = 10; + a0.ref.a1[9] = 11; + + final result = passPointerStructInlineArrayVariable2Native(a0); + + print("result = $result"); + + Expect.equals(66, result); + + calloc.free(a0); +} diff --git a/tests/ffi/function_structs_by_value_generated_args_test.dart b/tests/ffi/function_structs_by_value_generated_args_test.dart index 9b4bc1e4171..5f1b4e7b266 100644 --- a/tests/ffi/function_structs_by_value_generated_args_test.dart +++ b/tests/ffi/function_structs_by_value_generated_args_test.dart @@ -95,6 +95,7 @@ void main() { testPassPointerStruct12BytesHomogeneousInt32(); testPassPointerStructInlineArrayVariable(); testPassPointerStructInlineArrayVariableAlign(); + testPassPointerStructInlineArrayVariable2(); } } @@ -6094,3 +6095,35 @@ void testPassPointerStructInlineArrayVariableAlign() { calloc.free(a0); } + +final passPointerStructInlineArrayVariable2 = ffiTestFunctions.lookupFunction< + Int64 Function(Pointer), + int Function(Pointer) +>("PassPointerStructInlineArrayVariable2"); + +/// Variable length array with variable dimension of 1. +void testPassPointerStructInlineArrayVariable2() { + final a0 = calloc.allocate( + sizeOf() + 9 * sizeOf(), + ); + + a0.ref.a0 = 1; + a0.ref.a1[0] = 2; + a0.ref.a1[1] = 3; + a0.ref.a1[2] = 4; + a0.ref.a1[3] = 5; + a0.ref.a1[4] = 6; + a0.ref.a1[5] = 7; + a0.ref.a1[6] = 8; + a0.ref.a1[7] = 9; + a0.ref.a1[8] = 10; + a0.ref.a1[9] = 11; + + final result = passPointerStructInlineArrayVariable2(a0); + + print("result = $result"); + + Expect.equals(66, result); + + calloc.free(a0); +} diff --git a/tests/ffi/function_structs_by_value_generated_compounds.dart b/tests/ffi/function_structs_by_value_generated_compounds.dart index 712ccffad77..6ea7f19f0e2 100644 --- a/tests/ffi/function_structs_by_value_generated_compounds.dart +++ b/tests/ffi/function_structs_by_value_generated_compounds.dart @@ -1305,3 +1305,33 @@ final class StructInlineArrayVariableAlign extends Struct { String toString() => "(${a0}, ${a1})"; } + +final class StructInlineArrayVariable2 extends Struct { + @Uint32() + external int a0; + + @Array.variableWithVariableDimension(1) + external Array a1; + + String toString() => "(${a0}, ${a1})"; +} + +final class StructInlineArrayVariableNested2 extends Struct { + @Uint32() + external int a0; + + @Array.variableWithVariableDimension(1, 2, 2) + external Array>> a1; + + String toString() => "(${a0}, ${a1})"; +} + +final class StructInlineArrayVariableNestedDeep2 extends Struct { + @Uint32() + external int a0; + + @Array.variableMulti(variableDimension: 1, [2, 2, 2, 2, 2, 2]) + external Array>>>>>> a1; + + String toString() => "(${a0}, ${a1})"; +} diff --git a/tests/ffi/function_structs_by_value_generated_compounds_sizeof_test.dart b/tests/ffi/function_structs_by_value_generated_compounds_sizeof_test.dart new file mode 100644 index 00000000000..294704811da --- /dev/null +++ b/tests/ffi/function_structs_by_value_generated_compounds_sizeof_test.dart @@ -0,0 +1,1239 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// +// This file has been automatically generated. Please do not edit it manually. +// Generated by tests/ffi/generator/structs_by_value_tests_generator.dart. +// +// SharedObjects=ffi_test_functions +// VMOptions= +// VMOptions=--deterministic --optimization-counter-threshold=90 +// VMOptions=--use-slow-path +// VMOptions=--use-slow-path --stacktrace-every=100 + +import 'dart:ffi'; + +import 'package:expect/expect.dart'; +// ignore: unused_import +import 'package:ffi/ffi.dart'; + +import 'dylib_utils.dart'; + +// Reuse the compound classes. +import 'function_structs_by_value_generated_compounds.dart'; + +final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions"); +void main() { + // Force dlopen so @Native lookups in DynamicLibrary.process() succeed. + dlopenGlobalPlatformSpecific('ffi_test_functions'); + + testSizeOfStruct1ByteBoolNativeLeaf(); + testSizeOfStruct1ByteIntNativeLeaf(); + testSizeOfStruct3BytesHomogeneousUint8NativeLeaf(); + testSizeOfStruct3BytesInt2ByteAlignedNativeLeaf(); + testSizeOfStruct4BytesHomogeneousInt16NativeLeaf(); + testSizeOfStruct4BytesFloatNativeLeaf(); + testSizeOfStruct7BytesHomogeneousUint8NativeLeaf(); + testSizeOfStruct7BytesInt4ByteAlignedNativeLeaf(); + testSizeOfStruct8BytesIntNativeLeaf(); + testSizeOfStruct8BytesHomogeneousFloatNativeLeaf(); + testSizeOfStruct8BytesFloatNativeLeaf(); + testSizeOfStruct8BytesMixedNativeLeaf(); + testSizeOfStruct9BytesHomogeneousUint8NativeLeaf(); + testSizeOfStruct9BytesInt4Or8ByteAlignedNativeLeaf(); + testSizeOfStruct10BytesHomogeneousBoolNativeLeaf(); + testSizeOfStruct12BytesHomogeneousFloatNativeLeaf(); + testSizeOfStruct12BytesHomogeneousInt32NativeLeaf(); + testSizeOfStruct16BytesHomogeneousFloatNativeLeaf(); + testSizeOfStruct16BytesMixedNativeLeaf(); + testSizeOfStruct16BytesMixed2NativeLeaf(); + testSizeOfStruct17BytesIntNativeLeaf(); + testSizeOfStruct19BytesHomogeneousUint8NativeLeaf(); + testSizeOfStruct20BytesHomogeneousInt32NativeLeaf(); + testSizeOfStruct20BytesHomogeneousFloatNativeLeaf(); + testSizeOfStruct32BytesHomogeneousDoubleNativeLeaf(); + testSizeOfStruct40BytesHomogeneousDoubleNativeLeaf(); + testSizeOfStruct1024BytesHomogeneousUint64NativeLeaf(); + testSizeOfStructAlignmentInt16NativeLeaf(); + testSizeOfStructAlignmentInt32NativeLeaf(); + testSizeOfStructAlignmentInt64NativeLeaf(); + testSizeOfStruct8BytesNestedIntNativeLeaf(); + testSizeOfStruct8BytesNestedFloatNativeLeaf(); + testSizeOfStruct8BytesNestedFloat2NativeLeaf(); + testSizeOfStruct8BytesNestedMixedNativeLeaf(); + testSizeOfStruct16BytesNestedIntNativeLeaf(); + testSizeOfStruct32BytesNestedIntNativeLeaf(); + testSizeOfStructNestedIntStructAlignmentInt16NativeLeaf(); + testSizeOfStructNestedIntStructAlignmentInt32NativeLeaf(); + testSizeOfStructNestedIntStructAlignmentInt64NativeLeaf(); + testSizeOfStructNestedIrregularBigNativeLeaf(); + testSizeOfStructNestedIrregularBiggerNativeLeaf(); + testSizeOfStructNestedIrregularEvenBiggerNativeLeaf(); + testSizeOfStruct8BytesInlineArrayIntNativeLeaf(); + testSizeOfStruct10BytesInlineArrayBoolNativeLeaf(); + testSizeOfStructInlineArrayIrregularNativeLeaf(); + testSizeOfStructInlineArray100BytesNativeLeaf(); + testSizeOfStructInlineArrayBigNativeLeaf(); + testSizeOfStructStruct16BytesHomogeneousFloat2NativeLeaf(); + testSizeOfStructStruct32BytesHomogeneousDouble2NativeLeaf(); + testSizeOfStructStruct16BytesMixed3NativeLeaf(); + testSizeOfStruct8BytesInlineArrayMultiDimensionalIntNativeLeaf(); + testSizeOfStruct32BytesInlineArrayMultiDimensionalIntNativeLeaf(); + testSizeOfStruct64BytesInlineArrayMultiDimensionalIntNativeLeaf(); + testSizeOfStruct4BytesInlineArrayMultiDimensionalIntNativeLeaf(); + testSizeOfStruct3BytesPackedIntNativeLeaf(); + testSizeOfStruct3BytesPackedIntMembersAlignedNativeLeaf(); + testSizeOfStruct5BytesPackedMixedNativeLeaf(); + testSizeOfStructNestedAlignmentStruct5BytesPackedMixedNativeLeaf(); + testSizeOfStruct6BytesInlineArrayIntNativeLeaf(); + testSizeOfStruct8BytesPackedIntNativeLeaf(); + testSizeOfStruct9BytesPackedMixedNativeLeaf(); + testSizeOfStruct15BytesInlineArrayMixedNativeLeaf(); + testSizeOfUnion4BytesMixedNativeLeaf(); + testSizeOfUnion8BytesNestedFloatNativeLeaf(); + testSizeOfUnion9BytesNestedIntNativeLeaf(); + testSizeOfUnion16BytesNestedInlineArrayFloatNativeLeaf(); + testSizeOfUnion16BytesNestedFloatNativeLeaf(); + testSizeOfStructInlineArrayIntNativeLeaf(); + testSizeOfStructInlineArrayVariableNativeLeaf(); + testSizeOfStructInlineArrayVariableNestedNativeLeaf(); + testSizeOfStructInlineArrayVariableNestedDeepNativeLeaf(); + testSizeOfStructInlineArrayVariableAlignNativeLeaf(); + testSizeOfStructInlineArrayVariable2NativeLeaf(); + testSizeOfStructInlineArrayVariableNested2NativeLeaf(); + testSizeOfStructInlineArrayVariableNestedDeep2NativeLeaf(); +} + +@Native(symbol: 'SizeOfStruct1ByteBool', isLeaf: true) +external int sizeOfStruct1ByteBoolNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct1ByteBool]. +void testSizeOfStruct1ByteBoolNativeLeaf() { + final result = sizeOfStruct1ByteBoolNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct1ByteInt', isLeaf: true) +external int sizeOfStruct1ByteIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct1ByteInt]. +void testSizeOfStruct1ByteIntNativeLeaf() { + final result = sizeOfStruct1ByteIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct3BytesHomogeneousUint8', + isLeaf: true, +) +external int sizeOfStruct3BytesHomogeneousUint8NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct3BytesHomogeneousUint8]. +void testSizeOfStruct3BytesHomogeneousUint8NativeLeaf() { + final result = sizeOfStruct3BytesHomogeneousUint8NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct3BytesInt2ByteAligned', + isLeaf: true, +) +external int sizeOfStruct3BytesInt2ByteAlignedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct3BytesInt2ByteAligned]. +void testSizeOfStruct3BytesInt2ByteAlignedNativeLeaf() { + final result = sizeOfStruct3BytesInt2ByteAlignedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct4BytesHomogeneousInt16', + isLeaf: true, +) +external int sizeOfStruct4BytesHomogeneousInt16NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct4BytesHomogeneousInt16]. +void testSizeOfStruct4BytesHomogeneousInt16NativeLeaf() { + final result = sizeOfStruct4BytesHomogeneousInt16NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct4BytesFloat', isLeaf: true) +external int sizeOfStruct4BytesFloatNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct4BytesFloat]. +void testSizeOfStruct4BytesFloatNativeLeaf() { + final result = sizeOfStruct4BytesFloatNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct7BytesHomogeneousUint8', + isLeaf: true, +) +external int sizeOfStruct7BytesHomogeneousUint8NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct7BytesHomogeneousUint8]. +void testSizeOfStruct7BytesHomogeneousUint8NativeLeaf() { + final result = sizeOfStruct7BytesHomogeneousUint8NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct7BytesInt4ByteAligned', + isLeaf: true, +) +external int sizeOfStruct7BytesInt4ByteAlignedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct7BytesInt4ByteAligned]. +void testSizeOfStruct7BytesInt4ByteAlignedNativeLeaf() { + final result = sizeOfStruct7BytesInt4ByteAlignedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct8BytesInt', isLeaf: true) +external int sizeOfStruct8BytesIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesInt]. +void testSizeOfStruct8BytesIntNativeLeaf() { + final result = sizeOfStruct8BytesIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct8BytesHomogeneousFloat', + isLeaf: true, +) +external int sizeOfStruct8BytesHomogeneousFloatNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesHomogeneousFloat]. +void testSizeOfStruct8BytesHomogeneousFloatNativeLeaf() { + final result = sizeOfStruct8BytesHomogeneousFloatNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct8BytesFloat', isLeaf: true) +external int sizeOfStruct8BytesFloatNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesFloat]. +void testSizeOfStruct8BytesFloatNativeLeaf() { + final result = sizeOfStruct8BytesFloatNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct8BytesMixed', isLeaf: true) +external int sizeOfStruct8BytesMixedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesMixed]. +void testSizeOfStruct8BytesMixedNativeLeaf() { + final result = sizeOfStruct8BytesMixedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct9BytesHomogeneousUint8', + isLeaf: true, +) +external int sizeOfStruct9BytesHomogeneousUint8NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct9BytesHomogeneousUint8]. +void testSizeOfStruct9BytesHomogeneousUint8NativeLeaf() { + final result = sizeOfStruct9BytesHomogeneousUint8NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct9BytesInt4Or8ByteAligned', + isLeaf: true, +) +external int sizeOfStruct9BytesInt4Or8ByteAlignedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct9BytesInt4Or8ByteAligned]. +void testSizeOfStruct9BytesInt4Or8ByteAlignedNativeLeaf() { + final result = sizeOfStruct9BytesInt4Or8ByteAlignedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct10BytesHomogeneousBool', + isLeaf: true, +) +external int sizeOfStruct10BytesHomogeneousBoolNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct10BytesHomogeneousBool]. +void testSizeOfStruct10BytesHomogeneousBoolNativeLeaf() { + final result = sizeOfStruct10BytesHomogeneousBoolNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct12BytesHomogeneousFloat', + isLeaf: true, +) +external int sizeOfStruct12BytesHomogeneousFloatNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct12BytesHomogeneousFloat]. +void testSizeOfStruct12BytesHomogeneousFloatNativeLeaf() { + final result = sizeOfStruct12BytesHomogeneousFloatNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct12BytesHomogeneousInt32', + isLeaf: true, +) +external int sizeOfStruct12BytesHomogeneousInt32NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct12BytesHomogeneousInt32]. +void testSizeOfStruct12BytesHomogeneousInt32NativeLeaf() { + final result = sizeOfStruct12BytesHomogeneousInt32NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct16BytesHomogeneousFloat', + isLeaf: true, +) +external int sizeOfStruct16BytesHomogeneousFloatNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct16BytesHomogeneousFloat]. +void testSizeOfStruct16BytesHomogeneousFloatNativeLeaf() { + final result = sizeOfStruct16BytesHomogeneousFloatNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct16BytesMixed', isLeaf: true) +external int sizeOfStruct16BytesMixedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct16BytesMixed]. +void testSizeOfStruct16BytesMixedNativeLeaf() { + final result = sizeOfStruct16BytesMixedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct16BytesMixed2', isLeaf: true) +external int sizeOfStruct16BytesMixed2NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct16BytesMixed2]. +void testSizeOfStruct16BytesMixed2NativeLeaf() { + final result = sizeOfStruct16BytesMixed2NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct17BytesInt', isLeaf: true) +external int sizeOfStruct17BytesIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct17BytesInt]. +void testSizeOfStruct17BytesIntNativeLeaf() { + final result = sizeOfStruct17BytesIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct19BytesHomogeneousUint8', + isLeaf: true, +) +external int sizeOfStruct19BytesHomogeneousUint8NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct19BytesHomogeneousUint8]. +void testSizeOfStruct19BytesHomogeneousUint8NativeLeaf() { + final result = sizeOfStruct19BytesHomogeneousUint8NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct20BytesHomogeneousInt32', + isLeaf: true, +) +external int sizeOfStruct20BytesHomogeneousInt32NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct20BytesHomogeneousInt32]. +void testSizeOfStruct20BytesHomogeneousInt32NativeLeaf() { + final result = sizeOfStruct20BytesHomogeneousInt32NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct20BytesHomogeneousFloat', + isLeaf: true, +) +external int sizeOfStruct20BytesHomogeneousFloatNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct20BytesHomogeneousFloat]. +void testSizeOfStruct20BytesHomogeneousFloatNativeLeaf() { + final result = sizeOfStruct20BytesHomogeneousFloatNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct32BytesHomogeneousDouble', + isLeaf: true, +) +external int sizeOfStruct32BytesHomogeneousDoubleNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct32BytesHomogeneousDouble]. +void testSizeOfStruct32BytesHomogeneousDoubleNativeLeaf() { + final result = sizeOfStruct32BytesHomogeneousDoubleNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct40BytesHomogeneousDouble', + isLeaf: true, +) +external int sizeOfStruct40BytesHomogeneousDoubleNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct40BytesHomogeneousDouble]. +void testSizeOfStruct40BytesHomogeneousDoubleNativeLeaf() { + final result = sizeOfStruct40BytesHomogeneousDoubleNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct1024BytesHomogeneousUint64', + isLeaf: true, +) +external int sizeOfStruct1024BytesHomogeneousUint64NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct1024BytesHomogeneousUint64]. +void testSizeOfStruct1024BytesHomogeneousUint64NativeLeaf() { + final result = sizeOfStruct1024BytesHomogeneousUint64NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStructAlignmentInt16', isLeaf: true) +external int sizeOfStructAlignmentInt16NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructAlignmentInt16]. +void testSizeOfStructAlignmentInt16NativeLeaf() { + final result = sizeOfStructAlignmentInt16NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStructAlignmentInt32', isLeaf: true) +external int sizeOfStructAlignmentInt32NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructAlignmentInt32]. +void testSizeOfStructAlignmentInt32NativeLeaf() { + final result = sizeOfStructAlignmentInt32NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStructAlignmentInt64', isLeaf: true) +external int sizeOfStructAlignmentInt64NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructAlignmentInt64]. +void testSizeOfStructAlignmentInt64NativeLeaf() { + final result = sizeOfStructAlignmentInt64NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct8BytesNestedInt', isLeaf: true) +external int sizeOfStruct8BytesNestedIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesNestedInt]. +void testSizeOfStruct8BytesNestedIntNativeLeaf() { + final result = sizeOfStruct8BytesNestedIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct8BytesNestedFloat', + isLeaf: true, +) +external int sizeOfStruct8BytesNestedFloatNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesNestedFloat]. +void testSizeOfStruct8BytesNestedFloatNativeLeaf() { + final result = sizeOfStruct8BytesNestedFloatNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct8BytesNestedFloat2', + isLeaf: true, +) +external int sizeOfStruct8BytesNestedFloat2NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesNestedFloat2]. +void testSizeOfStruct8BytesNestedFloat2NativeLeaf() { + final result = sizeOfStruct8BytesNestedFloat2NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct8BytesNestedMixed', + isLeaf: true, +) +external int sizeOfStruct8BytesNestedMixedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesNestedMixed]. +void testSizeOfStruct8BytesNestedMixedNativeLeaf() { + final result = sizeOfStruct8BytesNestedMixedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct16BytesNestedInt', isLeaf: true) +external int sizeOfStruct16BytesNestedIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct16BytesNestedInt]. +void testSizeOfStruct16BytesNestedIntNativeLeaf() { + final result = sizeOfStruct16BytesNestedIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct32BytesNestedInt', isLeaf: true) +external int sizeOfStruct32BytesNestedIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct32BytesNestedInt]. +void testSizeOfStruct32BytesNestedIntNativeLeaf() { + final result = sizeOfStruct32BytesNestedIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructNestedIntStructAlignmentInt16', + isLeaf: true, +) +external int sizeOfStructNestedIntStructAlignmentInt16NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructNestedIntStructAlignmentInt16]. +void testSizeOfStructNestedIntStructAlignmentInt16NativeLeaf() { + final result = sizeOfStructNestedIntStructAlignmentInt16NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructNestedIntStructAlignmentInt32', + isLeaf: true, +) +external int sizeOfStructNestedIntStructAlignmentInt32NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructNestedIntStructAlignmentInt32]. +void testSizeOfStructNestedIntStructAlignmentInt32NativeLeaf() { + final result = sizeOfStructNestedIntStructAlignmentInt32NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructNestedIntStructAlignmentInt64', + isLeaf: true, +) +external int sizeOfStructNestedIntStructAlignmentInt64NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructNestedIntStructAlignmentInt64]. +void testSizeOfStructNestedIntStructAlignmentInt64NativeLeaf() { + final result = sizeOfStructNestedIntStructAlignmentInt64NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructNestedIrregularBig', + isLeaf: true, +) +external int sizeOfStructNestedIrregularBigNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructNestedIrregularBig]. +void testSizeOfStructNestedIrregularBigNativeLeaf() { + final result = sizeOfStructNestedIrregularBigNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructNestedIrregularBigger', + isLeaf: true, +) +external int sizeOfStructNestedIrregularBiggerNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructNestedIrregularBigger]. +void testSizeOfStructNestedIrregularBiggerNativeLeaf() { + final result = sizeOfStructNestedIrregularBiggerNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructNestedIrregularEvenBigger', + isLeaf: true, +) +external int sizeOfStructNestedIrregularEvenBiggerNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructNestedIrregularEvenBigger]. +void testSizeOfStructNestedIrregularEvenBiggerNativeLeaf() { + final result = sizeOfStructNestedIrregularEvenBiggerNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct8BytesInlineArrayInt', + isLeaf: true, +) +external int sizeOfStruct8BytesInlineArrayIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesInlineArrayInt]. +void testSizeOfStruct8BytesInlineArrayIntNativeLeaf() { + final result = sizeOfStruct8BytesInlineArrayIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct10BytesInlineArrayBool', + isLeaf: true, +) +external int sizeOfStruct10BytesInlineArrayBoolNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct10BytesInlineArrayBool]. +void testSizeOfStruct10BytesInlineArrayBoolNativeLeaf() { + final result = sizeOfStruct10BytesInlineArrayBoolNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructInlineArrayIrregular', + isLeaf: true, +) +external int sizeOfStructInlineArrayIrregularNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArrayIrregular]. +void testSizeOfStructInlineArrayIrregularNativeLeaf() { + final result = sizeOfStructInlineArrayIrregularNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructInlineArray100Bytes', + isLeaf: true, +) +external int sizeOfStructInlineArray100BytesNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArray100Bytes]. +void testSizeOfStructInlineArray100BytesNativeLeaf() { + final result = sizeOfStructInlineArray100BytesNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStructInlineArrayBig', isLeaf: true) +external int sizeOfStructInlineArrayBigNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArrayBig]. +void testSizeOfStructInlineArrayBigNativeLeaf() { + final result = sizeOfStructInlineArrayBigNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructStruct16BytesHomogeneousFloat2', + isLeaf: true, +) +external int sizeOfStructStruct16BytesHomogeneousFloat2NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructStruct16BytesHomogeneousFloat2]. +void testSizeOfStructStruct16BytesHomogeneousFloat2NativeLeaf() { + final result = sizeOfStructStruct16BytesHomogeneousFloat2NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructStruct32BytesHomogeneousDouble2', + isLeaf: true, +) +external int sizeOfStructStruct32BytesHomogeneousDouble2NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructStruct32BytesHomogeneousDouble2]. +void testSizeOfStructStruct32BytesHomogeneousDouble2NativeLeaf() { + final result = sizeOfStructStruct32BytesHomogeneousDouble2NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructStruct16BytesMixed3', + isLeaf: true, +) +external int sizeOfStructStruct16BytesMixed3NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructStruct16BytesMixed3]. +void testSizeOfStructStruct16BytesMixed3NativeLeaf() { + final result = sizeOfStructStruct16BytesMixed3NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct8BytesInlineArrayMultiDimensionalInt', + isLeaf: true, +) +external int sizeOfStruct8BytesInlineArrayMultiDimensionalIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesInlineArrayMultiDimensionalInt]. +void testSizeOfStruct8BytesInlineArrayMultiDimensionalIntNativeLeaf() { + final result = sizeOfStruct8BytesInlineArrayMultiDimensionalIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct32BytesInlineArrayMultiDimensionalInt', + isLeaf: true, +) +external int sizeOfStruct32BytesInlineArrayMultiDimensionalIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct32BytesInlineArrayMultiDimensionalInt]. +void testSizeOfStruct32BytesInlineArrayMultiDimensionalIntNativeLeaf() { + final result = sizeOfStruct32BytesInlineArrayMultiDimensionalIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct64BytesInlineArrayMultiDimensionalInt', + isLeaf: true, +) +external int sizeOfStruct64BytesInlineArrayMultiDimensionalIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct64BytesInlineArrayMultiDimensionalInt]. +void testSizeOfStruct64BytesInlineArrayMultiDimensionalIntNativeLeaf() { + final result = sizeOfStruct64BytesInlineArrayMultiDimensionalIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct4BytesInlineArrayMultiDimensionalInt', + isLeaf: true, +) +external int sizeOfStruct4BytesInlineArrayMultiDimensionalIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct4BytesInlineArrayMultiDimensionalInt]. +void testSizeOfStruct4BytesInlineArrayMultiDimensionalIntNativeLeaf() { + final result = sizeOfStruct4BytesInlineArrayMultiDimensionalIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct3BytesPackedInt', isLeaf: true) +external int sizeOfStruct3BytesPackedIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct3BytesPackedInt]. +void testSizeOfStruct3BytesPackedIntNativeLeaf() { + final result = sizeOfStruct3BytesPackedIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct3BytesPackedIntMembersAligned', + isLeaf: true, +) +external int sizeOfStruct3BytesPackedIntMembersAlignedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct3BytesPackedIntMembersAligned]. +void testSizeOfStruct3BytesPackedIntMembersAlignedNativeLeaf() { + final result = sizeOfStruct3BytesPackedIntMembersAlignedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct5BytesPackedMixed', + isLeaf: true, +) +external int sizeOfStruct5BytesPackedMixedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct5BytesPackedMixed]. +void testSizeOfStruct5BytesPackedMixedNativeLeaf() { + final result = sizeOfStruct5BytesPackedMixedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructNestedAlignmentStruct5BytesPackedMixed', + isLeaf: true, +) +external int sizeOfStructNestedAlignmentStruct5BytesPackedMixedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructNestedAlignmentStruct5BytesPackedMixed]. +void testSizeOfStructNestedAlignmentStruct5BytesPackedMixedNativeLeaf() { + final result = sizeOfStructNestedAlignmentStruct5BytesPackedMixedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct6BytesInlineArrayInt', + isLeaf: true, +) +external int sizeOfStruct6BytesInlineArrayIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct6BytesInlineArrayInt]. +void testSizeOfStruct6BytesInlineArrayIntNativeLeaf() { + final result = sizeOfStruct6BytesInlineArrayIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStruct8BytesPackedInt', isLeaf: true) +external int sizeOfStruct8BytesPackedIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct8BytesPackedInt]. +void testSizeOfStruct8BytesPackedIntNativeLeaf() { + final result = sizeOfStruct8BytesPackedIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct9BytesPackedMixed', + isLeaf: true, +) +external int sizeOfStruct9BytesPackedMixedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct9BytesPackedMixed]. +void testSizeOfStruct9BytesPackedMixedNativeLeaf() { + final result = sizeOfStruct9BytesPackedMixedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStruct15BytesInlineArrayMixed', + isLeaf: true, +) +external int sizeOfStruct15BytesInlineArrayMixedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Struct15BytesInlineArrayMixed]. +void testSizeOfStruct15BytesInlineArrayMixedNativeLeaf() { + final result = sizeOfStruct15BytesInlineArrayMixedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfUnion4BytesMixed', isLeaf: true) +external int sizeOfUnion4BytesMixedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Union4BytesMixed]. +void testSizeOfUnion4BytesMixedNativeLeaf() { + final result = sizeOfUnion4BytesMixedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfUnion8BytesNestedFloat', isLeaf: true) +external int sizeOfUnion8BytesNestedFloatNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Union8BytesNestedFloat]. +void testSizeOfUnion8BytesNestedFloatNativeLeaf() { + final result = sizeOfUnion8BytesNestedFloatNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfUnion9BytesNestedInt', isLeaf: true) +external int sizeOfUnion9BytesNestedIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Union9BytesNestedInt]. +void testSizeOfUnion9BytesNestedIntNativeLeaf() { + final result = sizeOfUnion9BytesNestedIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfUnion16BytesNestedInlineArrayFloat', + isLeaf: true, +) +external int sizeOfUnion16BytesNestedInlineArrayFloatNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Union16BytesNestedInlineArrayFloat]. +void testSizeOfUnion16BytesNestedInlineArrayFloatNativeLeaf() { + final result = sizeOfUnion16BytesNestedInlineArrayFloatNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfUnion16BytesNestedFloat', + isLeaf: true, +) +external int sizeOfUnion16BytesNestedFloatNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [Union16BytesNestedFloat]. +void testSizeOfUnion16BytesNestedFloatNativeLeaf() { + final result = sizeOfUnion16BytesNestedFloatNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native(symbol: 'SizeOfStructInlineArrayInt', isLeaf: true) +external int sizeOfStructInlineArrayIntNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArrayInt]. +void testSizeOfStructInlineArrayIntNativeLeaf() { + final result = sizeOfStructInlineArrayIntNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructInlineArrayVariable', + isLeaf: true, +) +external int sizeOfStructInlineArrayVariableNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArrayVariable]. +void testSizeOfStructInlineArrayVariableNativeLeaf() { + final result = sizeOfStructInlineArrayVariableNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructInlineArrayVariableNested', + isLeaf: true, +) +external int sizeOfStructInlineArrayVariableNestedNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArrayVariableNested]. +void testSizeOfStructInlineArrayVariableNestedNativeLeaf() { + final result = sizeOfStructInlineArrayVariableNestedNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructInlineArrayVariableNestedDeep', + isLeaf: true, +) +external int sizeOfStructInlineArrayVariableNestedDeepNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArrayVariableNestedDeep]. +void testSizeOfStructInlineArrayVariableNestedDeepNativeLeaf() { + final result = sizeOfStructInlineArrayVariableNestedDeepNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructInlineArrayVariableAlign', + isLeaf: true, +) +external int sizeOfStructInlineArrayVariableAlignNativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArrayVariableAlign]. +void testSizeOfStructInlineArrayVariableAlignNativeLeaf() { + final result = sizeOfStructInlineArrayVariableAlignNativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructInlineArrayVariable2', + isLeaf: true, +) +external int sizeOfStructInlineArrayVariable2NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArrayVariable2]. +void testSizeOfStructInlineArrayVariable2NativeLeaf() { + final result = sizeOfStructInlineArrayVariable2NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructInlineArrayVariableNested2', + isLeaf: true, +) +external int sizeOfStructInlineArrayVariableNested2NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArrayVariableNested2]. +void testSizeOfStructInlineArrayVariableNested2NativeLeaf() { + final result = sizeOfStructInlineArrayVariableNested2NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} + +@Native( + symbol: 'SizeOfStructInlineArrayVariableNestedDeep2', + isLeaf: true, +) +external int sizeOfStructInlineArrayVariableNestedDeep2NativeLeaf(); + +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [StructInlineArrayVariableNestedDeep2]. +void testSizeOfStructInlineArrayVariableNestedDeep2NativeLeaf() { + final result = sizeOfStructInlineArrayVariableNestedDeep2NativeLeaf(); + + print("result = $result"); + + Expect.equals(sizeOf(), result); +} diff --git a/tests/ffi/generator/c_types.dart b/tests/ffi/generator/c_types.dart index c08008d4b0b..21e38c44b36 100644 --- a/tests/ffi/generator/c_types.dart +++ b/tests/ffi/generator/c_types.dart @@ -245,8 +245,7 @@ class Member { String get cStructField { String postFix = ""; - if (type is FixedLengthArrayType) { - final dimensions = (type as FixedLengthArrayType).dimensions; + if (type case FixedLengthArrayType(:final dimensions)) { postFix = "[${dimensions.map((d) => d == 0 ? '' : d.toString()).join("][")}]"; } @@ -488,24 +487,35 @@ class FixedLengthArrayType extends CType { } class VariableLengthArrayType extends FixedLengthArrayType { - VariableLengthArrayType(CType elementType) : super(elementType, 0); + VariableLengthArrayType(CType elementType, {this.variableDimension = 0}) + : super(elementType, variableDimension); factory VariableLengthArrayType.multi( CType elementType, - List fixedDimensions, - ) { + List fixedDimensions, { + int variableDimension = 0, + }) { final nestedArray = FixedLengthArrayType.multi( elementType, fixedDimensions, ); - return VariableLengthArrayType(nestedArray); + return VariableLengthArrayType( + nestedArray, + variableDimension: variableDimension, + ); } + final int variableDimension; + String get dartStructFieldAnnotation { if (dimensions.length > 5) { - return "@Array.variableMulti([${dimensions.skip(1).join(", ")}])"; + return variableDimension > 0 + ? "@Array.variableMulti(variableDimension: $variableDimension, [${dimensions.skip(1).join(", ")}])" + : "@Array.variableMulti([${dimensions.skip(1).join(", ")}])"; } - return "@Array.variable(${dimensions.skip(1).join(", ")})"; + return variableDimension > 0 + ? "@Array.variableWithVariableDimension($variableDimension, ${dimensions.skip(1).join(", ")})" + : "@Array.variable(${dimensions.skip(1).join(", ")})"; } } @@ -614,6 +624,8 @@ class FunctionType extends CType { } } else if (returnValue is UnionType && arguments.length == 1) { return "Return${returnValue.dartCType}"; + } else if (returnValue == uint64 && arguments.isEmpty) { + result = "SizeOf${reason}"; } else { result = "Uncategorized"; } diff --git a/tests/ffi/generator/structs_by_value_tests_configuration.dart b/tests/ffi/generator/structs_by_value_tests_configuration.dart index 15b2ede7a55..59b7937f394 100644 --- a/tests/ffi/generator/structs_by_value_tests_configuration.dart +++ b/tests/ffi/generator/structs_by_value_tests_configuration.dart @@ -11,6 +11,12 @@ final functions = [ ...functionsReturnArgument, ]; +/// Functions that return the size of each compound. +final functionsCompoundSizeOf = [ + for (final compound in compounds) + FunctionType(const [], uint64, compound.name), +]; + /// Functions that pass structs as arguments. final functionsStructArguments = [ FunctionType(List.filled(10, struct1byteInt), int64, """ @@ -475,6 +481,12 @@ Variable length array""", Variable length array with variable length element having more alignment than the rest of the struct.""", ), + FunctionType( + [PointerType(structVariableLengthArray5)], + int64, + """ +Variable length array with variable dimension of 1.""", + ), ]; /// Functions that return a struct by value. @@ -748,6 +760,9 @@ final compounds = [ structVariableLengthArray2, structVariableLengthArray3, structVariableLengthArray4, + structVariableLengthArray5, + structVariableLengthArray6, + structVariableLengthArray7, ]; /// Function signatures for variadic argument tests. @@ -1160,3 +1175,25 @@ final structVariableLengthArray4 = StructType.override([ uint8, VariableLengthArrayType(uint32), ], "InlineArrayVariableAlign"); + +final structVariableLengthArray5 = StructType.override([ + uint32, + VariableLengthArrayType(uint8, variableDimension: 1), +], "InlineArrayVariable2"); + +final structVariableLengthArray6 = StructType.override([ + uint32, + VariableLengthArrayType.multi(uint8, [2, 2], variableDimension: 1), +], "InlineArrayVariableNested2"); + +final structVariableLengthArray7 = StructType.override([ + uint32, + VariableLengthArrayType.multi(uint8, [ + 2, + 2, + 2, + 2, + 2, + 2, + ], variableDimension: 1), +], "InlineArrayVariableNestedDeep2"); diff --git a/tests/ffi/generator/structs_by_value_tests_generator.dart b/tests/ffi/generator/structs_by_value_tests_generator.dart index f89ed536dd7..026ad2b68d0 100644 --- a/tests/ffi/generator/structs_by_value_tests_generator.dart +++ b/tests/ffi/generator/structs_by_value_tests_generator.dart @@ -9,9 +9,13 @@ import 'c_types.dart'; import 'structs_by_value_tests_configuration.dart'; import 'utils.dart'; -/// The test type determines how to convert the arguments into return values -/// such that the caller knows what to check. +/// Defines the type of test, detailing how arguments are handled and return +/// values are generated for validation. enum TestType { + /// Tested by comparing the sizes of compounds using Dart's `sizeOf` and C++'s + /// `sizeof`. + compoundSizeOf, + /// Tested by getting all the individual fields out of the structs and /// summing their values. structArguments, @@ -41,6 +45,9 @@ extension on FunctionType { return TestType.structReturn; } } + if (returnValue == uint64 && arguments.isEmpty) { + return TestType.compoundSizeOf; + } // No structs, sum the arguments as well. return TestType.structArguments; @@ -344,8 +351,11 @@ extension on CType { case StructType _: final lastMember = pointerTo.memberTypes.last; final String extraBytes = switch (lastMember) { - VariableLengthArrayType _ => - '+ $_variableLengthLength * sizeOf<${lastMember.elementType.dartCType}>()', + VariableLengthArrayType(:final variableDimension) => + variableDimension > 0 + ? '+ ${_variableLengthLength - variableDimension} * sizeOf<${lastMember.elementType.dartCType}>()' + : '+ $_variableLengthLength * sizeOf<${lastMember.elementType.dartCType}>()', + _ => '', }; return ''' @@ -753,6 +763,13 @@ extension on FunctionType { String expects; switch (testType) { + case TestType.compoundSizeOf: + // Check against sizeOf. + expects = returnValue.dartExpectsStatements( + "sizeOf<$reason>()", + "result", + ); + break; case TestType.structArguments: // Check against sum value. final expectedResult = a.sumValue(returnValue as FundamentalType); @@ -772,6 +789,12 @@ extension on FunctionType { var namePostfix = isNative ? "Native" : ""; namePostfix += isLeaf ? "Leaf" : ""; + final docs = + testType == TestType.compoundSizeOf + ? ''' +/// Tests that the Dart [sizeOf] returns the same value as the C++ `sizeof` for +/// [$reason].''' + : reason.makeDartDocComment(); return """ ${isNative ? ''' @@ -782,7 +805,7 @@ final $dartName$namePostfix = ffiTestFunctions.lookupFunction<$dartCType, $dartType>( "$cName"${isLeaf ? ", isLeaf:true" : ""}); '''} -${reason.makeDartDocComment()} +$docs void $dartTestName$namePostfix() { ${arguments.dartAllocateStatements()} ${assignValues} @@ -817,6 +840,8 @@ ${assignValues} } switch (testType) { + case TestType.compoundSizeOf: + throw UnsupportedError("Unsupported test type: $testType"); case TestType.structArguments: // Sum all input values. @@ -868,6 +893,8 @@ ${arguments.addToResultStatements(true, '${dartName}_')} String afterCallbackExpects = ""; String afterCallbackFrees = ""; switch (testType) { + case TestType.compoundSizeOf: + throw UnsupportedError("Unsupported test type: $testType"); case TestType.structArguments: // Check that the input structs are still available. // Check against sum value. @@ -1043,6 +1070,11 @@ Future ${dartName}AfterCallback() async { returnStatement = 'return result % 2 != 0;'; } switch (testType) { + case TestType.compoundSizeOf: + body = """ + $returnValueType result = sizeof($reason); + """; + break; case TestType.structArguments: body = """ $returnValueType result = 0; @@ -1085,9 +1117,12 @@ $varArgUnpackArguments """; } + final docs = + testType == TestType.compoundSizeOf + ? "// Used for testing the size of $reason." + : "// Used for testing structs and unions by value.\n${reason.makeCComment()}"; return """ -// Used for testing structs and unions by value. -${reason.makeCComment()} +$docs DART_EXPORT ${returnValue.cType} $cName($argumentString) { $varArgsUnpack @@ -1120,6 +1155,8 @@ $varArgsUnpack String expects = ""; String expectsZero = ""; switch (testType) { + case TestType.compoundSizeOf: + throw UnsupportedError("Unsupported test type: $testType"); case TestType.structArguments: // Check against sum value. final returnValue_ = returnValue as FundamentalType; @@ -1254,6 +1291,38 @@ Future writeDartCompounds() async { await runProcess(Platform.resolvedExecutable, ["format", path]); } +String compoundsSizeOfTestPath() => + Platform.script + .resolve( + "../../ffi/function_structs_by_value_generated_compounds_sizeof_test.dart", + ) + .toFilePath(); + +Future writeDartCompoundsSizeOfTest(List functions) async { + final StringBuffer buffer = StringBuffer(); + buffer.write(headerDartCallTest(copyrightYear: 2024)); + + final forceDlOpen = ''' + // Force dlopen so @Native lookups in DynamicLibrary.process() succeed. + dlopenGlobalPlatformSpecific('ffi_test_functions'); +'''; + + buffer.write(""" +void main() { +$forceDlOpen + ${functions.map((e) => "${e.dartTestName}NativeLeaf();").join("\n ")} +} +"""); + + buffer.writeAll( + functions.map((e) => e.dartCallCode(isLeaf: true, isNative: true)), + ); + + final path = compoundsSizeOfTestPath(); + await File(path).writeAsString(buffer.toString()); + await runProcess(Platform.resolvedExecutable, ["format", path]); +} + headerDartCallTest({required int copyrightYear, String vmFlags = ''}) { if (vmFlags.length != 0 && !vmFlags.endsWith(' ')) { vmFlags += ' '; @@ -1403,7 +1472,7 @@ Future writeDartCallbackTest( buffer.write(""" final testCases = [ - ${functions.map((e) => e.dartCallbackTestConstructor(isNativeCallable: isNativeCallable)).join("\n")} + ${functions.map((e) => e.dartCallbackTestConstructor(isNativeCallable: isNativeCallable)).join()} ]; """); @@ -1482,9 +1551,13 @@ Future writeDartNativeCallableListenerTest( if (isAsync) { functions = functions.where((f) => !f.arguments.containsPointers).toList(); } - final constructors = functions - .map((e) => e.dartNativeCallableListenerTestConstructor(isAsync: isAsync)) - .join("\n"); + final constructors = + functions + .map( + (e) => + e.dartNativeCallableListenerTestConstructor(isAsync: isAsync), + ) + .join(); buffer.write(""" final testCases = [ @@ -1515,6 +1588,7 @@ Future writeC() async { buffer.write(headerC(copyrightYear: 2020, generatorPath: generatorPath)); buffer.writeAll(compounds.map((e) => e.cDefinition)); + buffer.writeAll(functionsCompoundSizeOf.map((e) => e.cCallCode)); buffer.writeAll(functions.map((e) => e.cCallCode)); buffer.writeAll(functions.map((e) => e.cCallbackCode)); buffer.writeAll(functions.map((e) => e.cAsyncCallbackCode)); @@ -1563,6 +1637,7 @@ void main(List arguments) async { await Future.wait([ writeDartCompounds(), + writeDartCompoundsSizeOfTest(functionsCompoundSizeOf), for (bool isLeaf in [false, true]) ...[ for (bool isNative in [false, true]) ...[ writeDartCallTest( diff --git a/tests/ffi/inline_array_variable_length_test.dart b/tests/ffi/inline_array_variable_length_test.dart index ffe96943699..0d3ca5efea8 100644 --- a/tests/ffi/inline_array_variable_length_test.dart +++ b/tests/ffi/inline_array_variable_length_test.dart @@ -16,6 +16,9 @@ void main() { testInlineArray(); testInlineArrayNested(); testInlineArrayNestedDeep(); + testInlineArray2(); + testInlineArrayNested2(); + testInlineArrayNestedDeep2(); testSizeOf(); } @@ -79,6 +82,67 @@ void testInlineArrayNestedDeep() { Expect.equals(45, sum); } +void testInlineArray2() { + const length = 10; + final lengthInBytes = + sizeOf() + sizeOf() * (length - 1); + final pointer = calloc.allocate(lengthInBytes); + pointer.ref.a0 = length; + final struct = pointer.ref; + for (int i = 0; i < length; i++) { + struct.a1[i] = i; + } + var sum = 0; + for (int i = 0; i < length; i++) { + sum += struct.a1[i]; + } + calloc.free(pointer); + Expect.equals(45, sum); +} + +void testInlineArrayNested2() { + const length = 10; + + final lengthInBytes = + sizeOf() + + sizeOf() * (length - 1) * 2 * 2; + final pointer = calloc.allocate( + lengthInBytes, + ); + pointer.ref.a0 = length; + final struct = pointer.ref; + for (int i = 0; i < length; i++) { + struct.a1[i][0][0] = i; + } + var sum = 0; + for (int i = 0; i < length; i++) { + sum += struct.a1[i][0][0]; + } + calloc.free(pointer); + Expect.equals(45, sum); +} + +void testInlineArrayNestedDeep2() { + const length = 10; + final lengthInBytes = + sizeOf() + + sizeOf() * (length - 1) * 2 * 2 * 2 * 2 * 2 * 2; + final pointer = calloc.allocate( + lengthInBytes, + ); + pointer.ref.a0 = length; + final struct = pointer.ref; + for (int i = 0; i < length; i++) { + struct.a1[i][0][0][1][1][0][0] = i; + } + var sum = 0; + for (int i = 0; i < length; i++) { + sum += struct.a1[i][0][0][1][1][0][0]; + } + calloc.free(pointer); + Expect.equals(45, sum); +} + final class Foo extends Struct { @Int8() external int field0; @@ -88,11 +152,56 @@ final class Foo2 extends Struct { @Int8() external int field0; - @Array.variable() + @Array.variable() external Array field1; } +final class Foo3 extends Struct { + @Int8() + external int field0; + + @Array.variableMulti([2, 2]) + external Array>> field1; +} + +final class Foo4 extends Struct { + @Int8() + external int field0; + + @Array.variableWithVariableDimension(0) + external Array field1; +} + +final class Foo5 extends Struct { + @Int8() + external int field0; + + @Array.variableWithVariableDimension(1) + external Array field1; +} + +final class Foo6 extends Struct { + @Int8() + external int field0; + + @Array.variableMulti(variableDimension: 0, [2, 2]) + external Array>> field1; +} + +final class Foo7 extends Struct { + @Int8() + external int field0; + + @Array.variableMulti(variableDimension: 1, [2, 2]) + external Array>> field1; +} + void testSizeOf() { Expect.equals(1, sizeOf()); Expect.equals(4, sizeOf()); + Expect.equals(4, sizeOf()); + Expect.equals(4, sizeOf()); + Expect.equals(8, sizeOf()); + Expect.equals(4, sizeOf()); + Expect.equals(20, sizeOf()); } diff --git a/tests/ffi/native_callables_sync_structs_by_value_generated_test.dart b/tests/ffi/native_callables_sync_structs_by_value_generated_test.dart index 19ab3469507..67fcd843e95 100644 --- a/tests/ffi/native_callables_sync_structs_by_value_generated_test.dart +++ b/tests/ffi/native_callables_sync_structs_by_value_generated_test.dart @@ -517,6 +517,13 @@ final testCases = [ ), noChecksAsync, ), + AsyncCallbackTest( + "PassPointerStructInlineArrayVariable2", + Pointer.fromFunction( + passPointerStructInlineArrayVariable2, + ), + noChecksAsync, + ), AsyncCallbackTest( "ReturnStruct1ByteInt", Pointer.fromFunction(returnStruct1ByteInt), @@ -5696,6 +5703,42 @@ Future passPointerStructInlineArrayVariableAlignAfterCallback() async { Expect.approxEquals(66, result); } +typedef PassPointerStructInlineArrayVariable2Type = + Void Function(Pointer); + +// Global variable that stores the result. +final PassPointerStructInlineArrayVariable2Result = Completer(); + +/// Variable length array with variable dimension of 1. +void passPointerStructInlineArrayVariable2( + Pointer a0, +) { + print("passPointerStructInlineArrayVariable2(${a0})"); + + double result = 0; + + result += a0.ref.a0; + result += a0.ref.a1[0]; + result += a0.ref.a1[1]; + result += a0.ref.a1[2]; + result += a0.ref.a1[3]; + result += a0.ref.a1[4]; + result += a0.ref.a1[5]; + result += a0.ref.a1[6]; + result += a0.ref.a1[7]; + result += a0.ref.a1[8]; + result += a0.ref.a1[9]; + + print("result = $result"); + PassPointerStructInlineArrayVariable2Result.complete(result); +} + +Future passPointerStructInlineArrayVariable2AfterCallback() async { + final result = await PassPointerStructInlineArrayVariable2Result.future; + print("after callback result = $result"); + Expect.approxEquals(66, result); +} + typedef ReturnStruct1ByteIntType = Void Function(Int8); // Global variable that stores the result. diff --git a/tests/ffi/static_checks/vmspecific_static_checks_array_test.dart b/tests/ffi/static_checks/vmspecific_static_checks_array_test.dart index dccd7f249f6..59490f144c8 100644 --- a/tests/ffi/static_checks/vmspecific_static_checks_array_test.dart +++ b/tests/ffi/static_checks/vmspecific_static_checks_array_test.dart @@ -121,3 +121,41 @@ final class TestStruct12 extends Struct { bool get a1 => true; set a1(bool value) {} } + +final class TestStruct13 extends Struct { + @Array.variableWithVariableDimension(-1) + // ^^ + // [analyzer] COMPILE_TIME_ERROR.NEGATIVE_VARIABLE_DIMENSION + external Array a0; + // ^^ + // [cfe] The variable dimension of a variable-length array must be non-negative. +} + +final class TestStruct14 extends Struct { + @Array.variableWithVariableDimension(0) + external Array a0; +} + +final class TestStruct15 extends Struct { + @Array.variableWithVariableDimension(1) + external Array a0; +} + +final class TestStruct16 extends Struct { + @Array.variableMulti(variableDimension: -1, [1, 2]) + // ^^ + // [analyzer] COMPILE_TIME_ERROR.NEGATIVE_VARIABLE_DIMENSION + external Array>> a0; + // ^^ + // [cfe] The variable dimension of a variable-length array must be non-negative. +} + +final class TestStruct17 extends Struct { + @Array.variableMulti(variableDimension: 0, [1, 2]) + external Array>> a0; +} + +final class TestStruct18 extends Struct { + @Array.variableMulti(variableDimension: 1, [1, 2]) + external Array>> a0; +}