Skip to content

Commit d45fd0f

Browse files
dcharkescommit-bot@chromium.org
authored andcommitted
[vm/ffi] Support inline arrays in Structs
Adds support for single dimension inline arrays in structs. Multi- dimensional arrays will be supported in a future CL. This CL adds: - CFE static error checks for inline arrays. - CFE transformations for inline arrays. - VM consumption of inline array fields for NativeType. - Test generator support for inline arrays + generated tests. Previous CLs added support for inline arrays in: - analyzer https://dart-review.googlesource.com/c/sdk/+/183684 - updated in this CL to new API. - ABI calculation https://dart-review.googlesource.com/c/sdk/+/183682 Closes: #35763 Open issue: #45101 CFE transformations are tested with expectation files: TEST=pkg/front_end/testcases/(.*)/ffi_struct_inline_array.dart Trampolines and CArray API are tested with end-to-end Dart tests: TEST=tests/ffi(_2)/(.*)by_value(.*)test.dart TEST=tests/ffi(_2)/inline_array_test.dart Compile-time errors (both CFE and analyzer) are tested in: TEST=tests/ffi(_2)/vmspecific_static_checks_test.dart Change-Id: I014c0e4153f1b885638adce80de6ab3cac8e6bb2 Cq-Include-Trybots: luci.dart.try:dart-sdk-linux-try,dart-sdk-mac-try,dart-sdk-win-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-mac-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-ia32-try,vm-kernel-nnbd-mac-release-x64-try,vm-kernel-nnbd-win-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-msan-linux-release-x64-try,vm-kernel-precomp-msan-linux-release-x64-try,vm-kernel-precomp-android-release-arm_x64-try,analyzer-analysis-server-linux-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/183640 Commit-Queue: Daco Harkes <[email protected]> Reviewed-by: Martin Kustermann <[email protected]> Reviewed-by: Clement Skau <[email protected]>
1 parent 3a4a4f5 commit d45fd0f

File tree

42 files changed

+6549
-263
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+6549
-263
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3903,6 +3903,28 @@ Message _withArgumentsFfiNotStatic(String name) {
39033903
arguments: {'name': name});
39043904
}
39053905

3906+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3907+
const Template<Message Function(String name)> templateFfiSizeAnnotation =
3908+
const Template<Message Function(String name)>(
3909+
messageTemplate:
3910+
r"""Field '#name' must have exactly one 'Array' annotation.""",
3911+
withArguments: _withArgumentsFfiSizeAnnotation);
3912+
3913+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3914+
const Code<Message Function(String name)> codeFfiSizeAnnotation =
3915+
const Code<Message Function(String name)>(
3916+
"FfiSizeAnnotation",
3917+
);
3918+
3919+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3920+
Message _withArgumentsFfiSizeAnnotation(String name) {
3921+
if (name.isEmpty) throw 'No name provided';
3922+
name = demangleMixinApplicationName(name);
3923+
return new Message(codeFfiSizeAnnotation,
3924+
message: """Field '${name}' must have exactly one 'Array' annotation.""",
3925+
arguments: {'name': name});
3926+
}
3927+
39063928
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
39073929
const Template<Message Function(String name)> templateFfiStructGeneric =
39083930
const Template<Message Function(String name)>(

pkg/analyzer/lib/src/dart/error/ffi_code.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class FfiCode extends AnalyzerErrorCode {
4444
*/
4545
static const FfiCode EXTRA_SIZE_ANNOTATION_CARRAY = FfiCode(
4646
name: 'EXTRA_SIZE_ANNOTATION_CARRAY',
47-
message: "'CArray's must have exactly one 'CArraySize' annotation.",
47+
message: "'Array's must have exactly one 'Array' annotation.",
4848
correction: "Try removing the extra annotation.");
4949

5050
/**
@@ -94,10 +94,10 @@ class FfiCode extends AnalyzerErrorCode {
9494
name: 'INVALID_FIELD_TYPE_IN_STRUCT',
9595
message:
9696
"Fields in struct classes can't have the type '{0}'. They can only "
97-
"be declared as 'int', 'double', 'CArray', 'Pointer', or subtype of "
97+
"be declared as 'int', 'double', 'Array', 'Pointer', or subtype of "
9898
"'Struct'.",
9999
correction:
100-
"Try using 'int', 'double', 'CArray', 'Pointer', or subtype of "
100+
"Try using 'int', 'double', 'Array', 'Pointer', or subtype of "
101101
"'Struct'.");
102102

103103
/**
@@ -146,8 +146,8 @@ class FfiCode extends AnalyzerErrorCode {
146146
*/
147147
static const FfiCode MISSING_SIZE_ANNOTATION_CARRAY = FfiCode(
148148
name: 'MISSING_SIZE_ANNOTATION_CARRAY',
149-
message: "'CArray's must have exactly one 'CArraySize' annotation.",
150-
correction: "Try adding a 'CArraySize' annotation.");
149+
message: "'Array's must have exactly one 'Array' annotation.",
150+
correction: "Try adding a 'Array' annotation.");
151151

152152
/**
153153
* Parameters:

pkg/analyzer/lib/src/generated/ffi_verifier.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
1818
static const _allocatorClassName = 'Allocator';
1919
static const _allocateExtensionMethodName = 'call';
2020
static const _allocatorExtensionName = 'AllocatorAlloc';
21-
static const _cArrayClassName = 'CArray';
21+
static const _cArrayClassName = 'Array';
2222
static const _dartFfiLibraryName = 'dart.ffi';
2323
static const _opaqueClassName = 'Opaque';
2424

@@ -159,7 +159,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
159159
if (element is MethodElement) {
160160
var enclosingElement = element.enclosingElement;
161161
if (enclosingElement.isNativeStructPointerExtension ||
162-
enclosingElement.isNativeStructCArrayExtension) {
162+
enclosingElement.isNativeStructArrayExtension) {
163163
if (element.name == '[]') {
164164
_validateRefIndexed(node);
165165
}
@@ -279,7 +279,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
279279
bool _isValidFfiNativeType(DartType? nativeType,
280280
{bool allowVoid = false,
281281
bool allowEmptyStruct = false,
282-
bool allowCArray = false}) {
282+
bool allowArray = false}) {
283283
if (nativeType is InterfaceType) {
284284
// Is it a primitive integer/double type (or ffi.Void if we allow it).
285285
final primitiveType = _primitiveNativeType(nativeType);
@@ -310,7 +310,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
310310
if (nativeType.isOpaqueSubtype) {
311311
return true;
312312
}
313-
if (allowCArray && nativeType.isCArray) {
313+
if (allowArray && nativeType.isArray) {
314314
return _isValidFfiNativeType(nativeType.typeArguments.single,
315315
allowVoid: false, allowEmptyStruct: false);
316316
}
@@ -550,7 +550,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
550550
_validateAnnotations(fieldType, annotations, _PrimitiveDartType.double);
551551
} else if (declaredType.isPointer) {
552552
_validateNoAnnotations(annotations);
553-
} else if (declaredType.isCArray) {
553+
} else if (declaredType.isArray) {
554554
final typeArg = (declaredType as InterfaceType).typeArguments.single;
555555
if (!_isSized(typeArg)) {
556556
_errorReporter.reportErrorForNode(FfiCode.NON_SIZED_TYPE_ARGUMENT,
@@ -663,7 +663,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
663663
void _validateRefIndexed(IndexExpression node) {
664664
var targetType = node.realTarget.staticType;
665665
if (!_isValidFfiNativeType(targetType,
666-
allowVoid: false, allowEmptyStruct: true, allowCArray: true)) {
666+
allowVoid: false, allowEmptyStruct: true, allowArray: true)) {
667667
final AstNode errorNode = node;
668668
_errorReporter.reportErrorForNode(
669669
FfiCode.NON_CONSTANT_TYPE_ARGUMENT, errorNode, ['[]']);
@@ -714,7 +714,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
714714
final element = annotation.element;
715715
return element is ConstructorElement &&
716716
element.ffiClass != null &&
717-
element.enclosingElement.name == 'CArraySize';
717+
element.enclosingElement.name == 'Array';
718718
}).toList();
719719

720720
if (ffiSizeAnnotations.isEmpty) {
@@ -766,10 +766,10 @@ extension on Element? {
766766
element.isFfiExtension;
767767
}
768768

769-
bool get isNativeStructCArrayExtension {
769+
bool get isNativeStructArrayExtension {
770770
final element = this;
771771
return element is ExtensionElement &&
772-
element.name == 'StructCArray' &&
772+
element.name == 'StructArray' &&
773773
element.isFfiExtension;
774774
}
775775

@@ -821,7 +821,7 @@ extension on ClassElement {
821821
return false;
822822
} else if (declaredType.isStructSubtype) {
823823
return false;
824-
} else if (declaredType.isCArray) {
824+
} else if (declaredType.isArray) {
825825
return false;
826826
}
827827
}
@@ -840,8 +840,8 @@ extension on ExtensionElement {
840840
}
841841

842842
extension on DartType {
843-
/// Return `true` if this represents the class `CArray`.
844-
bool get isCArray {
843+
/// Return `true` if this represents the class `Array`.
844+
bool get isArray {
845845
final self = this;
846846
if (self is InterfaceType) {
847847
final element = self.element;

pkg/analyzer/lib/src/test_utilities/mock_sdk.dart

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -690,12 +690,8 @@ class DartRepresentationOf {
690690
const DartRepresentationOf(String nativeType);
691691
}
692692
693-
class CArray<T extends NativeType> extends NativeType {}
694-
695-
class CArraySize {
696-
final int numberOfElements;
697-
698-
const CArraySize(this.numberOfElements);
693+
class Array<T extends NativeType> extends NativeType {
694+
external const factory Array(int dimension1);
699695
}
700696
701697
extension StructPointer<T extends Struct> on Pointer<T> {

pkg/analyzer/test/src/diagnostics/extra_size_annotation_carray_test.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ import '../dart/resolution/context_collection_resolution.dart';
99

1010
main() {
1111
defineReflectiveSuite(() {
12-
defineReflectiveTests(ExtraSizeAnnotationCArray);
12+
defineReflectiveTests(ExtraSizeAnnotationArray);
1313
});
1414
}
1515

1616
@reflectiveTest
17-
class ExtraSizeAnnotationCArray extends PubPackageResolutionTest {
17+
class ExtraSizeAnnotationArray extends PubPackageResolutionTest {
1818
test_one() async {
1919
await assertNoErrorsInCode(r'''
2020
import 'dart:ffi';
2121
2222
class C extends Struct {
23-
@CArraySize(8)
24-
CArray<Uint8> a0;
23+
@Array(8)
24+
Array<Uint8> a0;
2525
}
2626
''');
2727
}
@@ -31,12 +31,12 @@ class C extends Struct {
3131
import 'dart:ffi';
3232
3333
class C extends Struct {
34-
@CArraySize(8)
35-
@CArraySize(8)
36-
CArray<Uint8> a0;
34+
@Array(8)
35+
@Array(8)
36+
Array<Uint8> a0;
3737
}
3838
''', [
39-
error(FfiCode.EXTRA_SIZE_ANNOTATION_CARRAY, 64, 14),
39+
error(FfiCode.EXTRA_SIZE_ANNOTATION_CARRAY, 59, 9),
4040
]);
4141
}
4242
}

pkg/analyzer/test/src/diagnostics/missing_size_annotation_carray_test.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ import '../dart/resolution/context_collection_resolution.dart';
99

1010
main() {
1111
defineReflectiveSuite(() {
12-
defineReflectiveTests(MissingSizeAnnotationCArray);
12+
defineReflectiveTests(MissingSizeAnnotationArray);
1313
});
1414
}
1515

1616
@reflectiveTest
17-
class MissingSizeAnnotationCArray extends PubPackageResolutionTest {
17+
class MissingSizeAnnotationArray extends PubPackageResolutionTest {
1818
test_one() async {
1919
await assertNoErrorsInCode(r'''
2020
import 'dart:ffi';
2121
2222
class C extends Struct {
23-
@CArraySize(8)
24-
CArray<Uint8> a0;
23+
@Array(8)
24+
Array<Uint8> a0;
2525
}
2626
''');
2727
}
@@ -31,10 +31,10 @@ class C extends Struct {
3131
import 'dart:ffi';
3232
3333
class C extends Struct {
34-
CArray<Uint8> a0;
34+
Array<Uint8> a0;
3535
}
3636
''', [
37-
error(FfiCode.MISSING_SIZE_ANNOTATION_CARRAY, 47, 13),
37+
error(FfiCode.MISSING_SIZE_ANNOTATION_CARRAY, 47, 12),
3838
]);
3939
}
4040
}

pkg/analyzer/test/src/diagnostics/non_sized_type_argument_test.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ class NonSizedTypeArgument extends PubPackageResolutionTest {
2020
import 'dart:ffi';
2121
2222
class C extends Struct {
23-
@CArraySize(8)
24-
CArray<Uint8> a0;
23+
@Array(8)
24+
Array<Uint8> a0;
2525
}
2626
''');
2727
}
@@ -31,11 +31,11 @@ class C extends Struct {
3131
import 'dart:ffi';
3232
3333
class C extends Struct {
34-
@CArraySize(8)
35-
CArray<CArray<Uint8>> a0;
34+
@Array(8)
35+
Array<Array<Uint8>> a0;
3636
}
3737
''', [
38-
error(FfiCode.NON_SIZED_TYPE_ARGUMENT, 64, 21),
38+
error(FfiCode.NON_SIZED_TYPE_ARGUMENT, 59, 19),
3939
]);
4040
}
4141
}

pkg/front_end/lib/src/api_unstable/vm.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export '../fasta/fasta_codes.dart'
6464
templateFfiFieldNoAnnotation,
6565
templateFfiFieldNull,
6666
templateFfiNotStatic,
67+
templateFfiSizeAnnotation,
6768
templateFfiStructGeneric,
6869
templateFfiTypeInvalid,
6970
templateFfiTypeMismatch;

pkg/front_end/messages.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ FfiFieldInitializer/analyzerCode: Fail
329329
FfiFieldNoAnnotation/analyzerCode: Fail
330330
FfiFieldNull/analyzerCode: Fail
331331
FfiNotStatic/analyzerCode: Fail
332+
FfiSizeAnnotation/analyzerCode: Fail
332333
FfiStructAnnotation/analyzerCode: Fail
333334
FfiStructGeneric/analyzerCode: Fail
334335
FfiTypeInvalid/analyzerCode: Fail

pkg/front_end/messages.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4263,6 +4263,11 @@ FfiExtendsOrImplementsSealedClass:
42634263
template: "Class '#name' cannot be extended or implemented."
42644264
external: test/ffi_test.dart
42654265

4266+
FfiSizeAnnotation:
4267+
# Used by dart:ffi
4268+
template: "Field '#name' must have exactly one 'Array' annotation."
4269+
external: test/ffi_test.dart
4270+
42664271
FfiStructGeneric:
42674272
# Used by dart:ffi
42684273
template: "Struct '#name' should not be generic."
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:ffi';
6+
7+
import "package:ffi/ffi.dart";
8+
9+
class StructInlineArray extends Struct {
10+
@Array(8)
11+
external Array<Uint8> a0;
12+
}
13+
14+
main() {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:ffi" as ffi;
4+
5+
import "dart:ffi";
6+
import "package:ffi/ffi.dart";
7+
8+
class StructInlineArray extends ffi::Struct {
9+
synthetic constructor •() → self::StructInlineArray
10+
: super ffi::Struct::•()
11+
;
12+
@#C2
13+
external get a0() → ffi::Array<ffi::Uint8>;
14+
@#C2
15+
external set a0(ffi::Array<ffi::Uint8> #externalFieldValue) → void;
16+
}
17+
static method main() → dynamic {}
18+
19+
constants {
20+
#C1 = 8
21+
#C2 = ffi::_ArraySize<ffi::NativeType> {dimension1:#C1}
22+
}
23+
24+
25+
Constructor coverage from constants:
26+
org-dartlang-testcase:///ffi_struct_inline_array.dart:
27+
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:107:9)

0 commit comments

Comments
 (0)