[vm/ffi] Variable length inline arrays
Adds a new `@Array.variable()` to specify that the last element of structs is a variable length inline array. This CL does not add any checks for passing structs with variable length inline arrays by value or directly calling them with `AllocatorAlloc.call`. Instead, the implementation defaults to what C does, allocate as if there are 0 elements in the variable length inline array. TEST=tests/ffi/* CoreLibraryReviewExempt: VM only Closes: https://github.com/dart-lang/sdk/issues/55964 Change-Id: I524d8a1d710b1a744b392e05fa884908c3ff1f12 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-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-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/+/371960 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Lasse Nielsen <lrn@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
Commit Queue
parent
2fe6ffe8c3
commit
965234ccbe
@@ -248,6 +248,7 @@ if (is_fuchsia) {
|
||||
"tests/ffi/has_symbol_test.dart",
|
||||
"tests/ffi/inline_array_multi_dimensional_test.dart",
|
||||
"tests/ffi/inline_array_test.dart",
|
||||
"tests/ffi/inline_array_variable_length_test.dart",
|
||||
"tests/ffi/invoke_callback_after_suspension_test.dart",
|
||||
"tests/ffi/isolate_local_function_callbacks_test.dart",
|
||||
"tests/ffi/msan_test.dart",
|
||||
|
||||
@@ -6654,6 +6654,19 @@ Message _withArgumentsFfiStructGeneric(String string, String name) {
|
||||
);
|
||||
}
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const Code<Null> codeFfiVariableLengthArrayNotLast =
|
||||
messageFfiVariableLengthArrayNotLast;
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const MessageCode messageFfiVariableLengthArrayNotLast = const MessageCode(
|
||||
"FfiVariableLengthArrayNotLast",
|
||||
problemMessage:
|
||||
r"""Variable length 'Array's must only occur as the last field of Structs.""",
|
||||
correctionMessage:
|
||||
r"""Try adjusting the arguments in the 'Array' annotation.""",
|
||||
);
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const Template<Message Function(String name)>
|
||||
templateFieldAlreadyInitializedAtDeclaration =
|
||||
|
||||
@@ -1816,6 +1816,8 @@ FfiCode.PACKED_ANNOTATION_ALIGNMENT:
|
||||
status: noFix
|
||||
FfiCode.SIZE_ANNOTATION_DIMENSIONS:
|
||||
status: noFix
|
||||
FfiCode.VARIABLE_LENGTH_ARRAY_NOT_LAST:
|
||||
status: noFix
|
||||
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS:
|
||||
status: hasFix
|
||||
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS:
|
||||
|
||||
@@ -496,6 +496,13 @@ class FfiCode extends AnalyzerErrorCode {
|
||||
uniqueName: 'SUBTYPE_OF_STRUCT_CLASS_IN_WITH',
|
||||
);
|
||||
|
||||
/// No parameters.
|
||||
static const FfiCode VARIABLE_LENGTH_ARRAY_NOT_LAST = FfiCode(
|
||||
'VARIABLE_LENGTH_ARRAY_NOT_LAST',
|
||||
"Variable length 'Array's must only occur as the last field of Structs.",
|
||||
correctionMessage: "Try adjusting the arguments in the 'Array' annotation.",
|
||||
);
|
||||
|
||||
/// Initialize a newly created error code to have the given [name].
|
||||
const FfiCode(
|
||||
String name,
|
||||
|
||||
@@ -644,6 +644,7 @@ const List<ErrorCode> errorCodeValues = [
|
||||
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS,
|
||||
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS,
|
||||
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_WITH,
|
||||
FfiCode.VARIABLE_LENGTH_ARRAY_NOT_LAST,
|
||||
HintCode.DEPRECATED_COLON_FOR_DEFAULT_VALUE,
|
||||
HintCode.DEPRECATED_MEMBER_USE,
|
||||
HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE,
|
||||
|
||||
@@ -499,8 +499,14 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
|
||||
arguments: ['T', 'Native'],
|
||||
);
|
||||
} else {
|
||||
_checkFfiNativeField(errorNode, declarationElement, metadata,
|
||||
ffiSignature, annotationValue);
|
||||
_checkFfiNativeField(
|
||||
errorNode,
|
||||
declarationElement,
|
||||
metadata,
|
||||
ffiSignature,
|
||||
annotationValue,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,6 +521,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
|
||||
NodeList<Annotation> metadata,
|
||||
DartType ffiSignature,
|
||||
DartObject annotationValue,
|
||||
bool allowVariableLength,
|
||||
) {
|
||||
DartType type;
|
||||
|
||||
@@ -574,7 +581,11 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
|
||||
} else if (ffiSignature.isArray) {
|
||||
// Array fields need an `@Array` size annotation.
|
||||
_validateSizeOfAnnotation(
|
||||
errorToken, metadata, ffiSignature.arrayDimensions);
|
||||
errorToken,
|
||||
metadata,
|
||||
ffiSignature.arrayDimensions,
|
||||
allowVariableLength,
|
||||
);
|
||||
} else if (ffiSignature.isHandle || ffiSignature.isNativeFunction) {
|
||||
_errorReporter.atToken(
|
||||
errorToken,
|
||||
@@ -1466,7 +1477,19 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
|
||||
);
|
||||
}
|
||||
var arrayDimensions = declaredType.arrayDimensions;
|
||||
_validateSizeOfAnnotation(fieldType, annotations, arrayDimensions);
|
||||
var fieldElement = node.fields.variables.first.declaredElement;
|
||||
var lastElement = (fieldElement?.enclosingElement as ClassElement?)
|
||||
?.fields
|
||||
.reversed
|
||||
.where((field) => !field.isStatic)
|
||||
.firstOrNull;
|
||||
var isLastField = fieldElement == lastElement;
|
||||
_validateSizeOfAnnotation(
|
||||
fieldType,
|
||||
annotations,
|
||||
arrayDimensions,
|
||||
isLastField,
|
||||
);
|
||||
} else if (declaredType.isCompoundSubtype) {
|
||||
var clazz = (declaredType as InterfaceType).element;
|
||||
if (clazz.isEmptyStruct) {
|
||||
@@ -1903,8 +1926,12 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
|
||||
/// Validate that the [annotations] include exactly one size annotation. If
|
||||
/// an error is produced that cannot be associated with an annotation,
|
||||
/// associate it with the [errorEntity].
|
||||
void _validateSizeOfAnnotation(SyntacticEntity errorEntity,
|
||||
NodeList<Annotation> annotations, int arrayDimensions) {
|
||||
void _validateSizeOfAnnotation(
|
||||
SyntacticEntity errorEntity,
|
||||
NodeList<Annotation> annotations,
|
||||
int arrayDimensions,
|
||||
bool allowVariableLength,
|
||||
) {
|
||||
var ffiSizeAnnotations =
|
||||
annotations.where((annotation) => annotation.isArray).toList();
|
||||
|
||||
@@ -1928,7 +1955,8 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
// Check number of dimensions.
|
||||
var annotation = ffiSizeAnnotations.first;
|
||||
var dimensions = annotation.elementAnnotation?.arraySizeDimensions ?? [];
|
||||
var (dimensions, variableLength) =
|
||||
annotation.elementAnnotation?.arraySizeDimensions ?? (<int>[], false);
|
||||
var annotationDimensions = dimensions.length;
|
||||
if (annotationDimensions != arrayDimensions) {
|
||||
_errorReporter.atNode(
|
||||
@@ -1937,7 +1965,16 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
|
||||
);
|
||||
}
|
||||
|
||||
// Check dimensions are positive
|
||||
if (variableLength) {
|
||||
if (!allowVariableLength) {
|
||||
_errorReporter.atNode(
|
||||
annotation,
|
||||
FfiCode.VARIABLE_LENGTH_ARRAY_NOT_LAST,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check dimensions are positive.
|
||||
List<AstNode>? getArgumentNodes() {
|
||||
var arguments = annotation.arguments?.arguments;
|
||||
if (arguments != null && arguments.length == 1) {
|
||||
@@ -1950,6 +1987,9 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -2032,10 +2072,13 @@ extension on Annotation {
|
||||
}
|
||||
|
||||
extension on ElementAnnotation {
|
||||
List<int> get arraySizeDimensions {
|
||||
(List<int>, bool) get arraySizeDimensions {
|
||||
assert(isArray);
|
||||
var value = computeConstantValue();
|
||||
|
||||
var variableLength =
|
||||
value?.getField('variableLength')?.toBoolValue() ?? false;
|
||||
|
||||
// Element of `@Array.multi([1, 2, 3])`.
|
||||
var listField = value?.getField('dimensions');
|
||||
if (listField != null) {
|
||||
@@ -2045,7 +2088,7 @@ extension on ElementAnnotation {
|
||||
.whereType<int>()
|
||||
.toList();
|
||||
if (listValues != null) {
|
||||
return listValues;
|
||||
return ([if (variableLength) 0, ...listValues], variableLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2064,7 +2107,7 @@ extension on ElementAnnotation {
|
||||
result.add(dimensionValue);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return (result, variableLength);
|
||||
}
|
||||
|
||||
bool get isArray {
|
||||
|
||||
@@ -895,6 +895,13 @@ final class Array<T extends NativeType> extends _Compound {
|
||||
int dimension5]) = _ArraySize<T>;
|
||||
|
||||
const factory Array.multi(List<int> dimensions) = _ArraySize<T>.multi;
|
||||
|
||||
@Since('3.6')
|
||||
const factory Array.variable() = _ArraySize<T>.variable;
|
||||
|
||||
@Since('3.6')
|
||||
const factory Array.variableMulti(List<int> dimensions) =
|
||||
_ArraySize<T>.variableMulti;
|
||||
}
|
||||
|
||||
final class _ArraySize<T extends NativeType> implements Array<T> {
|
||||
@@ -906,16 +913,44 @@ final class _ArraySize<T extends NativeType> implements Array<T> {
|
||||
|
||||
final List<int>? dimensions;
|
||||
|
||||
const _ArraySize(this.dimension1,
|
||||
[this.dimension2, this.dimension3, this.dimension4, this.dimension5])
|
||||
: dimensions = null;
|
||||
final bool variableLength;
|
||||
|
||||
const _ArraySize(
|
||||
this.dimension1, [
|
||||
this.dimension2,
|
||||
this.dimension3,
|
||||
this.dimension4,
|
||||
this.dimension5,
|
||||
]) : dimensions = null,
|
||||
variableLength = false;
|
||||
|
||||
const _ArraySize.multi(this.dimensions)
|
||||
: dimension1 = null,
|
||||
dimension2 = null,
|
||||
dimension3 = null,
|
||||
dimension4 = null,
|
||||
dimension5 = null;
|
||||
dimension5 = null,
|
||||
variableLength = false;
|
||||
|
||||
static const variableLengthLength = 0;
|
||||
|
||||
const _ArraySize.variable([
|
||||
this.dimension2,
|
||||
this.dimension3,
|
||||
this.dimension4,
|
||||
this.dimension5,
|
||||
]) : dimension1 = variableLengthLength,
|
||||
dimensions = null,
|
||||
variableLength = true;
|
||||
|
||||
const _ArraySize.variableMulti(List<int> nestedDimensions)
|
||||
: dimensions = nestedDimensions,
|
||||
dimension1 = null,
|
||||
dimension2 = null,
|
||||
dimension3 = null,
|
||||
dimension4 = null,
|
||||
dimension5 = null,
|
||||
variableLength = true;
|
||||
}
|
||||
|
||||
extension StructPointer<T extends Struct> on Pointer<T> {
|
||||
|
||||
@@ -20543,6 +20543,17 @@ FfiCode:
|
||||
external Array<Uint8> a0;
|
||||
}
|
||||
```
|
||||
|
||||
If this is a variable length inline array, change the annotation to `Array.variable()`:
|
||||
|
||||
```dart
|
||||
import 'dart:ffi';
|
||||
|
||||
final class MyStruct extends Struct {
|
||||
@Array.variable()
|
||||
external Array<Uint8> a0;
|
||||
}
|
||||
```
|
||||
NON_SIZED_TYPE_ARGUMENT:
|
||||
problemMessage: "The type '{1}' isn't a valid type argument for '{0}'. The type argument must be a native integer, 'Float', 'Double', 'Pointer', or subtype of 'Struct', 'Union', or 'AbiSpecificInteger'."
|
||||
correctionMessage: "Try using a native integer, 'Float', 'Double', 'Pointer', or subtype of 'Struct', 'Union', or 'AbiSpecificInteger'."
|
||||
@@ -20666,6 +20677,65 @@ FfiCode:
|
||||
external Pointer<Uint8> notEmpty;
|
||||
}
|
||||
```
|
||||
VARIABLE_LENGTH_ARRAY_NOT_LAST:
|
||||
problemMessage: "Variable length 'Array's must only occur as the last field of Structs."
|
||||
correctionMessage: "Try adjusting the arguments in the 'Array' annotation."
|
||||
comment: No parameters.
|
||||
documentation: |-
|
||||
#### Description
|
||||
|
||||
The analyzer produces this diagnostic when a variable length inline `Array`
|
||||
is not the last member of a `Struct`.
|
||||
|
||||
For more information about FFI, see [C interop using dart:ffi][ffi].
|
||||
|
||||
#### Example
|
||||
|
||||
The following code produces this diagnostic because the field `a0` has a
|
||||
type with three nested arrays, but only two dimensions are given in the
|
||||
`Array` annotation:
|
||||
|
||||
```dart
|
||||
import 'dart:ffi';
|
||||
|
||||
final class C extends Struct {
|
||||
[!@Array.variable()!]
|
||||
external Array<Uint8> a0;
|
||||
|
||||
@Uint8()
|
||||
external int a1;
|
||||
}
|
||||
```
|
||||
|
||||
#### Common fixes
|
||||
|
||||
Move the variable length inline `Array` to be the last field in the struct.
|
||||
|
||||
```dart
|
||||
import 'dart:ffi';
|
||||
|
||||
final class C extends Struct {
|
||||
@Uint8()
|
||||
external int a1;
|
||||
|
||||
@Array.variable()
|
||||
external Array<Uint8> a0;
|
||||
}
|
||||
```
|
||||
|
||||
If the inline array has a fixed size, annotate it with the size:
|
||||
|
||||
```dart
|
||||
import 'dart:ffi';
|
||||
|
||||
final class C extends Struct {
|
||||
@Array(10)
|
||||
external Array<Uint8> a0;
|
||||
|
||||
@Uint8()
|
||||
external int a1;
|
||||
}
|
||||
```
|
||||
SIZE_ANNOTATION_DIMENSIONS:
|
||||
problemMessage: "'Array's must have an 'Array' annotation that matches the dimensions."
|
||||
correctionMessage: "Try adjusting the arguments in the 'Array' annotation."
|
||||
|
||||
@@ -15726,6 +15726,17 @@ final class MyStruct extends Struct {
|
||||
}
|
||||
```
|
||||
|
||||
If this is a variable length inline array, change the annotation to `Array.variable()`:
|
||||
|
||||
```dart
|
||||
import 'dart:ffi';
|
||||
|
||||
final class MyStruct extends Struct {
|
||||
@Array.variable()
|
||||
external Array<Uint8> a0;
|
||||
}
|
||||
```
|
||||
|
||||
### non_sized_type_argument
|
||||
|
||||
_The type '{1}' isn't a valid type argument for '{0}'. The type argument must be
|
||||
@@ -23674,6 +23685,65 @@ enum E {
|
||||
}
|
||||
```
|
||||
|
||||
### variable_length_array_not_last
|
||||
|
||||
_Variable length 'Array's must only occur as the last field of Structs._
|
||||
|
||||
#### Description
|
||||
|
||||
The analyzer produces this diagnostic when a variable length inline `Array`
|
||||
is not the last member of a `Struct`.
|
||||
|
||||
For more information about FFI, see [C interop using dart:ffi][ffi].
|
||||
|
||||
#### Example
|
||||
|
||||
The following code produces this diagnostic because the field `a0` has a
|
||||
type with three nested arrays, but only two dimensions are given in the
|
||||
`Array` annotation:
|
||||
|
||||
```dart
|
||||
import 'dart:ffi';
|
||||
|
||||
final class C extends Struct {
|
||||
[!@Array.variable()!]
|
||||
external Array<Uint8> a0;
|
||||
|
||||
@Uint8()
|
||||
external int a1;
|
||||
}
|
||||
```
|
||||
|
||||
#### Common fixes
|
||||
|
||||
Move the variable length inline `Array` to be the last field in the struct.
|
||||
|
||||
```dart
|
||||
import 'dart:ffi';
|
||||
|
||||
final class C extends Struct {
|
||||
@Uint8()
|
||||
external int a1;
|
||||
|
||||
@Array.variable()
|
||||
external Array<Uint8> a0;
|
||||
}
|
||||
```
|
||||
|
||||
If the inline array has a fixed size, annotate it with the size:
|
||||
|
||||
```dart
|
||||
import 'dart:ffi';
|
||||
|
||||
final class C extends Struct {
|
||||
@Array(10)
|
||||
external Array<Uint8> a0;
|
||||
|
||||
@Uint8()
|
||||
external int a1;
|
||||
}
|
||||
```
|
||||
|
||||
### variable_pattern_keyword_in_declaration_context
|
||||
|
||||
_Variable patterns in declaration context can't specify 'var' or 'final'
|
||||
|
||||
@@ -422,6 +422,7 @@ FfiStructAnnotation/analyzerCode: Fail
|
||||
FfiStructGeneric/analyzerCode: Fail
|
||||
FfiTypeInvalid/analyzerCode: Fail
|
||||
FfiTypeMismatch/analyzerCode: Fail
|
||||
FfiVariableLengthArrayNotLast/analyzerCode: Fail
|
||||
FieldInitializedOutsideDeclaringClass/part_wrapped_script1: Fail
|
||||
FieldInitializedOutsideDeclaringClass/script1: Fail
|
||||
FieldInitializerOutsideConstructor/part_wrapped_script1: Fail
|
||||
|
||||
@@ -5014,6 +5014,12 @@ FfiSizeAnnotationDimensions:
|
||||
problemMessage: "Field '#name' must have an 'Array' annotation that matches the dimensions."
|
||||
external: test/ffi_test.dart
|
||||
|
||||
FfiVariableLengthArrayNotLast:
|
||||
# Used by dart:ffi
|
||||
problemMessage: "Variable length 'Array's must only occur as the last field of Structs."
|
||||
correctionMessage: "Try adjusting the arguments in the 'Array' annotation."
|
||||
external: test/ffi_test.dart
|
||||
|
||||
FfiStructGeneric:
|
||||
# Used by dart:ffi
|
||||
problemMessage: "#string '#name' should not be generic."
|
||||
|
||||
@@ -17,6 +17,7 @@ annotate
|
||||
api
|
||||
apis
|
||||
argument(s)
|
||||
array's
|
||||
assigning
|
||||
augment
|
||||
augmentation
|
||||
|
||||
@@ -9,9 +9,9 @@ final class StructInlineArray extends ffi::Struct {
|
||||
synthetic constructor •() → self::StructInlineArray
|
||||
: super ffi::Struct::•()
|
||||
;
|
||||
@#C3
|
||||
@#C4
|
||||
external get a0() → ffi::Array<ffi::Uint8>;
|
||||
@#C3
|
||||
@#C4
|
||||
external set a0(synthesized ffi::Array<ffi::Uint8> #externalFieldValue) → void;
|
||||
}
|
||||
static method main() → dynamic {}
|
||||
@@ -19,7 +19,8 @@ static method main() → dynamic {}
|
||||
constants {
|
||||
#C1 = 8
|
||||
#C2 = null
|
||||
#C3 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C1, dimension2:#C2, dimension3:#C2, dimension4:#C2, dimension5:#C2, dimensions:#C2}
|
||||
#C3 = false
|
||||
#C4 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C1, dimension2:#C2, dimension3:#C2, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableLength:#C3}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ final class StructInlineArray extends ffi::Struct {
|
||||
synthetic constructor •() → self::StructInlineArray
|
||||
: super ffi::Struct::•()
|
||||
;
|
||||
@#C3
|
||||
@#C4
|
||||
external get a0() → ffi::Array<ffi::Uint8>;
|
||||
@#C3
|
||||
@#C4
|
||||
external set a0(synthesized ffi::Array<ffi::Uint8> #externalFieldValue) → void;
|
||||
}
|
||||
static method main() → dynamic {}
|
||||
@@ -19,7 +19,8 @@ static method main() → dynamic {}
|
||||
constants {
|
||||
#C1 = 8
|
||||
#C2 = null
|
||||
#C3 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C1, dimension2:#C2, dimension3:#C2, dimension4:#C2, dimension5:#C2, dimensions:#C2}
|
||||
#C3 = false
|
||||
#C4 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C1, dimension2:#C2, dimension3:#C2, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableLength:#C3}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<NativeType>{_ArraySize.dimension1: 8, _ArraySize.dimension2: null, _ArraySize.dimension3: null, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null})
|
||||
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array.dart:10:4 -> InstanceConstant(const _ArraySize<NativeType>{_ArraySize.dimension1: 8, _ArraySize.dimension2: null, _ArraySize.dimension3: null, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null})
|
||||
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array.dart:10:4 -> InstanceConstant(const _ArraySize<NativeType>{_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<NativeType>{_ArraySize.dimension1: 8, _ArraySize.dimension2: null, _ArraySize.dimension3: null, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null, _ArraySize.variableLength: false})
|
||||
Extra constant evaluation: evaluated: 2, effectively constant: 2
|
||||
|
||||
+16
-15
@@ -18,18 +18,18 @@ final class StructInlineArray extends ffi::Struct {
|
||||
constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::StructInlineArray
|
||||
: super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes)
|
||||
;
|
||||
@#C9
|
||||
@#C10
|
||||
get a0() → ffi::Array<ffi::Uint8>
|
||||
return new ffi::Array::_<ffi::Uint8>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::StructInlineArray::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C10);
|
||||
@#C9
|
||||
return new ffi::Array::_<ffi::Uint8>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::StructInlineArray::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C11);
|
||||
@#C10
|
||||
set a0(synthesized ffi::Array<ffi::Uint8> #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}, #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C13
|
||||
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}, #C12.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C14
|
||||
static get a0#offsetOf() → core::int
|
||||
return #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C13
|
||||
return #C16.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C14
|
||||
static get #sizeOf() → core::int
|
||||
return #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
return #C12.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
}
|
||||
static method main() → dynamic {}
|
||||
|
||||
@@ -42,13 +42,14 @@ constants {
|
||||
#C6 = null
|
||||
#C7 = ffi::_FfiStructLayout {fieldTypes:#C5, packing:#C6}
|
||||
#C8 = core::pragma {name:#C1, options:#C7}
|
||||
#C9 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C3, dimension2:#C6, dimension3:#C6, dimension4:#C6, dimension5:#C6, dimensions:#C6}
|
||||
#C10 = <core::int>[]
|
||||
#C11 = <core::int>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
|
||||
#C12 = "vm:prefer-inline"
|
||||
#C13 = core::pragma {name:#C12, options:#C6}
|
||||
#C14 = 0
|
||||
#C15 = <core::int>[#C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14]
|
||||
#C9 = false
|
||||
#C10 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C3, dimension2:#C6, dimension3:#C6, dimension4:#C6, dimension5:#C6, dimensions:#C6, variableLength:#C9}
|
||||
#C11 = <core::int>[]
|
||||
#C12 = <core::int>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
|
||||
#C13 = "vm:prefer-inline"
|
||||
#C14 = core::pragma {name:#C13, options:#C6}
|
||||
#C15 = 0
|
||||
#C16 = <core::int>[#C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15]
|
||||
}
|
||||
|
||||
|
||||
|
||||
+7
-6
@@ -10,25 +10,26 @@ final class StructInlineArrayMultiDimensional extends ffi::Struct {
|
||||
synthetic constructor •() → self::StructInlineArrayMultiDimensional
|
||||
: super ffi::Struct::•()
|
||||
;
|
||||
@#C3
|
||||
@#C4
|
||||
external get a0() → ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>>;
|
||||
@#C3
|
||||
@#C4
|
||||
external set a0(synthesized ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>> #externalFieldValue) → void;
|
||||
}
|
||||
static method main() → dynamic {
|
||||
final ffi::Pointer<self::StructInlineArrayMultiDimensional> pointer = ffi::AllocatorAlloc|call<self::StructInlineArrayMultiDimensional>(#C4);
|
||||
final ffi::Pointer<self::StructInlineArrayMultiDimensional> pointer = ffi::AllocatorAlloc|call<self::StructInlineArrayMultiDimensional>(#C5);
|
||||
final self::StructInlineArrayMultiDimensional struct = ffi::StructPointer|get#ref<self::StructInlineArrayMultiDimensional>(pointer);
|
||||
final ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>> array = struct.{self::StructInlineArrayMultiDimensional::a0}{ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>>};
|
||||
final ffi::Array<ffi::Array<ffi::Uint8>> subArray = ffi::ArrayArray|[]<ffi::Array<ffi::Uint8>>(array, 0);
|
||||
ffi::ArrayArray|[]=<ffi::Array<ffi::Uint8>>(array, 1, subArray);
|
||||
#C4.{all::CallocAllocator::free}(pointer){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C5.{all::CallocAllocator::free}(pointer){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 2
|
||||
#C2 = null
|
||||
#C3 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C1, dimension2:#C1, dimension3:#C1, dimension4:#C2, dimension5:#C2, dimensions:#C2}
|
||||
#C4 = all::CallocAllocator {}
|
||||
#C3 = false
|
||||
#C4 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C1, dimension2:#C1, dimension3:#C1, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableLength:#C3}
|
||||
#C5 = all::CallocAllocator {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+7
-6
@@ -10,25 +10,26 @@ final class StructInlineArrayMultiDimensional extends ffi::Struct {
|
||||
synthetic constructor •() → self::StructInlineArrayMultiDimensional
|
||||
: super ffi::Struct::•()
|
||||
;
|
||||
@#C3
|
||||
@#C4
|
||||
external get a0() → ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>>;
|
||||
@#C3
|
||||
@#C4
|
||||
external set a0(synthesized ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>> #externalFieldValue) → void;
|
||||
}
|
||||
static method main() → dynamic {
|
||||
final ffi::Pointer<self::StructInlineArrayMultiDimensional> pointer = ffi::AllocatorAlloc|call<self::StructInlineArrayMultiDimensional>(#C4);
|
||||
final ffi::Pointer<self::StructInlineArrayMultiDimensional> pointer = ffi::AllocatorAlloc|call<self::StructInlineArrayMultiDimensional>(#C5);
|
||||
final self::StructInlineArrayMultiDimensional struct = ffi::StructPointer|get#ref<self::StructInlineArrayMultiDimensional>(pointer);
|
||||
final ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>> array = struct.{self::StructInlineArrayMultiDimensional::a0}{ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>>};
|
||||
final ffi::Array<ffi::Array<ffi::Uint8>> subArray = ffi::ArrayArray|[]<ffi::Array<ffi::Uint8>>(array, 0);
|
||||
ffi::ArrayArray|[]=<ffi::Array<ffi::Uint8>>(array, 1, subArray);
|
||||
#C4.{all::CallocAllocator::free}(pointer){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C5.{all::CallocAllocator::free}(pointer){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 2
|
||||
#C2 = null
|
||||
#C3 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C1, dimension2:#C1, dimension3:#C1, dimension4:#C2, dimension5:#C2, dimensions:#C2}
|
||||
#C4 = all::CallocAllocator {}
|
||||
#C3 = false
|
||||
#C4 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C1, dimension2:#C1, dimension3:#C1, dimension4:#C2, dimension5:#C2, dimensions:#C2, variableLength:#C3}
|
||||
#C5 = all::CallocAllocator {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -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<NativeType>{_ArraySize.dimension1: 2, _ArraySize.dimension2: 2, _ArraySize.dimension3: 2, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null})
|
||||
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:10:4 -> InstanceConstant(const _ArraySize<NativeType>{_ArraySize.dimension1: 2, _ArraySize.dimension2: 2, _ArraySize.dimension3: 2, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null})
|
||||
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:10:4 -> InstanceConstant(const _ArraySize<NativeType>{_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<NativeType>{_ArraySize.dimension1: 2, _ArraySize.dimension2: 2, _ArraySize.dimension3: 2, _ArraySize.dimension4: null, _ArraySize.dimension5: null, _ArraySize.dimensions: null, _ArraySize.variableLength: false})
|
||||
Extra constant evaluation: evaluated: 2, effectively constant: 2
|
||||
|
||||
+23
-22
@@ -19,28 +19,28 @@ final class StructInlineArrayMultiDimensional extends ffi::Struct {
|
||||
constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::StructInlineArrayMultiDimensional
|
||||
: super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes)
|
||||
;
|
||||
@#C10
|
||||
@#C11
|
||||
get a0() → ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>>
|
||||
return new ffi::Array::_<ffi::Array<ffi::Array<ffi::Uint8>>>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::StructInlineArrayMultiDimensional::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C9, #C11);
|
||||
@#C10
|
||||
return new ffi::Array::_<ffi::Array<ffi::Array<ffi::Uint8>>>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::StructInlineArrayMultiDimensional::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C9, #C12);
|
||||
@#C11
|
||||
set a0(synthesized ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>> #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}, #C12.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C14
|
||||
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}, #C13.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C15
|
||||
static get a0#offsetOf() → core::int
|
||||
return #C16.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C14
|
||||
return #C17.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C15
|
||||
static get #sizeOf() → core::int
|
||||
return #C12.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
return #C13.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
}
|
||||
static method main() → dynamic {
|
||||
final ffi::Pointer<self::StructInlineArrayMultiDimensional> pointer = #C17.{ffi::Allocator::allocate}<self::StructInlineArrayMultiDimensional>(self::StructInlineArrayMultiDimensional::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::StructInlineArrayMultiDimensional>};
|
||||
final self::StructInlineArrayMultiDimensional struct = new self::StructInlineArrayMultiDimensional::#fromTypedDataBase(pointer!, #C15);
|
||||
final ffi::Pointer<self::StructInlineArrayMultiDimensional> pointer = #C18.{ffi::Allocator::allocate}<self::StructInlineArrayMultiDimensional>(self::StructInlineArrayMultiDimensional::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::StructInlineArrayMultiDimensional>};
|
||||
final self::StructInlineArrayMultiDimensional struct = new self::StructInlineArrayMultiDimensional::#fromTypedDataBase(pointer!, #C16);
|
||||
final ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>> array = struct.{self::StructInlineArrayMultiDimensional::a0}{ffi::Array<ffi::Array<ffi::Array<ffi::Uint8>>>};
|
||||
final ffi::Array<ffi::Array<ffi::Uint8>> subArray = block {
|
||||
synthesized ffi::Array<dynamic> #array = array!;
|
||||
synthesized core::int #index = 0!;
|
||||
#array.{ffi::Array::_checkIndex}(#index){(core::int) → void};
|
||||
synthesized core::int #singleElementSize = #C18;
|
||||
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::_<ffi::Array<ffi::Uint8>>(#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<core::int>});
|
||||
@@ -48,12 +48,12 @@ static method main() → dynamic {
|
||||
synthesized ffi::Array<dynamic> #array = array!;
|
||||
synthesized core::int #index = 1!;
|
||||
#array.{ffi::Array::_checkIndex}(#index){(core::int) → void};
|
||||
synthesized core::int #singleElementSize = #C18;
|
||||
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};
|
||||
synthesized ffi::Array<dynamic> #value = subArray!;
|
||||
} =>ffi::_memCopy(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#offset){(core::num) → core::num}, #value.{ffi::_Compound::_typedDataBase}{core::Object}, #value.{ffi::_Compound::_offsetInBytes}{core::int}, #elementSize);
|
||||
#C17.{all::CallocAllocator::free}(pointer){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C18.{all::CallocAllocator::free}(pointer){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
|
||||
constants {
|
||||
@@ -66,15 +66,16 @@ constants {
|
||||
#C7 = ffi::_FfiStructLayout {fieldTypes:#C5, packing:#C6}
|
||||
#C8 = core::pragma {name:#C1, options:#C7}
|
||||
#C9 = 2
|
||||
#C10 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C9, dimension2:#C9, dimension3:#C9, dimension4:#C6, dimension5:#C6, dimensions:#C6}
|
||||
#C11 = <core::int>[#C9, #C9]
|
||||
#C12 = <core::int>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
|
||||
#C13 = "vm:prefer-inline"
|
||||
#C14 = core::pragma {name:#C13, options:#C6}
|
||||
#C15 = 0
|
||||
#C16 = <core::int>[#C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15]
|
||||
#C17 = all::CallocAllocator {}
|
||||
#C18 = 1
|
||||
#C10 = false
|
||||
#C11 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C9, dimension2:#C9, dimension3:#C9, dimension4:#C6, dimension5:#C6, dimensions:#C6, variableLength:#C10}
|
||||
#C12 = <core::int>[#C9, #C9]
|
||||
#C13 = <core::int>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
|
||||
#C14 = "vm:prefer-inline"
|
||||
#C15 = core::pragma {name:#C14, options:#C6}
|
||||
#C16 = 0
|
||||
#C17 = <core::int>[#C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16, #C16]
|
||||
#C18 = all::CallocAllocator {}
|
||||
#C19 = 1
|
||||
}
|
||||
|
||||
Extra constant evaluation status:
|
||||
|
||||
@@ -13,6 +13,7 @@ import 'package:front_end/src/codes/cfe_codes.dart'
|
||||
show
|
||||
messageFfiLeafCallMustNotReturnHandle,
|
||||
messageFfiLeafCallMustNotTakeHandle,
|
||||
messageFfiVariableLengthArrayNotLast,
|
||||
messageNonPositiveArrayDimensions,
|
||||
templateFfiSizeAnnotation,
|
||||
templateFfiSizeAnnotationDimensions,
|
||||
@@ -223,6 +224,7 @@ class FfiTransformer extends Transformer {
|
||||
final Field arraySizeDimension4Field;
|
||||
final Field arraySizeDimension5Field;
|
||||
final Field arraySizeDimensionsField;
|
||||
final Field arraySizeVariableLengthField;
|
||||
final Class pointerClass;
|
||||
final Class compoundClass;
|
||||
final Class structClass;
|
||||
@@ -413,6 +415,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'),
|
||||
pointerClass = index.getClass('dart:ffi', 'Pointer'),
|
||||
compoundClass = index.getClass('dart:ffi', '_Compound'),
|
||||
structClass = index.getClass('dart:ffi', 'Struct'),
|
||||
@@ -985,9 +989,14 @@ class FfiTransformer extends Transformer {
|
||||
/// matching its [type].
|
||||
///
|
||||
/// Throws an [FfiStaticTypeError] otherwise.
|
||||
List<int> ensureArraySizeAnnotation(Member node, DartType type) {
|
||||
List<int> ensureArraySizeAnnotation(
|
||||
Member node,
|
||||
DartType type,
|
||||
bool allowVariableLength,
|
||||
) {
|
||||
final sizeAnnotations = getArraySizeAnnotations(node);
|
||||
List<int> dimensions;
|
||||
bool variableLength;
|
||||
var success = true;
|
||||
|
||||
if (sizeAnnotations.length == 1) {
|
||||
@@ -996,7 +1005,8 @@ class FfiTransformer extends Transformer {
|
||||
assert(singleElementType is InvalidType);
|
||||
throw FfiStaticTypeError();
|
||||
} else {
|
||||
dimensions = sizeAnnotations.single;
|
||||
dimensions = sizeAnnotations.single.$1;
|
||||
variableLength = sizeAnnotations.single.$2;
|
||||
if (arrayDimensions(type) != dimensions.length) {
|
||||
diagnosticReporter.report(
|
||||
templateFfiSizeAnnotationDimensions.withArguments(node.name.text),
|
||||
@@ -1004,6 +1014,17 @@ class FfiTransformer extends Transformer {
|
||||
node.name.text.length,
|
||||
node.fileUri);
|
||||
}
|
||||
if (variableLength) {
|
||||
if (!allowVariableLength) {
|
||||
diagnosticReporter.report(
|
||||
messageFfiVariableLengthArrayNotLast,
|
||||
node.fileOffset,
|
||||
node.name.text.length,
|
||||
node.fileUri,
|
||||
);
|
||||
}
|
||||
return dimensions; // Variable length single dimension.
|
||||
}
|
||||
for (var dimension in dimensions) {
|
||||
if (dimension <= 0) {
|
||||
diagnosticReporter.report(messageNonPositiveArrayDimensions,
|
||||
@@ -1028,7 +1049,7 @@ class FfiTransformer extends Transformer {
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
Iterable<List<int>> getArraySizeAnnotations(Member node) {
|
||||
Iterable<(List<int>, bool)> getArraySizeAnnotations(Member node) {
|
||||
return node.annotations
|
||||
.whereType<ConstantExpression>()
|
||||
.map((e) => e.constant)
|
||||
@@ -1038,16 +1059,18 @@ class FfiTransformer extends Transformer {
|
||||
}
|
||||
|
||||
/// Reads the dimensions from a constant instance of `_ArraySize`.
|
||||
List<int> _arraySize(InstanceConstant constant) {
|
||||
(List<int>, bool) _arraySize(InstanceConstant constant) {
|
||||
final variableLength =
|
||||
(constant.fieldValues[arraySizeVariableLengthField.fieldReference]
|
||||
as BoolConstant)
|
||||
.value;
|
||||
final dimensions =
|
||||
constant.fieldValues[arraySizeDimensionsField.fieldReference];
|
||||
if (dimensions != null) {
|
||||
if (dimensions is ListConstant) {
|
||||
final result = dimensions.entries
|
||||
.whereType<IntConstant>()
|
||||
.map((e) => e.value)
|
||||
.toList();
|
||||
return result;
|
||||
final result =
|
||||
dimensions.entries.whereType<IntConstant>().map((e) => e.value);
|
||||
return ([if (variableLength) 0, ...result], variableLength);
|
||||
}
|
||||
}
|
||||
final dimensionFields = [
|
||||
@@ -1062,7 +1085,7 @@ class FfiTransformer extends Transformer {
|
||||
.whereType<IntConstant>()
|
||||
.map((c) => c.value)
|
||||
.toList();
|
||||
return result;
|
||||
return (result, variableLength);
|
||||
}
|
||||
|
||||
/// Returns the number of dimensions of `Array`.
|
||||
|
||||
@@ -442,6 +442,7 @@ class _FfiDefinitionTransformer extends FfiTransformer {
|
||||
bool success = true;
|
||||
final membersWithAnnotations =
|
||||
_compoundFieldMembers(node, includeSetters: false);
|
||||
final lastField = membersWithAnnotations.lastOrNull;
|
||||
for (final Member f in membersWithAnnotations) {
|
||||
if (f is Field) {
|
||||
if (f.initializer is! NullLiteral) {
|
||||
@@ -485,7 +486,8 @@ class _FfiDefinitionTransformer extends FfiTransformer {
|
||||
if (isArrayType(type)) {
|
||||
try {
|
||||
ensureNativeTypeValid(type, f, allowInlineArray: true);
|
||||
ensureArraySizeAnnotation(f, type);
|
||||
final isLastField = f == lastField;
|
||||
ensureArraySizeAnnotation(f, type, isLastField);
|
||||
} on FfiStaticTypeError {
|
||||
// It's OK to swallow the exception because the diagnostics issued will
|
||||
// cause compilation to fail. By continuing, we can report more
|
||||
@@ -674,7 +676,7 @@ class _FfiDefinitionTransformer extends FfiTransformer {
|
||||
if (isArrayType(dartType)) {
|
||||
final sizeAnnotations = getArraySizeAnnotations(m).toList();
|
||||
if (sizeAnnotations.length == 1) {
|
||||
final arrayDimensions = sizeAnnotations.single;
|
||||
final arrayDimensions = sizeAnnotations.single.$1;
|
||||
if (this.arrayDimensions(dartType) == arrayDimensions.length) {
|
||||
final elementType = arraySingleElementType(dartType);
|
||||
if (elementType is! InterfaceType) {
|
||||
|
||||
@@ -764,7 +764,7 @@ class FfiNativeTransformer extends FfiTransformer {
|
||||
|
||||
// Array types must have an @Array annotation denoting its size.
|
||||
if (isArrayType(ffiType)) {
|
||||
final dimensions = ensureArraySizeAnnotation(node, ffiType);
|
||||
final dimensions = ensureArraySizeAnnotation(node, ffiType, false);
|
||||
return (
|
||||
ffiType,
|
||||
NativeTypeCfe.withoutLayout(this, dartType, arrayDimensions: dimensions)
|
||||
|
||||
@@ -60,31 +60,31 @@ final class WCharArrayStruct extends ffi::Struct {
|
||||
constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::WCharArrayStruct
|
||||
: super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes)
|
||||
;
|
||||
@#C83
|
||||
@#C84
|
||||
get a0() → ffi::Array<self::WChar>
|
||||
return new ffi::Array::_<self::WChar>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::WCharArrayStruct::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C78, #C84);
|
||||
@#C83
|
||||
return new ffi::Array::_<self::WChar>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::WCharArrayStruct::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C78, #C85);
|
||||
@#C84
|
||||
set a0(synthesized ffi::Array<self::WChar> #externalFieldValue) → void
|
||||
return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::WCharArrayStruct::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}, #C87.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::WCharArrayStruct::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}, #C88.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C67
|
||||
static get a0#offsetOf() → core::int
|
||||
return #C75.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C67
|
||||
static get #sizeOf() → core::int
|
||||
return #C87.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
return #C88.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
}
|
||||
class _DummyAllocator extends core::Object implements ffi::Allocator /*hasConstConstructor*/ {
|
||||
const constructor •() → self::_DummyAllocator
|
||||
: super core::Object::•()
|
||||
;
|
||||
@#C88
|
||||
@#C89
|
||||
method allocate<T extends ffi::NativeType>(core::int byteCount, {core::int? alignment = #C66}) → ffi::Pointer<self::_DummyAllocator::allocate::T> {
|
||||
return ffi::Pointer::fromAddress<self::_DummyAllocator::allocate::T>(0);
|
||||
}
|
||||
@#C88
|
||||
@#C89
|
||||
method free(ffi::Pointer<ffi::NativeType> pointer) → void {}
|
||||
}
|
||||
static const field self::_DummyAllocator noAlloc = #C89;
|
||||
static const field self::_DummyAllocator noAlloc = #C90;
|
||||
static method main() → void {
|
||||
self::testSizeOf();
|
||||
self::testStoreLoad();
|
||||
@@ -97,29 +97,29 @@ static method testSizeOf() → void {
|
||||
core::print(size);
|
||||
}
|
||||
static method testStoreLoad() → void {
|
||||
final ffi::Pointer<self::WChar> p = #C89.{ffi::Allocator::allocate}<self::WChar>(self::WChar::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::WChar>};
|
||||
final ffi::Pointer<self::WChar> p = #C90.{ffi::Allocator::allocate}<self::WChar>(self::WChar::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::WChar>};
|
||||
ffi::_storeAbiSpecificInt<self::WChar>(p, #C1, 10);
|
||||
core::print(ffi::_loadAbiSpecificInt<self::WChar>(p, #C1));
|
||||
#C89.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C90.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
static method testStoreLoadIndexed() → void {
|
||||
final ffi::Pointer<self::WChar> p = #C89.{ffi::Allocator::allocate}<self::WChar>(2.{core::num::*}(self::WChar::#sizeOf){(core::num) → core::num}){(core::int, {alignment: core::int?}) → ffi::Pointer<self::WChar>};
|
||||
final ffi::Pointer<self::WChar> p = #C90.{ffi::Allocator::allocate}<self::WChar>(2.{core::num::*}(self::WChar::#sizeOf){(core::num) → core::num}){(core::int, {alignment: core::int?}) → ffi::Pointer<self::WChar>};
|
||||
ffi::_storeAbiSpecificIntAtIndex<self::WChar>(p, #C1, 0, 10);
|
||||
ffi::_storeAbiSpecificIntAtIndex<self::WChar>(p, #C1, 1, 3);
|
||||
core::print(ffi::_loadAbiSpecificIntAtIndex<self::WChar>(p, #C1, 0));
|
||||
core::print(ffi::_loadAbiSpecificIntAtIndex<self::WChar>(p, #C1, 1));
|
||||
#C89.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C90.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
static method testStruct() → void {
|
||||
final ffi::Pointer<self::WCharStruct> p = #C89.{ffi::Allocator::allocate}<self::WCharStruct>(self::WCharStruct::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::WCharStruct>};
|
||||
final ffi::Pointer<self::WCharStruct> p = #C90.{ffi::Allocator::allocate}<self::WCharStruct>(self::WCharStruct::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::WCharStruct>};
|
||||
new self::WCharStruct::#fromTypedDataBase(p!, #C1).{self::WCharStruct::a0} = 1;
|
||||
core::print(new self::WCharStruct::#fromTypedDataBase(p!, #C1).{self::WCharStruct::a0}{core::int});
|
||||
new self::WCharStruct::#fromTypedDataBase(p!, #C1).{self::WCharStruct::a0} = 2;
|
||||
core::print(new self::WCharStruct::#fromTypedDataBase(p!, #C1).{self::WCharStruct::a0}{core::int});
|
||||
#C89.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C90.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
static method testInlineArray() → void {
|
||||
final ffi::Pointer<self::WCharArrayStruct> p = #C89.{ffi::Allocator::allocate}<self::WCharArrayStruct>(self::WCharArrayStruct::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::WCharArrayStruct>};
|
||||
final ffi::Pointer<self::WCharArrayStruct> p = #C90.{ffi::Allocator::allocate}<self::WCharArrayStruct>(self::WCharArrayStruct::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::WCharArrayStruct>};
|
||||
final ffi::Array<self::WChar> array = new self::WCharArrayStruct::#fromTypedDataBase(p!, #C1).{self::WCharArrayStruct::a0}{ffi::Array<self::WChar>};
|
||||
for (core::int i = 0; i.{core::num::<}(100){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int}) {
|
||||
block {
|
||||
@@ -135,7 +135,7 @@ static method testInlineArray() → void {
|
||||
#array.{ffi::Array::_checkIndex}(#index){(core::int) → void};
|
||||
} =>ffi::_loadAbiSpecificIntAtIndex<self::WChar>(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}, #index));
|
||||
}
|
||||
#C89.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C90.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
constants {
|
||||
#C1 = 0
|
||||
@@ -220,11 +220,12 @@ constants {
|
||||
#C80 = <core::Type>[#C79]
|
||||
#C81 = ffi::_FfiStructLayout {fieldTypes:#C80, packing:#C66}
|
||||
#C82 = core::pragma {name:#C69, options:#C81}
|
||||
#C83 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C78, dimension2:#C66, dimension3:#C66, dimension4:#C66, dimension5:#C66, dimensions:#C66}
|
||||
#C84 = <core::int>[]
|
||||
#C85 = 400
|
||||
#C86 = 200
|
||||
#C87 = <core::int>[#C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C85, #C86, #C86, #C86]
|
||||
#C88 = core::_Override {}
|
||||
#C89 = self::_DummyAllocator {}
|
||||
#C83 = false
|
||||
#C84 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C78, dimension2:#C66, dimension3:#C66, dimension4:#C66, dimension5:#C66, dimensions:#C66, variableLength:#C83}
|
||||
#C85 = <core::int>[]
|
||||
#C86 = 400
|
||||
#C87 = 200
|
||||
#C88 = <core::int>[#C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C86, #C87, #C87, #C87]
|
||||
#C89 = core::_Override {}
|
||||
#C90 = self::_DummyAllocator {}
|
||||
}
|
||||
|
||||
@@ -60,31 +60,31 @@ final class IncompleteArrayStruct extends ffi::Struct {
|
||||
constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::IncompleteArrayStruct
|
||||
: super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes)
|
||||
;
|
||||
@#C46
|
||||
@#C47
|
||||
get a0() → ffi::Array<self::Incomplete>
|
||||
return new ffi::Array::_<self::Incomplete>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::IncompleteArrayStruct::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C41, #C47);
|
||||
@#C46
|
||||
return new ffi::Array::_<self::Incomplete>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::IncompleteArrayStruct::a0#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C41, #C48);
|
||||
@#C47
|
||||
set a0(synthesized ffi::Array<self::Incomplete> #externalFieldValue) → void
|
||||
return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::IncompleteArrayStruct::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}, ffi::_checkAbiSpecificIntegerMapping<core::int>(#C49.{core::List::[]}(ffi::_abi()){(core::int) → core::int?}));
|
||||
return ffi::_memCopy(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::IncompleteArrayStruct::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}, ffi::_checkAbiSpecificIntegerMapping<core::int>(#C50.{core::List::[]}(ffi::_abi()){(core::int) → core::int?}));
|
||||
@#C29
|
||||
static get a0#offsetOf() → core::int
|
||||
return #C38.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C29
|
||||
static get #sizeOf() → core::int
|
||||
return ffi::_checkAbiSpecificIntegerMapping<core::int>(#C49.{core::List::[]}(ffi::_abi()){(core::int) → core::int?});
|
||||
return ffi::_checkAbiSpecificIntegerMapping<core::int>(#C50.{core::List::[]}(ffi::_abi()){(core::int) → core::int?});
|
||||
}
|
||||
class _DummyAllocator extends core::Object implements ffi::Allocator /*hasConstConstructor*/ {
|
||||
const constructor •() → self::_DummyAllocator
|
||||
: super core::Object::•()
|
||||
;
|
||||
@#C50
|
||||
@#C51
|
||||
method allocate<T extends ffi::NativeType>(core::int byteCount, {core::int? alignment = #C23}) → ffi::Pointer<self::_DummyAllocator::allocate::T> {
|
||||
return ffi::Pointer::fromAddress<self::_DummyAllocator::allocate::T>(0);
|
||||
}
|
||||
@#C50
|
||||
@#C51
|
||||
method free(ffi::Pointer<ffi::NativeType> pointer) → void {}
|
||||
}
|
||||
static const field self::_DummyAllocator noAlloc = #C51;
|
||||
static const field self::_DummyAllocator noAlloc = #C52;
|
||||
static method main() → void {
|
||||
self::testSizeOf();
|
||||
self::testStoreLoad();
|
||||
@@ -97,29 +97,29 @@ static method testSizeOf() → void {
|
||||
core::print(size);
|
||||
}
|
||||
static method testStoreLoad() → void {
|
||||
final ffi::Pointer<self::Incomplete> p = #C51.{ffi::Allocator::allocate}<self::Incomplete>(self::Incomplete::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::Incomplete>};
|
||||
final ffi::Pointer<self::Incomplete> p = #C52.{ffi::Allocator::allocate}<self::Incomplete>(self::Incomplete::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::Incomplete>};
|
||||
ffi::_storeAbiSpecificInt<self::Incomplete>(p, #C4, 10);
|
||||
core::print(ffi::_loadAbiSpecificInt<self::Incomplete>(p, #C4));
|
||||
#C51.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C52.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
static method testStoreLoadIndexed() → void {
|
||||
final ffi::Pointer<self::Incomplete> p = #C51.{ffi::Allocator::allocate}<self::Incomplete>(2.{core::num::*}(self::Incomplete::#sizeOf){(core::num) → core::num}){(core::int, {alignment: core::int?}) → ffi::Pointer<self::Incomplete>};
|
||||
final ffi::Pointer<self::Incomplete> p = #C52.{ffi::Allocator::allocate}<self::Incomplete>(2.{core::num::*}(self::Incomplete::#sizeOf){(core::num) → core::num}){(core::int, {alignment: core::int?}) → ffi::Pointer<self::Incomplete>};
|
||||
ffi::_storeAbiSpecificIntAtIndex<self::Incomplete>(p, #C4, 0, 10);
|
||||
ffi::_storeAbiSpecificIntAtIndex<self::Incomplete>(p, #C4, 1, 3);
|
||||
core::print(ffi::_loadAbiSpecificIntAtIndex<self::Incomplete>(p, #C4, 0));
|
||||
core::print(ffi::_loadAbiSpecificIntAtIndex<self::Incomplete>(p, #C4, 1));
|
||||
#C51.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C52.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
static method testStruct() → void {
|
||||
final ffi::Pointer<self::IncompleteStruct> p = #C51.{ffi::Allocator::allocate}<self::IncompleteStruct>(self::IncompleteStruct::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::IncompleteStruct>};
|
||||
final ffi::Pointer<self::IncompleteStruct> p = #C52.{ffi::Allocator::allocate}<self::IncompleteStruct>(self::IncompleteStruct::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::IncompleteStruct>};
|
||||
new self::IncompleteStruct::#fromTypedDataBase(p!, #C4).{self::IncompleteStruct::a0} = 1;
|
||||
core::print(new self::IncompleteStruct::#fromTypedDataBase(p!, #C4).{self::IncompleteStruct::a0}{core::int});
|
||||
new self::IncompleteStruct::#fromTypedDataBase(p!, #C4).{self::IncompleteStruct::a0} = 2;
|
||||
core::print(new self::IncompleteStruct::#fromTypedDataBase(p!, #C4).{self::IncompleteStruct::a0}{core::int});
|
||||
#C51.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C52.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
static method testInlineArray() → void {
|
||||
final ffi::Pointer<self::IncompleteArrayStruct> p = #C51.{ffi::Allocator::allocate}<self::IncompleteArrayStruct>(self::IncompleteArrayStruct::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::IncompleteArrayStruct>};
|
||||
final ffi::Pointer<self::IncompleteArrayStruct> p = #C52.{ffi::Allocator::allocate}<self::IncompleteArrayStruct>(self::IncompleteArrayStruct::#sizeOf){(core::int, {alignment: core::int?}) → ffi::Pointer<self::IncompleteArrayStruct>};
|
||||
final ffi::Array<self::Incomplete> array = new self::IncompleteArrayStruct::#fromTypedDataBase(p!, #C4).{self::IncompleteArrayStruct::a0}{ffi::Array<self::Incomplete>};
|
||||
for (core::int i = 0; i.{core::num::<}(100){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int}) {
|
||||
block {
|
||||
@@ -135,7 +135,7 @@ static method testInlineArray() → void {
|
||||
#array.{ffi::Array::_checkIndex}(#index){(core::int) → void};
|
||||
} =>ffi::_loadAbiSpecificIntAtIndex<self::Incomplete>(#array.{ffi::_Compound::_typedDataBase}{core::Object}, #array.{ffi::_Compound::_offsetInBytes}{core::int}, #index));
|
||||
}
|
||||
#C51.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
#C52.{self::_DummyAllocator::free}(p){(ffi::Pointer<ffi::NativeType>) → void};
|
||||
}
|
||||
constants {
|
||||
#C1 = 3
|
||||
@@ -183,10 +183,11 @@ constants {
|
||||
#C43 = <core::Type>[#C42]
|
||||
#C44 = ffi::_FfiStructLayout {fieldTypes:#C43, packing:#C23}
|
||||
#C45 = core::pragma {name:#C32, options:#C44}
|
||||
#C46 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C41, dimension2:#C23, dimension3:#C23, dimension4:#C23, dimension5:#C23, dimensions:#C23}
|
||||
#C47 = <core::int>[]
|
||||
#C48 = 400
|
||||
#C49 = <core::int?>[#C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C48, #C48, #C48, #C48, #C23, #C23, #C23, #C23, #C23, #C23, #C23]
|
||||
#C50 = core::_Override {}
|
||||
#C51 = self::_DummyAllocator {}
|
||||
#C46 = false
|
||||
#C47 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C41, dimension2:#C23, dimension3:#C23, dimension4:#C23, dimension5:#C23, dimensions:#C23, variableLength:#C46}
|
||||
#C48 = <core::int>[]
|
||||
#C49 = 400
|
||||
#C50 = <core::int?>[#C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C49, #C49, #C49, #C49, #C23, #C23, #C23, #C23, #C23, #C23, #C23]
|
||||
#C51 = core::_Override {}
|
||||
#C52 = self::_DummyAllocator {}
|
||||
}
|
||||
|
||||
@@ -17,20 +17,20 @@ final class MyStruct extends ffi::Struct {
|
||||
constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyStruct
|
||||
: super ffi::Struct::_fromTypedData(#typedData, #offset, #sizeInBytes)
|
||||
;
|
||||
@#C9
|
||||
@#C10
|
||||
get a() → ffi::Array<ffi::Int8>
|
||||
return new ffi::Array::_<ffi::Int8>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C10);
|
||||
@#C9
|
||||
return new ffi::Array::_<ffi::Int8>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::a#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C11);
|
||||
@#C10
|
||||
set a(synthesized ffi::Array<ffi::Int8> #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}, #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C13
|
||||
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}, #C12.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C14
|
||||
static get a#offsetOf() → core::int
|
||||
return #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C13
|
||||
return #C16.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C14
|
||||
static get #sizeOf() → core::int
|
||||
return #C11.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
return #C12.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
}
|
||||
@#C18
|
||||
@#C19
|
||||
final class MyUnion extends ffi::Union {
|
||||
synthetic constructor •() → self::MyUnion
|
||||
: super ffi::Union::•()
|
||||
@@ -41,43 +41,43 @@ final class MyUnion extends ffi::Union {
|
||||
constructor #fromTypedData(synthesized typ::TypedData #typedData, synthesized core::int #offset, synthesized core::int #sizeInBytes) → self::MyUnion
|
||||
: super ffi::Union::_fromTypedData(#typedData, #offset, #sizeInBytes)
|
||||
;
|
||||
@#C19
|
||||
@#C20
|
||||
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});
|
||||
@#C19
|
||||
@#C20
|
||||
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);
|
||||
@#C13
|
||||
@#C14
|
||||
static get a#offsetOf() → core::int
|
||||
return #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C13
|
||||
return #C16.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C14
|
||||
static get #sizeOf() → core::int
|
||||
return #C21.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
}
|
||||
static method main() → void {
|
||||
final self::MyStruct myStruct = new self::MyStruct::#fromTypedDataBase(typ::Uint8List::•(self::MyStruct::#sizeOf), #C14);
|
||||
final self::MyStruct myStruct = new self::MyStruct::#fromTypedDataBase(typ::Uint8List::•(self::MyStruct::#sizeOf), #C15);
|
||||
self::myNative#C(myStruct);
|
||||
final self::MyUnion myUnion = new self::MyUnion::#fromTypedDataBase(typ::Uint8List::•(self::MyUnion::#sizeOf), #C14);
|
||||
final self::MyUnion myUnion = new self::MyUnion::#fromTypedDataBase(typ::Uint8List::•(self::MyUnion::#sizeOf), #C15);
|
||||
self::myNative2#C(myUnion);
|
||||
self::myNative3#C(myStruct.{self::MyStruct::a}{ffi::Array<ffi::Int8>});
|
||||
}
|
||||
@#C27
|
||||
@#C29
|
||||
@#C28
|
||||
@#C30
|
||||
external static method myNative(ffi::Pointer<self::MyStruct> pointer) → void;
|
||||
@#C32
|
||||
@#C33
|
||||
@#C34
|
||||
external static method myNative2(ffi::Pointer<self::MyUnion> pointer) → void;
|
||||
@#C36
|
||||
@#C37
|
||||
@#C38
|
||||
external static method myNative3(ffi::Pointer<ffi::Int8> pointer) → void;
|
||||
@#C27
|
||||
@#C29
|
||||
@#C28
|
||||
@#C30
|
||||
external static method myNative#C(ffi::_Compound pointer) → void;
|
||||
@#C32
|
||||
@#C33
|
||||
@#C34
|
||||
external static method myNative2#C(ffi::_Compound pointer) → void;
|
||||
@#C36
|
||||
@#C37
|
||||
@#C38
|
||||
external static method myNative3#C(ffi::_Compound pointer) → void;
|
||||
constants {
|
||||
#C1 = "vm:ffi:struct-fields"
|
||||
@@ -88,33 +88,34 @@ constants {
|
||||
#C6 = null
|
||||
#C7 = ffi::_FfiStructLayout {fieldTypes:#C5, packing:#C6}
|
||||
#C8 = core::pragma {name:#C1, options:#C7}
|
||||
#C9 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C3, dimension2:#C6, dimension3:#C6, dimension4:#C6, dimension5:#C6, dimensions:#C6}
|
||||
#C10 = <core::int>[]
|
||||
#C11 = <core::int>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
|
||||
#C12 = "vm:prefer-inline"
|
||||
#C13 = core::pragma {name:#C12, options:#C6}
|
||||
#C14 = 0
|
||||
#C15 = <core::int>[#C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14, #C14]
|
||||
#C16 = <core::Type>[#C2]
|
||||
#C17 = ffi::_FfiStructLayout {fieldTypes:#C16, packing:#C6}
|
||||
#C18 = core::pragma {name:#C1, options:#C17}
|
||||
#C19 = ffi::Int8 {}
|
||||
#C20 = 1
|
||||
#C21 = <core::int>[#C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20]
|
||||
#C22 = "cfe:ffi:native-marker"
|
||||
#C23 = "myNative"
|
||||
#C24 = "#lib"
|
||||
#C25 = true
|
||||
#C26 = ffi::Native<(ffi::Pointer<self::MyStruct>) → ffi::Void> {symbol:#C23, assetId:#C24, isLeaf:#C25}
|
||||
#C27 = core::pragma {name:#C22, options:#C26}
|
||||
#C28 = "vm:ffi:native"
|
||||
#C29 = core::pragma {name:#C28, options:#C26}
|
||||
#C30 = "myNative2"
|
||||
#C31 = ffi::Native<(ffi::Pointer<self::MyUnion>) → ffi::Void> {symbol:#C30, assetId:#C24, isLeaf:#C25}
|
||||
#C32 = core::pragma {name:#C22, options:#C31}
|
||||
#C33 = core::pragma {name:#C28, options:#C31}
|
||||
#C34 = "myNative3"
|
||||
#C35 = ffi::Native<(ffi::Pointer<ffi::Int8>) → ffi::Void> {symbol:#C34, assetId:#C24, isLeaf:#C25}
|
||||
#C36 = core::pragma {name:#C22, options:#C35}
|
||||
#C37 = core::pragma {name:#C28, options:#C35}
|
||||
#C9 = false
|
||||
#C10 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C3, dimension2:#C6, dimension3:#C6, dimension4:#C6, dimension5:#C6, dimensions:#C6, variableLength:#C9}
|
||||
#C11 = <core::int>[]
|
||||
#C12 = <core::int>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
|
||||
#C13 = "vm:prefer-inline"
|
||||
#C14 = core::pragma {name:#C13, options:#C6}
|
||||
#C15 = 0
|
||||
#C16 = <core::int>[#C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15, #C15]
|
||||
#C17 = <core::Type>[#C2]
|
||||
#C18 = ffi::_FfiStructLayout {fieldTypes:#C17, packing:#C6}
|
||||
#C19 = core::pragma {name:#C1, options:#C18}
|
||||
#C20 = ffi::Int8 {}
|
||||
#C21 = 1
|
||||
#C22 = <core::int>[#C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21]
|
||||
#C23 = "cfe:ffi:native-marker"
|
||||
#C24 = "myNative"
|
||||
#C25 = "#lib"
|
||||
#C26 = true
|
||||
#C27 = ffi::Native<(ffi::Pointer<self::MyStruct>) → ffi::Void> {symbol:#C24, assetId:#C25, isLeaf:#C26}
|
||||
#C28 = core::pragma {name:#C23, options:#C27}
|
||||
#C29 = "vm:ffi:native"
|
||||
#C30 = core::pragma {name:#C29, options:#C27}
|
||||
#C31 = "myNative2"
|
||||
#C32 = ffi::Native<(ffi::Pointer<self::MyUnion>) → ffi::Void> {symbol:#C31, assetId:#C25, isLeaf:#C26}
|
||||
#C33 = core::pragma {name:#C23, options:#C32}
|
||||
#C34 = core::pragma {name:#C29, options:#C32}
|
||||
#C35 = "myNative3"
|
||||
#C36 = ffi::Native<(ffi::Pointer<ffi::Int8>) → ffi::Void> {symbol:#C35, assetId:#C25, isLeaf:#C26}
|
||||
#C37 = core::pragma {name:#C23, options:#C36}
|
||||
#C38 = core::pragma {name:#C29, options:#C36}
|
||||
}
|
||||
|
||||
@@ -29,35 +29,35 @@ final class MyStruct extends ffi::Struct {
|
||||
@#C11
|
||||
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);
|
||||
@#C12
|
||||
@#C13
|
||||
get array() → ffi::Array<ffi::Int8>
|
||||
return new ffi::Array::_<ffi::Int8>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C13);
|
||||
@#C12
|
||||
return new ffi::Array::_<ffi::Int8>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C14);
|
||||
@#C13
|
||||
set array(synthesized ffi::Array<ffi::Int8> #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}, #C14.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C12
|
||||
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}, #C15.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C13
|
||||
get array2() → ffi::Array<ffi::UnsignedLong>
|
||||
return new ffi::Array::_<ffi::UnsignedLong>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array2#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C13);
|
||||
@#C12
|
||||
return new ffi::Array::_<ffi::UnsignedLong>(this.{ffi::_Compound::_typedDataBase}{core::Object}, self::MyStruct::array2#offsetOf.{core::num::+}(this.{ffi::_Compound::_offsetInBytes}{core::int}){(core::num) → core::num}, #C3, #C14);
|
||||
@#C13
|
||||
set array2(synthesized ffi::Array<ffi::UnsignedLong> #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}, #C17.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C19
|
||||
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}, #C18.{core::List::[]}(ffi::_abi()){(core::int) → core::int});
|
||||
@#C20
|
||||
static get a#offsetOf() → core::int
|
||||
return #C21.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C19
|
||||
return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C20
|
||||
static get b#offsetOf() → core::int
|
||||
return #C23.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C19
|
||||
return #C24.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C20
|
||||
static get array#offsetOf() → core::int
|
||||
return #C25.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C19
|
||||
return #C26.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C20
|
||||
static get array2#offsetOf() → core::int
|
||||
return #C28.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C19
|
||||
return #C29.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C20
|
||||
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};
|
||||
}
|
||||
@#C34
|
||||
@#C35
|
||||
final class MyUnion extends ffi::Union {
|
||||
synthetic constructor •() → self::MyUnion
|
||||
: super ffi::Union::•()
|
||||
@@ -80,41 +80,41 @@ final class MyUnion extends ffi::Union {
|
||||
@#C11
|
||||
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);
|
||||
@#C19
|
||||
@#C20
|
||||
static get a#offsetOf() → core::int
|
||||
return #C21.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C19
|
||||
return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C20
|
||||
static get b#offsetOf() → core::int
|
||||
return #C21.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C19
|
||||
return #C22.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
@#C20
|
||||
static get #sizeOf() → core::int
|
||||
return #C23.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
return #C24.{core::List::[]}(ffi::_abi()){(core::int) → core::int};
|
||||
}
|
||||
static method main() → void {
|
||||
final self::MyStruct myStruct = new self::MyStruct::#fromTypedDataBase(typ::Uint8List::•(self::MyStruct::#sizeOf), #C20);
|
||||
final self::MyStruct myStruct = new self::MyStruct::#fromTypedDataBase(typ::Uint8List::•(self::MyStruct::#sizeOf), #C21);
|
||||
self::myNative#CC( block {
|
||||
synthesized ffi::_Compound pointer#value = myStruct;
|
||||
} =>new ffi::_Compound::_fromTypedDataBase(pointer#value.{ffi::_Compound::_typedDataBase}{core::Object}, pointer#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(self::MyStruct::a#offsetOf){(core::num) → core::num}), block {
|
||||
synthesized ffi::_Compound pointer2#value = myStruct;
|
||||
} =>new ffi::_Compound::_fromTypedDataBase(pointer2#value.{ffi::_Compound::_typedDataBase}{core::Object}, pointer2#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(self::MyStruct::b#offsetOf){(core::num) → core::num}));
|
||||
final self::MyUnion myUnion = new self::MyUnion::#fromTypedDataBase(typ::Uint8List::•(self::MyUnion::#sizeOf), #C20);
|
||||
final self::MyUnion myUnion = new self::MyUnion::#fromTypedDataBase(typ::Uint8List::•(self::MyUnion::#sizeOf), #C21);
|
||||
self::myNative#CC(myUnion, myUnion);
|
||||
self::myNative#CC( block {
|
||||
synthesized ffi::_Compound pointer#value = myStruct.{self::MyStruct::array}{ffi::Array<ffi::Int8>};
|
||||
} =>new ffi::_Compound::_fromTypedDataBase(pointer#value.{ffi::_Compound::_typedDataBase}{core::Object}, pointer#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#C22.{core::num::*}(3){(core::num) → core::num}){(core::num) → core::num}), block {
|
||||
} =>new ffi::_Compound::_fromTypedDataBase(pointer#value.{ffi::_Compound::_typedDataBase}{core::Object}, pointer#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#C23.{core::num::*}(3){(core::num) → core::num}){(core::num) → core::num}), block {
|
||||
synthesized ffi::_Compound pointer2#value = myStruct.{self::MyStruct::array}{ffi::Array<ffi::Int8>};
|
||||
} =>new ffi::_Compound::_fromTypedDataBase(pointer2#value.{ffi::_Compound::_typedDataBase}{core::Object}, pointer2#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#C22.{core::num::*}(4){(core::num) → core::num}){(core::num) → core::num}));
|
||||
} =>new ffi::_Compound::_fromTypedDataBase(pointer2#value.{ffi::_Compound::_typedDataBase}{core::Object}, pointer2#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(#C23.{core::num::*}(4){(core::num) → core::num}){(core::num) → core::num}));
|
||||
self::myNative#CC( block {
|
||||
synthesized ffi::_Compound pointer#value = myStruct.{self::MyStruct::array2}{ffi::Array<ffi::UnsignedLong>};
|
||||
} =>new ffi::_Compound::_fromTypedDataBase(pointer#value.{ffi::_Compound::_typedDataBase}{core::Object}, pointer#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(ffi::UnsignedLong::#sizeOf.{core::num::*}(3){(core::num) → core::num}){(core::num) → core::num}), block {
|
||||
synthesized ffi::_Compound pointer2#value = myStruct.{self::MyStruct::array2}{ffi::Array<ffi::UnsignedLong>};
|
||||
} =>new ffi::_Compound::_fromTypedDataBase(pointer2#value.{ffi::_Compound::_typedDataBase}{core::Object}, pointer2#value.{ffi::_Compound::_offsetInBytes}{core::int}.{core::num::+}(ffi::UnsignedLong::#sizeOf.{core::num::*}(4){(core::num) → core::num}){(core::num) → core::num}));
|
||||
}
|
||||
@#C40
|
||||
@#C42
|
||||
@#C41
|
||||
@#C43
|
||||
external static method myNative(ffi::Pointer<ffi::Int8> pointer, ffi::Pointer<ffi::Int8> pointer2) → void;
|
||||
@#C40
|
||||
@#C42
|
||||
@#C41
|
||||
@#C43
|
||||
external static method myNative#CC(ffi::_Compound pointer, ffi::_Compound pointer2) → void;
|
||||
constants {
|
||||
#C1 = "vm:ffi:struct-fields"
|
||||
@@ -128,35 +128,36 @@ constants {
|
||||
#C9 = ffi::_FfiStructLayout {fieldTypes:#C7, packing:#C8}
|
||||
#C10 = core::pragma {name:#C1, options:#C9}
|
||||
#C11 = ffi::Int8 {}
|
||||
#C12 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C3, dimension2:#C8, dimension3:#C8, dimension4:#C8, dimension5:#C8, dimensions:#C8}
|
||||
#C13 = <core::int>[]
|
||||
#C14 = <core::int>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
|
||||
#C15 = 40
|
||||
#C16 = 80
|
||||
#C17 = <core::int>[#C15, #C16, #C15, #C16, #C16, #C16, #C16, #C16, #C15, #C16, #C16, #C15, #C16, #C15, #C16, #C15, #C16, #C16, #C16, #C15, #C15, #C15]
|
||||
#C18 = "vm:prefer-inline"
|
||||
#C19 = core::pragma {name:#C18, options:#C8}
|
||||
#C20 = 0
|
||||
#C21 = <core::int>[#C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20, #C20]
|
||||
#C22 = 1
|
||||
#C23 = <core::int>[#C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22, #C22]
|
||||
#C24 = 2
|
||||
#C25 = <core::int>[#C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24, #C24]
|
||||
#C26 = 12
|
||||
#C27 = 16
|
||||
#C28 = <core::int>[#C26, #C27, #C26, #C27, #C27, #C27, #C27, #C27, #C26, #C27, #C27, #C26, #C27, #C26, #C27, #C26, #C27, #C27, #C27, #C26, #C26, #C26]
|
||||
#C29 = 52
|
||||
#C30 = 96
|
||||
#C31 = <core::int>[#C29, #C30, #C29, #C30, #C30, #C30, #C30, #C30, #C29, #C30, #C30, #C29, #C30, #C29, #C30, #C29, #C30, #C30, #C30, #C29, #C29, #C29]
|
||||
#C32 = <core::Type>[#C2, #C2]
|
||||
#C33 = ffi::_FfiStructLayout {fieldTypes:#C32, packing:#C8}
|
||||
#C34 = core::pragma {name:#C1, options:#C33}
|
||||
#C35 = "cfe:ffi:native-marker"
|
||||
#C36 = "myNative"
|
||||
#C37 = "#lib"
|
||||
#C38 = true
|
||||
#C39 = ffi::Native<(ffi::Pointer<ffi::Int8>, ffi::Pointer<ffi::Int8>) → ffi::Void> {symbol:#C36, assetId:#C37, isLeaf:#C38}
|
||||
#C40 = core::pragma {name:#C35, options:#C39}
|
||||
#C41 = "vm:ffi:native"
|
||||
#C42 = core::pragma {name:#C41, options:#C39}
|
||||
#C12 = false
|
||||
#C13 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C3, dimension2:#C8, dimension3:#C8, dimension4:#C8, dimension5:#C8, dimensions:#C8, variableLength:#C12}
|
||||
#C14 = <core::int>[]
|
||||
#C15 = <core::int>[#C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3, #C3]
|
||||
#C16 = 40
|
||||
#C17 = 80
|
||||
#C18 = <core::int>[#C16, #C17, #C16, #C17, #C17, #C17, #C17, #C17, #C16, #C17, #C17, #C16, #C17, #C16, #C17, #C16, #C17, #C17, #C17, #C16, #C16, #C16]
|
||||
#C19 = "vm:prefer-inline"
|
||||
#C20 = core::pragma {name:#C19, options:#C8}
|
||||
#C21 = 0
|
||||
#C22 = <core::int>[#C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21, #C21]
|
||||
#C23 = 1
|
||||
#C24 = <core::int>[#C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23, #C23]
|
||||
#C25 = 2
|
||||
#C26 = <core::int>[#C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25, #C25]
|
||||
#C27 = 12
|
||||
#C28 = 16
|
||||
#C29 = <core::int>[#C27, #C28, #C27, #C28, #C28, #C28, #C28, #C28, #C27, #C28, #C28, #C27, #C28, #C27, #C28, #C27, #C28, #C28, #C28, #C27, #C27, #C27]
|
||||
#C30 = 52
|
||||
#C31 = 96
|
||||
#C32 = <core::int>[#C30, #C31, #C30, #C31, #C31, #C31, #C31, #C31, #C30, #C31, #C31, #C30, #C31, #C30, #C31, #C30, #C31, #C31, #C31, #C30, #C30, #C30]
|
||||
#C33 = <core::Type>[#C2, #C2]
|
||||
#C34 = ffi::_FfiStructLayout {fieldTypes:#C33, packing:#C8}
|
||||
#C35 = core::pragma {name:#C1, options:#C34}
|
||||
#C36 = "cfe:ffi:native-marker"
|
||||
#C37 = "myNative"
|
||||
#C38 = "#lib"
|
||||
#C39 = true
|
||||
#C40 = ffi::Native<(ffi::Pointer<ffi::Int8>, ffi::Pointer<ffi::Int8>) → ffi::Void> {symbol:#C37, assetId:#C38, isLeaf:#C39}
|
||||
#C41 = core::pragma {name:#C36, options:#C40}
|
||||
#C42 = "vm:ffi:native"
|
||||
#C43 = core::pragma {name:#C42, options:#C40}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ constants {
|
||||
#C39 = 1
|
||||
#C40 = 2
|
||||
#C41 = 3
|
||||
#C42 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C39, dimension2:#C40, dimension3:#C41, dimension4:#C4, dimension5:#C4, dimensions:#C4}
|
||||
#C42 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C39, dimension2:#C40, dimension3:#C41, dimension4:#C4, dimension5:#C4, dimensions:#C4, variableLength:#C24}
|
||||
#C43 = "manyNumbers"
|
||||
#C44 = ffi::Native<ffi::Array<ffi::Array<ffi::Array<ffi::Double>>>> {symbol:#C43, assetId:#C23, isLeaf:#C24}
|
||||
#C45 = core::pragma {name:#C21, options:#C44}
|
||||
|
||||
@@ -578,6 +578,26 @@ struct StructInlineArrayInt {
|
||||
wchar_t a0[10];
|
||||
};
|
||||
|
||||
struct StructInlineArrayVariable {
|
||||
uint32_t a0;
|
||||
uint8_t a1[];
|
||||
};
|
||||
|
||||
struct StructInlineArrayVariableNested {
|
||||
uint32_t a0;
|
||||
uint8_t a1[][2][2];
|
||||
};
|
||||
|
||||
struct StructInlineArrayVariableNestedDeep {
|
||||
uint32_t a0;
|
||||
uint8_t a1[][2][2][2][2][2][2];
|
||||
};
|
||||
|
||||
struct StructInlineArrayVariableAlign {
|
||||
uint8_t a0;
|
||||
uint32_t a1[];
|
||||
};
|
||||
|
||||
// Used for testing structs and unions by value.
|
||||
// Smallest struct with data.
|
||||
// 10 struct arguments will exhaust available registers.
|
||||
@@ -4894,6 +4914,73 @@ PassPointerStruct12BytesHomogeneousInt32(Struct12BytesHomogeneousInt32* a0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Used for testing structs and unions by value.
|
||||
// Variable length array
|
||||
DART_EXPORT int64_t
|
||||
PassPointerStructInlineArrayVariable(StructInlineArrayVariable* a0) {
|
||||
std::cout << "PassPointerStructInlineArrayVariable"
|
||||
<< "((" << a0->a0 << ", [" << static_cast<int>(a0->a1[0]) << ", "
|
||||
<< static_cast<int>(a0->a1[1]) << ", "
|
||||
<< static_cast<int>(a0->a1[2]) << ", "
|
||||
<< static_cast<int>(a0->a1[3]) << ", "
|
||||
<< static_cast<int>(a0->a1[4]) << ", "
|
||||
<< static_cast<int>(a0->a1[5]) << ", "
|
||||
<< static_cast<int>(a0->a1[6]) << ", "
|
||||
<< static_cast<int>(a0->a1[7]) << ", "
|
||||
<< static_cast<int>(a0->a1[8]) << ", "
|
||||
<< static_cast<int>(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.
|
||||
// Variable length array with variable length element having more alignment than
|
||||
// the rest of the struct.
|
||||
DART_EXPORT int64_t
|
||||
PassPointerStructInlineArrayVariableAlign(StructInlineArrayVariableAlign* a0) {
|
||||
std::cout << "PassPointerStructInlineArrayVariableAlign"
|
||||
<< "((" << static_cast<int>(a0->a0) << ", [" << a0->a1[0] << ", "
|
||||
<< a0->a1[1] << ", " << a0->a1[2] << ", " << a0->a1[3] << ", "
|
||||
<< a0->a1[4] << ", " << a0->a1[5] << ", " << a0->a1[6] << ", "
|
||||
<< a0->a1[7] << ", " << a0->a1[8] << ", " << 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) {
|
||||
@@ -12630,8 +12717,9 @@ DART_EXPORT intptr_t TestPassInt64x7Struct12BytesHomogeneousInt32(
|
||||
DART_EXPORT intptr_t TestPassPointerStruct12BytesHomogeneousInt32(
|
||||
// NOLINTNEXTLINE(whitespace/parens)
|
||||
int64_t (*f)(Struct12BytesHomogeneousInt32* a0)) {
|
||||
Struct12BytesHomogeneousInt32 a0_value = {};
|
||||
Struct12BytesHomogeneousInt32* a0 = &a0_value;
|
||||
Struct12BytesHomogeneousInt32* a0 =
|
||||
static_cast<Struct12BytesHomogeneousInt32*>(
|
||||
calloc(1, sizeof(Struct12BytesHomogeneousInt32)));
|
||||
|
||||
a0->a0 = -1;
|
||||
a0->a1 = 2;
|
||||
@@ -12661,6 +12749,120 @@ DART_EXPORT intptr_t TestPassPointerStruct12BytesHomogeneousInt32(
|
||||
|
||||
CHECK_EQ(0, result);
|
||||
|
||||
free(a0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Used for testing structs and unions by value.
|
||||
// Variable length array
|
||||
DART_EXPORT intptr_t TestPassPointerStructInlineArrayVariable(
|
||||
// NOLINTNEXTLINE(whitespace/parens)
|
||||
int64_t (*f)(StructInlineArrayVariable* a0)) {
|
||||
StructInlineArrayVariable* a0 = static_cast<StructInlineArrayVariable*>(
|
||||
calloc(1, sizeof(StructInlineArrayVariable) + 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 TestPassPointerStructInlineArrayVariable("
|
||||
<< "((" << a0->a0 << ", [" << static_cast<int>(a0->a1[0]) << ", "
|
||||
<< static_cast<int>(a0->a1[1]) << ", "
|
||||
<< static_cast<int>(a0->a1[2]) << ", "
|
||||
<< static_cast<int>(a0->a1[3]) << ", "
|
||||
<< static_cast<int>(a0->a1[4]) << ", "
|
||||
<< static_cast<int>(a0->a1[5]) << ", "
|
||||
<< static_cast<int>(a0->a1[6]) << ", "
|
||||
<< static_cast<int>(a0->a1[7]) << ", "
|
||||
<< static_cast<int>(a0->a1[8]) << ", "
|
||||
<< static_cast<int>(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.
|
||||
// Variable length array with variable length element having more alignment than
|
||||
// the rest of the struct.
|
||||
DART_EXPORT intptr_t TestPassPointerStructInlineArrayVariableAlign(
|
||||
// NOLINTNEXTLINE(whitespace/parens)
|
||||
int64_t (*f)(StructInlineArrayVariableAlign* a0)) {
|
||||
StructInlineArrayVariableAlign* a0 =
|
||||
static_cast<StructInlineArrayVariableAlign*>(calloc(
|
||||
1, sizeof(StructInlineArrayVariableAlign) + 10 * sizeof(uint32_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 TestPassPointerStructInlineArrayVariableAlign("
|
||||
<< "((" << static_cast<int>(a0->a0) << ", [" << a0->a1[0] << ", "
|
||||
<< a0->a1[1] << ", " << a0->a1[2] << ", " << a0->a1[3] << ", "
|
||||
<< a0->a1[4] << ", " << a0->a1[5] << ", " << a0->a1[6] << ", "
|
||||
<< a0->a1[7] << ", " << a0->a1[8] << ", " << 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;
|
||||
}
|
||||
|
||||
@@ -21287,8 +21489,9 @@ DART_EXPORT void TestAsyncPassInt64x7Struct12BytesHomogeneousInt32(
|
||||
DART_EXPORT void TestAsyncPassPointerStruct12BytesHomogeneousInt32(
|
||||
// NOLINTNEXTLINE(whitespace/parens)
|
||||
void (*f)(Struct12BytesHomogeneousInt32* a0)) {
|
||||
Struct12BytesHomogeneousInt32 a0_value = {};
|
||||
Struct12BytesHomogeneousInt32* a0 = &a0_value;
|
||||
Struct12BytesHomogeneousInt32* a0 =
|
||||
static_cast<Struct12BytesHomogeneousInt32*>(
|
||||
calloc(1, sizeof(Struct12BytesHomogeneousInt32)));
|
||||
|
||||
a0->a0 = -1;
|
||||
a0->a1 = 2;
|
||||
@@ -21299,6 +21502,80 @@ DART_EXPORT void TestAsyncPassPointerStruct12BytesHomogeneousInt32(
|
||||
<< ")\n";
|
||||
|
||||
f(a0);
|
||||
|
||||
free(a0);
|
||||
}
|
||||
|
||||
// Used for testing structs and unions by value.
|
||||
// Variable length array
|
||||
DART_EXPORT void TestAsyncPassPointerStructInlineArrayVariable(
|
||||
// NOLINTNEXTLINE(whitespace/parens)
|
||||
void (*f)(StructInlineArrayVariable* a0)) {
|
||||
StructInlineArrayVariable* a0 = static_cast<StructInlineArrayVariable*>(
|
||||
calloc(1, sizeof(StructInlineArrayVariable) + 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 TestAsyncPassPointerStructInlineArrayVariable("
|
||||
<< "((" << a0->a0 << ", [" << static_cast<int>(a0->a1[0]) << ", "
|
||||
<< static_cast<int>(a0->a1[1]) << ", "
|
||||
<< static_cast<int>(a0->a1[2]) << ", "
|
||||
<< static_cast<int>(a0->a1[3]) << ", "
|
||||
<< static_cast<int>(a0->a1[4]) << ", "
|
||||
<< static_cast<int>(a0->a1[5]) << ", "
|
||||
<< static_cast<int>(a0->a1[6]) << ", "
|
||||
<< static_cast<int>(a0->a1[7]) << ", "
|
||||
<< static_cast<int>(a0->a1[8]) << ", "
|
||||
<< static_cast<int>(a0->a1[9]) << "]))"
|
||||
<< ")\n";
|
||||
|
||||
f(a0);
|
||||
|
||||
free(a0);
|
||||
}
|
||||
|
||||
// Used for testing structs and unions by value.
|
||||
// Variable length array with variable length element having more alignment than
|
||||
// the rest of the struct.
|
||||
DART_EXPORT void TestAsyncPassPointerStructInlineArrayVariableAlign(
|
||||
// NOLINTNEXTLINE(whitespace/parens)
|
||||
void (*f)(StructInlineArrayVariableAlign* a0)) {
|
||||
StructInlineArrayVariableAlign* a0 =
|
||||
static_cast<StructInlineArrayVariableAlign*>(calloc(
|
||||
1, sizeof(StructInlineArrayVariableAlign) + 10 * sizeof(uint32_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 TestAsyncPassPointerStructInlineArrayVariableAlign("
|
||||
<< "((" << static_cast<int>(a0->a0) << ", [" << a0->a1[0] << ", "
|
||||
<< a0->a1[1] << ", " << a0->a1[2] << ", " << a0->a1[3] << ", "
|
||||
<< a0->a1[4] << ", " << a0->a1[5] << ", " << a0->a1[6] << ", "
|
||||
<< a0->a1[7] << ", " << a0->a1[8] << ", " << a0->a1[9] << "]))"
|
||||
<< ")\n";
|
||||
|
||||
f(a0);
|
||||
|
||||
free(a0);
|
||||
}
|
||||
|
||||
// Used for testing structs and unions by value.
|
||||
|
||||
@@ -344,7 +344,12 @@ final class Array<T extends NativeType> extends _Compound {
|
||||
List<int> get _nestedDimensionsRest =>
|
||||
_nestedDimensionsRestCache ??= _nestedDimensions.sublist(1);
|
||||
|
||||
static const _variableLengthLength = 0;
|
||||
|
||||
void _checkIndex(int index) {
|
||||
if (_size == _variableLengthLength) {
|
||||
return;
|
||||
}
|
||||
if (index < 0 || index >= _size) {
|
||||
throw RangeError.range(index, 0, _size - 1);
|
||||
}
|
||||
|
||||
+140
-6
@@ -88,7 +88,7 @@ final class Pointer<T extends NativeType> implements SizedNativeType {
|
||||
/// A fixed-sized array of [T]s.
|
||||
@Since('2.13')
|
||||
final class Array<T extends NativeType> extends _Compound {
|
||||
/// Const constructor to specify [Array] dimensions in [Struct]s.
|
||||
/// Annotation to specify [Array] dimensions in [Struct]s.
|
||||
///
|
||||
/// ```dart
|
||||
/// final class MyStruct extends Struct {
|
||||
@@ -107,7 +107,7 @@ final class Array<T extends NativeType> extends _Compound {
|
||||
int dimension4,
|
||||
int dimension5]) = _ArraySize<T>;
|
||||
|
||||
/// Const constructor to specify [Array] dimensions in [Struct]s.
|
||||
/// Annotation to specify [Array] dimensions in [Struct]s.
|
||||
///
|
||||
/// ```dart
|
||||
/// final class MyStruct extends Struct {
|
||||
@@ -121,6 +121,97 @@ final class Array<T extends NativeType> extends _Compound {
|
||||
///
|
||||
/// Do not invoke in normal code.
|
||||
const factory Array.multi(List<int> dimensions) = _ArraySize<T>.multi;
|
||||
|
||||
/// Annotation to specify a variable length [Array] in [Struct]s.
|
||||
///
|
||||
/// Can only be used on the last field of a struct. The last field of the
|
||||
/// struct is _not_ taken into account in [sizeOf]. Using an
|
||||
/// [AllocatorAlloc.call] will _not_ allocate any backing storage for the
|
||||
/// variable length array. Instead use [Allocator.allocate] and calculate the
|
||||
/// required number of bytes manually.
|
||||
///
|
||||
/// ```dart
|
||||
/// import 'dart:ffi';
|
||||
/// import 'package:ffi/ffi.dart';
|
||||
///
|
||||
/// final class MyStruct extends Struct {
|
||||
/// @Size()
|
||||
/// external int length;
|
||||
///
|
||||
/// @Array.variable()
|
||||
/// external Array<Uint8> inlineArray;
|
||||
///
|
||||
/// static Pointer<MyStruct> allocate(Allocator allocator, int length) {
|
||||
/// final lengthInBytes = sizeOf<MyStruct>() + sizeOf<Uint8>() * length;
|
||||
/// final result = allocator.allocate<MyStruct>(lengthInBytes);
|
||||
/// result.ref.length = length;
|
||||
/// return result;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// void main() {
|
||||
/// final myStruct = MyStruct.allocate(calloc, 10);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The variable lenght is always the outermost dimension of the array.
|
||||
///
|
||||
/// ```dart
|
||||
/// import 'dart:ffi';
|
||||
/// import 'package:ffi/ffi.dart';
|
||||
///
|
||||
/// final class MyStruct extends Struct {
|
||||
/// @Size()
|
||||
/// external int length;
|
||||
///
|
||||
/// @Array.variable(10, 10)
|
||||
/// external Array<Array<Array<Uint8>>> inlineArray;
|
||||
///
|
||||
/// static Pointer<MyStruct> allocate(Allocator allocator, int length) {
|
||||
/// final lengthInBytes = sizeOf<MyStruct>() + sizeOf<Uint8>() * length * 100;
|
||||
/// final result = allocator.allocate<MyStruct>(lengthInBytes);
|
||||
/// result.ref.length = length;
|
||||
/// return result;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Accessing variable length inline arrays of structs passed by value in FFI
|
||||
/// calls and callbacks is undefined behavior. Accessing variable length
|
||||
/// inline arrays in structs passed by value is undefined behavior in C.
|
||||
///
|
||||
/// For more information about variable length inline arrays in C, please
|
||||
/// refer to: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html.
|
||||
///
|
||||
/// Do not invoke in normal code.
|
||||
@Since('3.6')
|
||||
const factory Array.variable([
|
||||
int dimension2,
|
||||
int dimension3,
|
||||
int dimension4,
|
||||
int dimension5,
|
||||
]) = _ArraySize<T>.variable;
|
||||
|
||||
/// Annotation to a variable length [Array] in [Struct]s.
|
||||
///
|
||||
/// ```dart
|
||||
/// final class MyStruct extends Struct {
|
||||
/// @Array.variableMulti([2, 2])
|
||||
/// external Array<Array<Array<Uint8>>> threeDimensionalInlineArray;
|
||||
/// }
|
||||
///
|
||||
/// final class MyStruct2 extends Struct {
|
||||
/// @Array.variableMulti([2, 2, 2, 2, 2, 2, 2])
|
||||
/// external Array<Array<Array<Array<Array<Array<Array<Array<Uint8>>>>>>>> eightDimensionalInlineArray;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The variable lenght is always the outermost dimension of the array.
|
||||
///
|
||||
/// Do not invoke in normal code.
|
||||
@Since('3.6')
|
||||
const factory Array.variableMulti(List<int> dimensions) =
|
||||
_ArraySize<T>.variableMulti;
|
||||
}
|
||||
|
||||
final class _ArraySize<T extends NativeType> implements Array<T> {
|
||||
@@ -132,16 +223,59 @@ final class _ArraySize<T extends NativeType> implements Array<T> {
|
||||
|
||||
final List<int>? dimensions;
|
||||
|
||||
const _ArraySize(this.dimension1,
|
||||
[this.dimension2, this.dimension3, this.dimension4, this.dimension5])
|
||||
: dimensions = null;
|
||||
// When `true`, [dimension1] is [variableLengthLength], or [dimensions]
|
||||
// should be prepended with [variableLengthLength].
|
||||
final bool variableLength;
|
||||
|
||||
const _ArraySize(
|
||||
this.dimension1, [
|
||||
this.dimension2,
|
||||
this.dimension3,
|
||||
this.dimension4,
|
||||
this.dimension5,
|
||||
]) : dimensions = null,
|
||||
variableLength = false;
|
||||
|
||||
const _ArraySize.multi(this.dimensions)
|
||||
: dimension1 = null,
|
||||
dimension2 = null,
|
||||
dimension3 = null,
|
||||
dimension4 = null,
|
||||
dimension5 = 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;
|
||||
|
||||
const _ArraySize.variable([
|
||||
this.dimension2,
|
||||
this.dimension3,
|
||||
this.dimension4,
|
||||
this.dimension5,
|
||||
]) : dimension1 = variableLengthLength,
|
||||
dimensions = null,
|
||||
variableLength = true;
|
||||
|
||||
const _ArraySize.variableMulti(List<int> nestedDimensions)
|
||||
: dimensions = nestedDimensions, // Should be `[0, ...nestedDimensions]`.
|
||||
dimension1 = null,
|
||||
dimension2 = null,
|
||||
dimension3 = null,
|
||||
dimension4 = null,
|
||||
dimension5 = null,
|
||||
variableLength = true;
|
||||
}
|
||||
|
||||
/// Extension on [Pointer] specialized for the type argument [NativeFunction].
|
||||
|
||||
@@ -382,6 +382,16 @@ final testCases = [
|
||||
Pointer.fromFunction<PassPointerStruct12BytesHomogeneousInt32Type>(
|
||||
passPointerStruct12BytesHomogeneousInt32, 0),
|
||||
noChecks),
|
||||
CallbackTest.withCheck(
|
||||
"PassPointerStructInlineArrayVariable",
|
||||
Pointer.fromFunction<PassPointerStructInlineArrayVariableType>(
|
||||
passPointerStructInlineArrayVariable, 0),
|
||||
noChecks),
|
||||
CallbackTest.withCheck(
|
||||
"PassPointerStructInlineArrayVariableAlign",
|
||||
Pointer.fromFunction<PassPointerStructInlineArrayVariableAlignType>(
|
||||
passPointerStructInlineArrayVariableAlign, 0),
|
||||
noChecks),
|
||||
CallbackTest.withCheck(
|
||||
"ReturnStruct1ByteInt",
|
||||
Pointer.fromFunction<ReturnStruct1ByteIntType>(returnStruct1ByteInt),
|
||||
@@ -7970,6 +7980,109 @@ int passPointerStruct12BytesHomogeneousInt32(
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef PassPointerStructInlineArrayVariableType = Int64 Function(
|
||||
Pointer<StructInlineArrayVariable>);
|
||||
|
||||
// Global variables to be able to test inputs after callback returned.
|
||||
Pointer<StructInlineArrayVariable> passPointerStructInlineArrayVariable_a0 =
|
||||
nullptr;
|
||||
|
||||
// Result variable also global, so we can delete it after the callback.
|
||||
int passPointerStructInlineArrayVariableResult = 0;
|
||||
|
||||
int passPointerStructInlineArrayVariableCalculateResult() {
|
||||
int result = 0;
|
||||
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a0;
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[0];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[1];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[2];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[3];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[4];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[5];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[6];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[7];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[8];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[9];
|
||||
|
||||
passPointerStructInlineArrayVariableResult = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Variable length array
|
||||
int passPointerStructInlineArrayVariable(
|
||||
Pointer<StructInlineArrayVariable> a0) {
|
||||
print("passPointerStructInlineArrayVariable(${a0})");
|
||||
|
||||
// Possibly throw.
|
||||
if (a0.ref.a0 == 42 || a0.ref.a0 == 84) {
|
||||
print("throwing!");
|
||||
throw Exception(
|
||||
"PassPointerStructInlineArrayVariable throwing on purpose!");
|
||||
}
|
||||
|
||||
passPointerStructInlineArrayVariable_a0 = a0;
|
||||
|
||||
final result = passPointerStructInlineArrayVariableCalculateResult();
|
||||
|
||||
print("result = $result");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef PassPointerStructInlineArrayVariableAlignType = Int64 Function(
|
||||
Pointer<StructInlineArrayVariableAlign>);
|
||||
|
||||
// Global variables to be able to test inputs after callback returned.
|
||||
Pointer<StructInlineArrayVariableAlign>
|
||||
passPointerStructInlineArrayVariableAlign_a0 = nullptr;
|
||||
|
||||
// Result variable also global, so we can delete it after the callback.
|
||||
int passPointerStructInlineArrayVariableAlignResult = 0;
|
||||
|
||||
int passPointerStructInlineArrayVariableAlignCalculateResult() {
|
||||
int result = 0;
|
||||
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a0;
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[0];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[1];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[2];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[3];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[4];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[5];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[6];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[7];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[8];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[9];
|
||||
|
||||
passPointerStructInlineArrayVariableAlignResult = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Variable length array with variable length element having more alignment than
|
||||
/// the rest of the struct.
|
||||
int passPointerStructInlineArrayVariableAlign(
|
||||
Pointer<StructInlineArrayVariableAlign> a0) {
|
||||
print("passPointerStructInlineArrayVariableAlign(${a0})");
|
||||
|
||||
// Possibly throw.
|
||||
if (a0.ref.a0 == 42 || a0.ref.a0 == 84) {
|
||||
print("throwing!");
|
||||
throw Exception(
|
||||
"PassPointerStructInlineArrayVariableAlign throwing on purpose!");
|
||||
}
|
||||
|
||||
passPointerStructInlineArrayVariableAlign_a0 = a0;
|
||||
|
||||
final result = passPointerStructInlineArrayVariableAlignCalculateResult();
|
||||
|
||||
print("result = $result");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef ReturnStruct1ByteIntType = Struct1ByteInt Function(Int8);
|
||||
|
||||
// Global variables to be able to test inputs after callback returned.
|
||||
|
||||
@@ -457,6 +457,19 @@ final testCases = [
|
||||
passPointerStruct12BytesHomogeneousInt32,
|
||||
exceptionalReturn: 0),
|
||||
noChecks),
|
||||
CallbackTest.withCheck(
|
||||
"PassPointerStructInlineArrayVariable",
|
||||
NativeCallable<PassPointerStructInlineArrayVariableType>.isolateLocal(
|
||||
passPointerStructInlineArrayVariable,
|
||||
exceptionalReturn: 0),
|
||||
noChecks),
|
||||
CallbackTest.withCheck(
|
||||
"PassPointerStructInlineArrayVariableAlign",
|
||||
NativeCallable<
|
||||
PassPointerStructInlineArrayVariableAlignType>.isolateLocal(
|
||||
passPointerStructInlineArrayVariableAlign,
|
||||
exceptionalReturn: 0),
|
||||
noChecks),
|
||||
CallbackTest.withCheck(
|
||||
"ReturnStruct1ByteInt",
|
||||
NativeCallable<ReturnStruct1ByteIntType>.isolateLocal(
|
||||
@@ -8055,6 +8068,109 @@ int passPointerStruct12BytesHomogeneousInt32(
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef PassPointerStructInlineArrayVariableType = Int64 Function(
|
||||
Pointer<StructInlineArrayVariable>);
|
||||
|
||||
// Global variables to be able to test inputs after callback returned.
|
||||
Pointer<StructInlineArrayVariable> passPointerStructInlineArrayVariable_a0 =
|
||||
nullptr;
|
||||
|
||||
// Result variable also global, so we can delete it after the callback.
|
||||
int passPointerStructInlineArrayVariableResult = 0;
|
||||
|
||||
int passPointerStructInlineArrayVariableCalculateResult() {
|
||||
int result = 0;
|
||||
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a0;
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[0];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[1];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[2];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[3];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[4];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[5];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[6];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[7];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[8];
|
||||
result += passPointerStructInlineArrayVariable_a0.ref.a1[9];
|
||||
|
||||
passPointerStructInlineArrayVariableResult = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Variable length array
|
||||
int passPointerStructInlineArrayVariable(
|
||||
Pointer<StructInlineArrayVariable> a0) {
|
||||
print("passPointerStructInlineArrayVariable(${a0})");
|
||||
|
||||
// Possibly throw.
|
||||
if (a0.ref.a0 == 42 || a0.ref.a0 == 84) {
|
||||
print("throwing!");
|
||||
throw Exception(
|
||||
"PassPointerStructInlineArrayVariable throwing on purpose!");
|
||||
}
|
||||
|
||||
passPointerStructInlineArrayVariable_a0 = a0;
|
||||
|
||||
final result = passPointerStructInlineArrayVariableCalculateResult();
|
||||
|
||||
print("result = $result");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef PassPointerStructInlineArrayVariableAlignType = Int64 Function(
|
||||
Pointer<StructInlineArrayVariableAlign>);
|
||||
|
||||
// Global variables to be able to test inputs after callback returned.
|
||||
Pointer<StructInlineArrayVariableAlign>
|
||||
passPointerStructInlineArrayVariableAlign_a0 = nullptr;
|
||||
|
||||
// Result variable also global, so we can delete it after the callback.
|
||||
int passPointerStructInlineArrayVariableAlignResult = 0;
|
||||
|
||||
int passPointerStructInlineArrayVariableAlignCalculateResult() {
|
||||
int result = 0;
|
||||
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a0;
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[0];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[1];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[2];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[3];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[4];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[5];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[6];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[7];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[8];
|
||||
result += passPointerStructInlineArrayVariableAlign_a0.ref.a1[9];
|
||||
|
||||
passPointerStructInlineArrayVariableAlignResult = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Variable length array with variable length element having more alignment than
|
||||
/// the rest of the struct.
|
||||
int passPointerStructInlineArrayVariableAlign(
|
||||
Pointer<StructInlineArrayVariableAlign> a0) {
|
||||
print("passPointerStructInlineArrayVariableAlign(${a0})");
|
||||
|
||||
// Possibly throw.
|
||||
if (a0.ref.a0 == 42 || a0.ref.a0 == 84) {
|
||||
print("throwing!");
|
||||
throw Exception(
|
||||
"PassPointerStructInlineArrayVariableAlign throwing on purpose!");
|
||||
}
|
||||
|
||||
passPointerStructInlineArrayVariableAlign_a0 = a0;
|
||||
|
||||
final result = passPointerStructInlineArrayVariableAlignCalculateResult();
|
||||
|
||||
print("result = $result");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef ReturnStruct1ByteIntType = Struct1ByteInt Function(Int8);
|
||||
|
||||
// Global variables to be able to test inputs after callback returned.
|
||||
|
||||
@@ -93,6 +93,8 @@ void main() {
|
||||
testPassWCharStructInlineArrayIntUintPtrx2LongUnsignedLeaf();
|
||||
testPassInt64x7Struct12BytesHomogeneousInt32Leaf();
|
||||
testPassPointerStruct12BytesHomogeneousInt32Leaf();
|
||||
testPassPointerStructInlineArrayVariableLeaf();
|
||||
testPassPointerStructInlineArrayVariableAlignLeaf();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5509,7 +5511,8 @@ final passPointerStruct12BytesHomogeneousInt32Leaf =
|
||||
|
||||
/// Passing a pointer to a struct
|
||||
void testPassPointerStruct12BytesHomogeneousInt32Leaf() {
|
||||
final a0 = calloc<Struct12BytesHomogeneousInt32>();
|
||||
final a0 = calloc.allocate<Struct12BytesHomogeneousInt32>(
|
||||
sizeOf<Struct12BytesHomogeneousInt32>());
|
||||
|
||||
a0.ref.a0 = -1;
|
||||
a0.ref.a1 = 2;
|
||||
@@ -5523,3 +5526,70 @@ void testPassPointerStruct12BytesHomogeneousInt32Leaf() {
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
final passPointerStructInlineArrayVariableLeaf =
|
||||
ffiTestFunctions.lookupFunction<
|
||||
Int64 Function(Pointer<StructInlineArrayVariable>),
|
||||
int Function(Pointer<StructInlineArrayVariable>)>(
|
||||
"PassPointerStructInlineArrayVariable",
|
||||
isLeaf: true);
|
||||
|
||||
/// Variable length array
|
||||
void testPassPointerStructInlineArrayVariableLeaf() {
|
||||
final a0 = calloc.allocate<StructInlineArrayVariable>(
|
||||
sizeOf<StructInlineArrayVariable>() + 10 * sizeOf<Uint8>());
|
||||
|
||||
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 = passPointerStructInlineArrayVariableLeaf(a0);
|
||||
|
||||
print("result = $result");
|
||||
|
||||
Expect.equals(66, result);
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
final passPointerStructInlineArrayVariableAlignLeaf =
|
||||
ffiTestFunctions.lookupFunction<
|
||||
Int64 Function(Pointer<StructInlineArrayVariableAlign>),
|
||||
int Function(Pointer<StructInlineArrayVariableAlign>)>(
|
||||
"PassPointerStructInlineArrayVariableAlign",
|
||||
isLeaf: true);
|
||||
|
||||
/// Variable length array with variable length element having more alignment than
|
||||
/// the rest of the struct.
|
||||
void testPassPointerStructInlineArrayVariableAlignLeaf() {
|
||||
final a0 = calloc.allocate<StructInlineArrayVariableAlign>(
|
||||
sizeOf<StructInlineArrayVariableAlign>() + 10 * sizeOf<Uint32>());
|
||||
|
||||
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 = passPointerStructInlineArrayVariableAlignLeaf(a0);
|
||||
|
||||
print("result = $result");
|
||||
|
||||
Expect.equals(66, result);
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,8 @@ void main() {
|
||||
testPassWCharStructInlineArrayIntUintPtrx2LongUnsignedNativeLeaf();
|
||||
testPassInt64x7Struct12BytesHomogeneousInt32NativeLeaf();
|
||||
testPassPointerStruct12BytesHomogeneousInt32NativeLeaf();
|
||||
testPassPointerStructInlineArrayVariableNativeLeaf();
|
||||
testPassPointerStructInlineArrayVariableAlignNativeLeaf();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5471,7 +5473,8 @@ external int passPointerStruct12BytesHomogeneousInt32NativeLeaf(
|
||||
|
||||
/// Passing a pointer to a struct
|
||||
void testPassPointerStruct12BytesHomogeneousInt32NativeLeaf() {
|
||||
final a0 = calloc<Struct12BytesHomogeneousInt32>();
|
||||
final a0 = calloc.allocate<Struct12BytesHomogeneousInt32>(
|
||||
sizeOf<Struct12BytesHomogeneousInt32>());
|
||||
|
||||
a0.ref.a0 = -1;
|
||||
a0.ref.a1 = 2;
|
||||
@@ -5485,3 +5488,66 @@ void testPassPointerStruct12BytesHomogeneousInt32NativeLeaf() {
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
@Native<Int64 Function(Pointer<StructInlineArrayVariable>)>(
|
||||
symbol: 'PassPointerStructInlineArrayVariable', isLeaf: true)
|
||||
external int passPointerStructInlineArrayVariableNativeLeaf(
|
||||
Pointer<StructInlineArrayVariable> a0);
|
||||
|
||||
/// Variable length array
|
||||
void testPassPointerStructInlineArrayVariableNativeLeaf() {
|
||||
final a0 = calloc.allocate<StructInlineArrayVariable>(
|
||||
sizeOf<StructInlineArrayVariable>() + 10 * sizeOf<Uint8>());
|
||||
|
||||
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 = passPointerStructInlineArrayVariableNativeLeaf(a0);
|
||||
|
||||
print("result = $result");
|
||||
|
||||
Expect.equals(66, result);
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
@Native<Int64 Function(Pointer<StructInlineArrayVariableAlign>)>(
|
||||
symbol: 'PassPointerStructInlineArrayVariableAlign', isLeaf: true)
|
||||
external int passPointerStructInlineArrayVariableAlignNativeLeaf(
|
||||
Pointer<StructInlineArrayVariableAlign> a0);
|
||||
|
||||
/// Variable length array with variable length element having more alignment than
|
||||
/// the rest of the struct.
|
||||
void testPassPointerStructInlineArrayVariableAlignNativeLeaf() {
|
||||
final a0 = calloc.allocate<StructInlineArrayVariableAlign>(
|
||||
sizeOf<StructInlineArrayVariableAlign>() + 10 * sizeOf<Uint32>());
|
||||
|
||||
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 = passPointerStructInlineArrayVariableAlignNativeLeaf(a0);
|
||||
|
||||
print("result = $result");
|
||||
|
||||
Expect.equals(66, result);
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,8 @@ void main() {
|
||||
testPassWCharStructInlineArrayIntUintPtrx2LongUnsignedNative();
|
||||
testPassInt64x7Struct12BytesHomogeneousInt32Native();
|
||||
testPassPointerStruct12BytesHomogeneousInt32Native();
|
||||
testPassPointerStructInlineArrayVariableNative();
|
||||
testPassPointerStructInlineArrayVariableAlignNative();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5481,7 +5483,8 @@ external int passPointerStruct12BytesHomogeneousInt32Native(
|
||||
|
||||
/// Passing a pointer to a struct
|
||||
void testPassPointerStruct12BytesHomogeneousInt32Native() {
|
||||
final a0 = calloc<Struct12BytesHomogeneousInt32>();
|
||||
final a0 = calloc.allocate<Struct12BytesHomogeneousInt32>(
|
||||
sizeOf<Struct12BytesHomogeneousInt32>());
|
||||
|
||||
a0.ref.a0 = -1;
|
||||
a0.ref.a1 = 2;
|
||||
@@ -5495,3 +5498,66 @@ void testPassPointerStruct12BytesHomogeneousInt32Native() {
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
@Native<Int64 Function(Pointer<StructInlineArrayVariable>)>(
|
||||
symbol: 'PassPointerStructInlineArrayVariable')
|
||||
external int passPointerStructInlineArrayVariableNative(
|
||||
Pointer<StructInlineArrayVariable> a0);
|
||||
|
||||
/// Variable length array
|
||||
void testPassPointerStructInlineArrayVariableNative() {
|
||||
final a0 = calloc.allocate<StructInlineArrayVariable>(
|
||||
sizeOf<StructInlineArrayVariable>() + 10 * sizeOf<Uint8>());
|
||||
|
||||
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 = passPointerStructInlineArrayVariableNative(a0);
|
||||
|
||||
print("result = $result");
|
||||
|
||||
Expect.equals(66, result);
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
@Native<Int64 Function(Pointer<StructInlineArrayVariableAlign>)>(
|
||||
symbol: 'PassPointerStructInlineArrayVariableAlign')
|
||||
external int passPointerStructInlineArrayVariableAlignNative(
|
||||
Pointer<StructInlineArrayVariableAlign> a0);
|
||||
|
||||
/// Variable length array with variable length element having more alignment than
|
||||
/// the rest of the struct.
|
||||
void testPassPointerStructInlineArrayVariableAlignNative() {
|
||||
final a0 = calloc.allocate<StructInlineArrayVariableAlign>(
|
||||
sizeOf<StructInlineArrayVariableAlign>() + 10 * sizeOf<Uint32>());
|
||||
|
||||
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 = passPointerStructInlineArrayVariableAlignNative(a0);
|
||||
|
||||
print("result = $result");
|
||||
|
||||
Expect.equals(66, result);
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
@@ -93,6 +93,8 @@ void main() {
|
||||
testPassWCharStructInlineArrayIntUintPtrx2LongUnsigned();
|
||||
testPassInt64x7Struct12BytesHomogeneousInt32();
|
||||
testPassPointerStruct12BytesHomogeneousInt32();
|
||||
testPassPointerStructInlineArrayVariable();
|
||||
testPassPointerStructInlineArrayVariableAlign();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5430,7 +5432,8 @@ final passPointerStruct12BytesHomogeneousInt32 =
|
||||
|
||||
/// Passing a pointer to a struct
|
||||
void testPassPointerStruct12BytesHomogeneousInt32() {
|
||||
final a0 = calloc<Struct12BytesHomogeneousInt32>();
|
||||
final a0 = calloc.allocate<Struct12BytesHomogeneousInt32>(
|
||||
sizeOf<Struct12BytesHomogeneousInt32>());
|
||||
|
||||
a0.ref.a0 = -1;
|
||||
a0.ref.a1 = 2;
|
||||
@@ -5444,3 +5447,67 @@ void testPassPointerStruct12BytesHomogeneousInt32() {
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
final passPointerStructInlineArrayVariable = ffiTestFunctions.lookupFunction<
|
||||
Int64 Function(Pointer<StructInlineArrayVariable>),
|
||||
int Function(Pointer<StructInlineArrayVariable>)>(
|
||||
"PassPointerStructInlineArrayVariable");
|
||||
|
||||
/// Variable length array
|
||||
void testPassPointerStructInlineArrayVariable() {
|
||||
final a0 = calloc.allocate<StructInlineArrayVariable>(
|
||||
sizeOf<StructInlineArrayVariable>() + 10 * sizeOf<Uint8>());
|
||||
|
||||
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 = passPointerStructInlineArrayVariable(a0);
|
||||
|
||||
print("result = $result");
|
||||
|
||||
Expect.equals(66, result);
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
final passPointerStructInlineArrayVariableAlign =
|
||||
ffiTestFunctions.lookupFunction<
|
||||
Int64 Function(Pointer<StructInlineArrayVariableAlign>),
|
||||
int Function(Pointer<StructInlineArrayVariableAlign>)>(
|
||||
"PassPointerStructInlineArrayVariableAlign");
|
||||
|
||||
/// Variable length array with variable length element having more alignment than
|
||||
/// the rest of the struct.
|
||||
void testPassPointerStructInlineArrayVariableAlign() {
|
||||
final a0 = calloc.allocate<StructInlineArrayVariableAlign>(
|
||||
sizeOf<StructInlineArrayVariableAlign>() + 10 * sizeOf<Uint32>());
|
||||
|
||||
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 = passPointerStructInlineArrayVariableAlign(a0);
|
||||
|
||||
print("result = $result");
|
||||
|
||||
Expect.equals(66, result);
|
||||
|
||||
calloc.free(a0);
|
||||
}
|
||||
|
||||
@@ -1277,3 +1277,43 @@ final class StructInlineArrayInt extends Struct {
|
||||
|
||||
String toString() => "(${[for (var i0 = 0; i0 < 10; i0 += 1) a0[i0]]})";
|
||||
}
|
||||
|
||||
final class StructInlineArrayVariable extends Struct {
|
||||
@Uint32()
|
||||
external int a0;
|
||||
|
||||
@Array.variable()
|
||||
external Array<Uint8> a1;
|
||||
|
||||
String toString() => "(${a0}, ${a1})";
|
||||
}
|
||||
|
||||
final class StructInlineArrayVariableNested extends Struct {
|
||||
@Uint32()
|
||||
external int a0;
|
||||
|
||||
@Array.variable(2, 2)
|
||||
external Array<Array<Array<Uint8>>> a1;
|
||||
|
||||
String toString() => "(${a0}, ${a1})";
|
||||
}
|
||||
|
||||
final class StructInlineArrayVariableNestedDeep extends Struct {
|
||||
@Uint32()
|
||||
external int a0;
|
||||
|
||||
@Array.variableMulti([2, 2, 2, 2, 2, 2])
|
||||
external Array<Array<Array<Array<Array<Array<Array<Uint8>>>>>>> a1;
|
||||
|
||||
String toString() => "(${a0}, ${a1})";
|
||||
}
|
||||
|
||||
final class StructInlineArrayVariableAlign extends Struct {
|
||||
@Uint8()
|
||||
external int a0;
|
||||
|
||||
@Array.variable()
|
||||
external Array<Uint32> a1;
|
||||
|
||||
String toString() => "(${a0}, ${a1})";
|
||||
}
|
||||
|
||||
@@ -247,7 +247,8 @@ class Member {
|
||||
String postFix = "";
|
||||
if (type is FixedLengthArrayType) {
|
||||
final dimensions = (type as FixedLengthArrayType).dimensions;
|
||||
postFix = "[${dimensions.join("][")}]";
|
||||
postFix =
|
||||
"[${dimensions.map((d) => d == 0 ? '' : d.toString()).join("][")}]";
|
||||
}
|
||||
return "${type.cType} $name$postFix;";
|
||||
}
|
||||
@@ -479,6 +480,26 @@ class FixedLengthArrayType extends CType {
|
||||
bool get isOnlyBool => elementType.isOnlyBool;
|
||||
}
|
||||
|
||||
class VariableLengthArrayType extends FixedLengthArrayType {
|
||||
VariableLengthArrayType(
|
||||
CType elementType,
|
||||
) : super(elementType, 0);
|
||||
|
||||
factory VariableLengthArrayType.multi(
|
||||
CType elementType, List<int> fixedDimensions) {
|
||||
final nestedArray =
|
||||
FixedLengthArrayType.multi(elementType, fixedDimensions);
|
||||
return VariableLengthArrayType(nestedArray);
|
||||
}
|
||||
|
||||
String get dartStructFieldAnnotation {
|
||||
if (dimensions.length > 5) {
|
||||
return "@Array.variableMulti([${dimensions.skip(1).join(", ")}])";
|
||||
}
|
||||
return "@Array.variable(${dimensions.skip(1).join(", ")})";
|
||||
}
|
||||
}
|
||||
|
||||
class FunctionType extends CType {
|
||||
final List<Member> arguments;
|
||||
final int? varArgsIndex;
|
||||
|
||||
@@ -457,6 +457,21 @@ Struct stradles last argument register"""),
|
||||
int64,
|
||||
"""
|
||||
Passing a pointer to a struct"""),
|
||||
FunctionType(
|
||||
[
|
||||
PointerType(structVariableLengthArray),
|
||||
],
|
||||
int64,
|
||||
"""
|
||||
Variable length array"""),
|
||||
FunctionType(
|
||||
[
|
||||
PointerType(structVariableLengthArray4),
|
||||
],
|
||||
int64,
|
||||
"""
|
||||
Variable length array with variable length element having more alignment than
|
||||
the rest of the struct."""),
|
||||
];
|
||||
|
||||
/// Functions that return a struct by value.
|
||||
@@ -711,6 +726,10 @@ final compounds = [
|
||||
union16bytesFloat,
|
||||
union16bytesFloat2,
|
||||
structArrayWChar,
|
||||
structVariableLengthArray,
|
||||
structVariableLengthArray2,
|
||||
structVariableLengthArray3,
|
||||
structVariableLengthArray4,
|
||||
];
|
||||
|
||||
/// Function signatures for variadic argument tests.
|
||||
@@ -1061,3 +1080,35 @@ final union16bytesFloat2 =
|
||||
|
||||
/// This struct contains an AbiSpecificInt type.
|
||||
final structArrayWChar = StructType([FixedLengthArrayType(wchar, 10)]);
|
||||
|
||||
final structVariableLengthArray = StructType.override(
|
||||
[
|
||||
uint32,
|
||||
VariableLengthArrayType(uint8),
|
||||
],
|
||||
"InlineArrayVariable",
|
||||
);
|
||||
|
||||
final structVariableLengthArray2 = StructType.override(
|
||||
[
|
||||
uint32,
|
||||
VariableLengthArrayType.multi(uint8, [2, 2]),
|
||||
],
|
||||
"InlineArrayVariableNested",
|
||||
);
|
||||
|
||||
final structVariableLengthArray3 = StructType.override(
|
||||
[
|
||||
uint32,
|
||||
VariableLengthArrayType.multi(uint8, [2, 2, 2, 2, 2, 2]),
|
||||
],
|
||||
"InlineArrayVariableNestedDeep",
|
||||
);
|
||||
|
||||
final structVariableLengthArray4 = StructType.override(
|
||||
[
|
||||
uint8,
|
||||
VariableLengthArrayType(uint32),
|
||||
],
|
||||
"InlineArrayVariableAlign",
|
||||
);
|
||||
|
||||
@@ -76,8 +76,13 @@ extension on CType {
|
||||
return this_.members.take(1).toList().coutExpression("$variableName.");
|
||||
|
||||
case FixedLengthArrayType:
|
||||
case VariableLengthArrayType:
|
||||
final this_ = this as FixedLengthArrayType;
|
||||
final indices = [for (var i = 0; i < this_.length; i += 1) i];
|
||||
final int length = switch (this_) {
|
||||
VariableLengthArrayType _ => _variableLengthLength,
|
||||
FixedLengthArrayType _ => this_.length,
|
||||
};
|
||||
final indices = [for (var i = 0; i < length; i += 1) i];
|
||||
|
||||
String result = '<< "["';
|
||||
result += indices
|
||||
@@ -144,8 +149,13 @@ extension on CType {
|
||||
.addToResultStatements("$variableName.${member.name}", isDart);
|
||||
|
||||
case FixedLengthArrayType:
|
||||
case VariableLengthArrayType:
|
||||
final this_ = this as FixedLengthArrayType;
|
||||
final indices = [for (var i = 0; i < this_.length; i += 1) i];
|
||||
final int length = switch (this_) {
|
||||
VariableLengthArrayType _ => _variableLengthLength,
|
||||
FixedLengthArrayType _ => this_.length,
|
||||
};
|
||||
final indices = [for (var i = 0; i < length; i += 1) i];
|
||||
return indices
|
||||
.map((i) => this_.elementType
|
||||
.addToResultStatements("$variableName[$i]", isDart))
|
||||
@@ -192,8 +202,13 @@ extension on CType {
|
||||
.assignValueStatements(a, "$variableName.${member.name}", isDart);
|
||||
|
||||
case FixedLengthArrayType:
|
||||
case VariableLengthArrayType:
|
||||
final this_ = this as FixedLengthArrayType;
|
||||
final indices = [for (var i = 0; i < this_.length; i += 1) i];
|
||||
final int length = switch (this_) {
|
||||
VariableLengthArrayType _ => _variableLengthLength,
|
||||
FixedLengthArrayType _ => this_.length,
|
||||
};
|
||||
final indices = [for (var i = 0; i < length; i += 1) i];
|
||||
return indices
|
||||
.map((i) => this_.elementType
|
||||
.assignValueStatements(a, "$variableName[$i]", isDart))
|
||||
@@ -301,8 +316,14 @@ extension on CType {
|
||||
final pointerTo = this_.pointerTo;
|
||||
switch (pointerTo) {
|
||||
case StructType _:
|
||||
final lastMember = pointerTo.memberTypes.last;
|
||||
final String extraBytes = switch (lastMember) {
|
||||
VariableLengthArrayType _ =>
|
||||
'+ $_variableLengthLength * sizeOf<${lastMember.elementType.dartCType}>()',
|
||||
_ => '',
|
||||
};
|
||||
return '''
|
||||
final ${variableName} = calloc<${pointerTo.dartType}>();
|
||||
final ${variableName} = calloc.allocate<${pointerTo.dartType}>(sizeOf<${pointerTo.dartType}>() $extraBytes);
|
||||
''';
|
||||
}
|
||||
return "\n";
|
||||
@@ -408,15 +429,33 @@ extension on CType {
|
||||
final pointerTo = this_.pointerTo;
|
||||
switch (pointerTo) {
|
||||
case StructType _:
|
||||
final lastMember = pointerTo.memberTypes.last;
|
||||
final String extraBytes = switch (lastMember) {
|
||||
VariableLengthArrayType _ =>
|
||||
'+ $_variableLengthLength * sizeof(${lastMember.elementType.cType})',
|
||||
_ => '',
|
||||
};
|
||||
return '''
|
||||
${pointerTo.cType} ${variableName}_value = {};
|
||||
${cType} ${variableName} = &${variableName}_value;
|
||||
${cType} ${variableName} = static_cast<${cType}>(calloc(1, sizeof(${pointerTo.cType}) $extraBytes));
|
||||
''';
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception("Not implemented for ${this.runtimeType}");
|
||||
}
|
||||
|
||||
String cFreeStatements(String variableName) {
|
||||
switch (this.runtimeType) {
|
||||
case FundamentalType:
|
||||
case StructType:
|
||||
case UnionType:
|
||||
return "";
|
||||
case PointerType:
|
||||
return 'free(${variableName});';
|
||||
}
|
||||
|
||||
throw Exception("Not implemented for ${this.runtimeType}");
|
||||
}
|
||||
}
|
||||
|
||||
extension on List<Member> {
|
||||
@@ -425,6 +464,10 @@ extension on List<Member> {
|
||||
return map((m) => m.type.cAllocateStatements("$namePrefix${m.name}"))
|
||||
.join();
|
||||
}
|
||||
|
||||
String cFreeStatements([String namePrefix = ""]) {
|
||||
return map((m) => m.type.cFreeStatements("$namePrefix${m.name}")).join();
|
||||
}
|
||||
}
|
||||
|
||||
extension on CType {
|
||||
@@ -597,7 +640,8 @@ extension CompositeTypeGenerator on CompositeType {
|
||||
dartFields += "${member.dartStructField()}\n\n";
|
||||
}
|
||||
String toStringBody = members.map((m) {
|
||||
if (m.type is FixedLengthArrayType) {
|
||||
if (m.type is FixedLengthArrayType &&
|
||||
m.type is! VariableLengthArrayType) {
|
||||
int dimensionNumber = 0;
|
||||
String inlineFor = "";
|
||||
String read = m.name;
|
||||
@@ -993,6 +1037,7 @@ $varArgsUnpack
|
||||
String get cCallbackCode {
|
||||
final a = ArgumentValueAssigner();
|
||||
final argumentAllocations = arguments.cAllocateStatements();
|
||||
final argumentFrees = arguments.cFreeStatements();
|
||||
final assignValues = arguments.assignValueStatements(a, false);
|
||||
|
||||
final argumentString = [
|
||||
@@ -1062,6 +1107,8 @@ $varArgsUnpack
|
||||
|
||||
$expectsZero
|
||||
|
||||
$argumentFrees
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1071,6 +1118,7 @@ $varArgsUnpack
|
||||
String get cAsyncCallbackCode {
|
||||
final a = ArgumentValueAssigner();
|
||||
final argumentAllocations = arguments.cAllocateStatements();
|
||||
final argumentFrees = arguments.cFreeStatements();
|
||||
final assignValues = arguments.assignValueStatements(a, false);
|
||||
|
||||
final argumentString = [
|
||||
@@ -1095,6 +1143,8 @@ $varArgsUnpack
|
||||
std::cout << "Calling TestAsync$cName(" ${arguments.coutExpression()} << ")\\n";
|
||||
|
||||
f($argumentNames);
|
||||
|
||||
$argumentFrees
|
||||
}
|
||||
|
||||
""";
|
||||
@@ -1469,3 +1519,6 @@ void main(List<String> arguments) async {
|
||||
writeC(),
|
||||
]);
|
||||
}
|
||||
|
||||
// This test uses this number of elements for variable length arrays.
|
||||
const _variableLengthLength = 10;
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// 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.
|
||||
//
|
||||
// SharedObjects=ffi_test_functions
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
// Reuse compound definitions.
|
||||
import 'function_structs_by_value_generated_compounds.dart';
|
||||
|
||||
void main() {
|
||||
testInlineArray();
|
||||
testInlineArrayNested();
|
||||
testInlineArrayNestedDeep();
|
||||
testSizeOf();
|
||||
}
|
||||
|
||||
void testInlineArray() {
|
||||
const length = 10;
|
||||
final lengthInBytes =
|
||||
sizeOf<StructInlineArrayVariable>() + sizeOf<Uint8>() * length;
|
||||
final pointer = calloc.allocate<StructInlineArrayVariable>(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 testInlineArrayNested() {
|
||||
const length = 10;
|
||||
final lengthInBytes = sizeOf<StructInlineArrayVariableNested>() +
|
||||
sizeOf<Uint8>() * length * 2 * 2;
|
||||
final pointer =
|
||||
calloc.allocate<StructInlineArrayVariableNested>(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 testInlineArrayNestedDeep() {
|
||||
const length = 10;
|
||||
final lengthInBytes = sizeOf<StructInlineArrayVariableNestedDeep>() +
|
||||
sizeOf<Uint8>() * length * 2 * 2 * 2 * 2 * 2 * 2;
|
||||
final pointer =
|
||||
calloc.allocate<StructInlineArrayVariableNestedDeep>(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;
|
||||
}
|
||||
|
||||
final class Foo2 extends Struct {
|
||||
@Int8()
|
||||
external int field0;
|
||||
|
||||
@Array<Uint32>.variable()
|
||||
external Array<Uint32> field1;
|
||||
}
|
||||
|
||||
void testSizeOf() {
|
||||
Expect.equals(1, sizeOf<Foo>());
|
||||
Expect.equals(4, sizeOf<Foo2>());
|
||||
}
|
||||
@@ -382,6 +382,16 @@ final testCases = [
|
||||
Pointer.fromFunction<PassPointerStruct12BytesHomogeneousInt32Type>(
|
||||
passPointerStruct12BytesHomogeneousInt32),
|
||||
noChecksAsync),
|
||||
AsyncCallbackTest(
|
||||
"PassPointerStructInlineArrayVariable",
|
||||
Pointer.fromFunction<PassPointerStructInlineArrayVariableType>(
|
||||
passPointerStructInlineArrayVariable),
|
||||
noChecksAsync),
|
||||
AsyncCallbackTest(
|
||||
"PassPointerStructInlineArrayVariableAlign",
|
||||
Pointer.fromFunction<PassPointerStructInlineArrayVariableAlignType>(
|
||||
passPointerStructInlineArrayVariableAlign),
|
||||
noChecksAsync),
|
||||
AsyncCallbackTest(
|
||||
"ReturnStruct1ByteInt",
|
||||
Pointer.fromFunction<ReturnStruct1ByteIntType>(returnStruct1ByteInt),
|
||||
@@ -5167,6 +5177,77 @@ Future<void> passPointerStruct12BytesHomogeneousInt32AfterCallback() async {
|
||||
Expect.approxEquals(-2, result);
|
||||
}
|
||||
|
||||
typedef PassPointerStructInlineArrayVariableType = Void Function(
|
||||
Pointer<StructInlineArrayVariable>);
|
||||
|
||||
// Global variable that stores the result.
|
||||
final PassPointerStructInlineArrayVariableResult = Completer<double>();
|
||||
|
||||
/// Variable length array
|
||||
void passPointerStructInlineArrayVariable(
|
||||
Pointer<StructInlineArrayVariable> a0) {
|
||||
print("passPointerStructInlineArrayVariable(${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");
|
||||
PassPointerStructInlineArrayVariableResult.complete(result);
|
||||
}
|
||||
|
||||
Future<void> passPointerStructInlineArrayVariableAfterCallback() async {
|
||||
final result = await PassPointerStructInlineArrayVariableResult.future;
|
||||
print("after callback result = $result");
|
||||
Expect.approxEquals(66, result);
|
||||
}
|
||||
|
||||
typedef PassPointerStructInlineArrayVariableAlignType = Void Function(
|
||||
Pointer<StructInlineArrayVariableAlign>);
|
||||
|
||||
// Global variable that stores the result.
|
||||
final PassPointerStructInlineArrayVariableAlignResult = Completer<double>();
|
||||
|
||||
/// Variable length array with variable length element having more alignment than
|
||||
/// the rest of the struct.
|
||||
void passPointerStructInlineArrayVariableAlign(
|
||||
Pointer<StructInlineArrayVariableAlign> a0) {
|
||||
print("passPointerStructInlineArrayVariableAlign(${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");
|
||||
PassPointerStructInlineArrayVariableAlignResult.complete(result);
|
||||
}
|
||||
|
||||
Future<void> passPointerStructInlineArrayVariableAlignAfterCallback() async {
|
||||
final result = await PassPointerStructInlineArrayVariableAlignResult.future;
|
||||
print("after callback result = $result");
|
||||
Expect.approxEquals(66, result);
|
||||
}
|
||||
|
||||
typedef ReturnStruct1ByteIntType = Void Function(Int8);
|
||||
|
||||
// Global variable that stores the result.
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// 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.
|
||||
//
|
||||
// Dart test program for testing dart:ffi extra checks
|
||||
//
|
||||
// SharedObjects=ffi_test_dynamic_library ffi_test_functions
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
void main() {}
|
||||
|
||||
final class TestStruct1 extends Struct {
|
||||
/**/ @Array.variable()
|
||||
// ^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.SIZE_ANNOTATION_DIMENSIONS
|
||||
external Array<Array<Uint8>> a0;
|
||||
// ^
|
||||
// [cfe] Field 'a0' must have an 'Array' annotation that matches the dimensions.
|
||||
}
|
||||
|
||||
final class TestStruct2 extends Struct {
|
||||
/**/ @Array.variable()
|
||||
// ^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.VARIABLE_LENGTH_ARRAY_NOT_LAST
|
||||
external Array<Uint8> a0;
|
||||
// ^
|
||||
// [cfe] Variable length 'Array's must only occur as the last field of Structs.
|
||||
|
||||
@Uint8()
|
||||
external int a1;
|
||||
}
|
||||
|
||||
final class TestStruct3 extends Struct {
|
||||
// This should be a Array.variable() not an `@Array(0)`.
|
||||
@Array(0)
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.NON_POSITIVE_ARRAY_DIMENSION
|
||||
external Array<Uint8> a0;
|
||||
// ^^
|
||||
// [cfe] Array dimensions must be positive numbers.
|
||||
}
|
||||
|
||||
final class TestStruct4 extends Struct {
|
||||
/**/ @Array.variable(1, 2)
|
||||
// ^^^^^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.SIZE_ANNOTATION_DIMENSIONS
|
||||
external Array<Array<Uint8>> a0;
|
||||
// ^
|
||||
// [cfe] Field 'a0' must have an 'Array' annotation that matches the dimensions.
|
||||
}
|
||||
|
||||
final class TestStruct5 extends Struct {
|
||||
/**/ @Array.variableMulti([1, 2])
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.SIZE_ANNOTATION_DIMENSIONS
|
||||
external Array<Array<Uint8>> a0;
|
||||
// ^
|
||||
// [cfe] Field 'a0' must have an 'Array' annotation that matches the dimensions.
|
||||
}
|
||||
|
||||
final class TestStruct6 extends Struct {
|
||||
@Array.variableMulti([1, 2])
|
||||
external Array<Array<Array<Uint8>>> a0;
|
||||
}
|
||||
|
||||
final class TestStruct7 extends Struct {
|
||||
/**/ @Array.variableMulti([1, 2])
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.SIZE_ANNOTATION_DIMENSIONS
|
||||
external Array<Array<Array<Array<Uint8>>>> a0;
|
||||
// ^
|
||||
// [cfe] Field 'a0' must have an 'Array' annotation that matches the dimensions.
|
||||
}
|
||||
Reference in New Issue
Block a user