Skip to content

Commit fc6cb0a

Browse files
sjindel-googlecommit-bot@chromium.org
authored andcommitted
[vm/ffi] Revamp struct representation in FFI.
See dartbug.com/37229 for details. Change-Id: I63490e41c512ffc9312803985a6f6d4be1586c0a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101291 Commit-Queue: Samir Jindel <sjindel@google.com> Reviewed-by: Daco Harkes <dacoharkes@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
1 parent 5fd51b9 commit fc6cb0a

Some content is hidden

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

49 files changed

+1071
-1035
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,16 @@ export '../fasta/fasta_codes.dart'
3737
messageBytecodeLimitExceededTooManyArguments,
3838
noLength,
3939
templateFfiFieldAnnotation,
40-
templateFfiStructAnnotation,
4140
templateFfiNotStatic,
4241
templateFfiTypeInvalid,
4342
templateFfiTypeMismatch,
4443
templateFfiTypeUnsized,
4544
templateFfiFieldInitializer,
4645
templateIllegalRecursiveType,
47-
templateFfiDartTypeMismatch;
46+
templateFfiDartTypeMismatch,
47+
templateFfiExtendsOrImplementsSealedClass,
48+
templateFfiStructGeneric,
49+
templateFfiWrongStructInheritance;
4850

4951
export '../fasta/hybrid_file_system.dart' show HybridFileSystem;
5052

pkg/front_end/lib/src/fasta/fasta_codes_generated.dart

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3669,12 +3669,37 @@ Message _withArgumentsFfiDartTypeMismatch(DartType _type, DartType _type2) {
36693669
arguments: {'type': _type, 'type2': _type2});
36703670
}
36713671

3672+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3673+
const Template<Message Function(String name)>
3674+
templateFfiExtendsOrImplementsSealedClass =
3675+
const Template<Message Function(String name)>(
3676+
messageTemplate:
3677+
r"""Class '#name' cannot be extended or implemented.""",
3678+
withArguments: _withArgumentsFfiExtendsOrImplementsSealedClass);
3679+
3680+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3681+
const Code<Message Function(String name)>
3682+
codeFfiExtendsOrImplementsSealedClass =
3683+
const Code<Message Function(String name)>(
3684+
"FfiExtendsOrImplementsSealedClass",
3685+
templateFfiExtendsOrImplementsSealedClass,
3686+
);
3687+
3688+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3689+
Message _withArgumentsFfiExtendsOrImplementsSealedClass(String name) {
3690+
if (name.isEmpty) throw 'No name provided';
3691+
name = demangleMixinApplicationName(name);
3692+
return new Message(codeFfiExtendsOrImplementsSealedClass,
3693+
message: """Class '${name}' cannot be extended or implemented.""",
3694+
arguments: {'name': name});
3695+
}
3696+
36723697
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
36733698
const Template<
36743699
Message Function(String name)> templateFfiFieldAnnotation = const Template<
36753700
Message Function(String name)>(
36763701
messageTemplate:
3677-
r"""Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi structs (Pointer<Void>) cannot have regular Dart fields.""",
3702+
r"""Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""",
36783703
withArguments: _withArgumentsFfiFieldAnnotation);
36793704

36803705
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3690,7 +3715,7 @@ Message _withArgumentsFfiFieldAnnotation(String name) {
36903715
name = demangleMixinApplicationName(name);
36913716
return new Message(codeFfiFieldAnnotation,
36923717
message:
3693-
"""Field '${name}' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi structs (Pointer<Void>) cannot have regular Dart fields.""",
3718+
"""Field '${name}' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""",
36943719
arguments: {'name': name});
36953720
}
36963721

@@ -3745,27 +3770,24 @@ Message _withArgumentsFfiNotStatic(String name) {
37453770
}
37463771

37473772
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3748-
const Template<
3749-
Message Function(String name)> templateFfiStructAnnotation = const Template<
3750-
Message Function(String name)>(
3751-
messageTemplate:
3752-
r"""Class '#name' is a dart:ffi Pointer but has no struct annotation. Only struct Pointers can have fields.""",
3753-
withArguments: _withArgumentsFfiStructAnnotation);
3773+
const Template<Message Function(String name)> templateFfiStructGeneric =
3774+
const Template<Message Function(String name)>(
3775+
messageTemplate: r"""Struct '#name' should not be generic.""",
3776+
withArguments: _withArgumentsFfiStructGeneric);
37543777

37553778
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3756-
const Code<Message Function(String name)> codeFfiStructAnnotation =
3779+
const Code<Message Function(String name)> codeFfiStructGeneric =
37573780
const Code<Message Function(String name)>(
3758-
"FfiStructAnnotation",
3759-
templateFfiStructAnnotation,
3781+
"FfiStructGeneric",
3782+
templateFfiStructGeneric,
37603783
);
37613784

37623785
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3763-
Message _withArgumentsFfiStructAnnotation(String name) {
3786+
Message _withArgumentsFfiStructGeneric(String name) {
37643787
if (name.isEmpty) throw 'No name provided';
37653788
name = demangleMixinApplicationName(name);
3766-
return new Message(codeFfiStructAnnotation,
3767-
message:
3768-
"""Class '${name}' is a dart:ffi Pointer but has no struct annotation. Only struct Pointers can have fields.""",
3789+
return new Message(codeFfiStructGeneric,
3790+
message: """Struct '${name}' should not be generic.""",
37693791
arguments: {'name': name});
37703792
}
37713793

@@ -3865,6 +3887,30 @@ Message _withArgumentsFfiTypeUnsized(String name, DartType _type) {
38653887
arguments: {'name': name, 'type': _type});
38663888
}
38673889

3890+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3891+
const Template<Message Function(String name)>
3892+
templateFfiWrongStructInheritance =
3893+
const Template<Message Function(String name)>(
3894+
messageTemplate:
3895+
r"""Struct '#name' must inherit from 'Struct<#name>'.""",
3896+
withArguments: _withArgumentsFfiWrongStructInheritance);
3897+
3898+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3899+
const Code<Message Function(String name)> codeFfiWrongStructInheritance =
3900+
const Code<Message Function(String name)>(
3901+
"FfiWrongStructInheritance",
3902+
templateFfiWrongStructInheritance,
3903+
);
3904+
3905+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3906+
Message _withArgumentsFfiWrongStructInheritance(String name) {
3907+
if (name.isEmpty) throw 'No name provided';
3908+
name = demangleMixinApplicationName(name);
3909+
return new Message(codeFfiWrongStructInheritance,
3910+
message: """Struct '${name}' must inherit from 'Struct<${name}>'.""",
3911+
arguments: {'name': name});
3912+
}
3913+
38683914
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
38693915
const Code<Null> codeFieldInitializedOutsideDeclaringClass =
38703916
messageFieldInitializedOutsideDeclaringClass;

pkg/front_end/messages.status

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,9 @@ FfiTypeInvalid/analyzerCode: Fail
254254
FfiTypeMismatch/analyzerCode: Fail
255255
FfiTypeUnsized/analyzerCode: Fail
256256
FfiDartTypeMismatch/analyzerCode: Fail
257+
FfiExtendsOrImplementsSealedClass/analyzerCode: Fail
258+
FfiStructGeneric/analyzerCode: Fail
259+
FfiWrongStructInheritance/analyzerCode: Fail
257260
FieldInitializedOutsideDeclaringClass/part_wrapped_script1: Fail
258261
FieldInitializedOutsideDeclaringClass/script1: Fail
259262
FieldInitializerOutsideConstructor/part_wrapped_script1: Fail

pkg/front_end/messages.yaml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3459,7 +3459,7 @@ FfiTypeUnsized:
34593459

34603460
FfiFieldAnnotation:
34613461
# Used by dart:ffi
3462-
template: "Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi structs (Pointer<Void>) cannot have regular Dart fields."
3462+
template: "Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields."
34633463
external: test/ffi_test.dart
34643464

34653465
FfiNotStatic:
@@ -3472,9 +3472,19 @@ FfiFieldInitializer:
34723472
template: "Field '#name' is a dart:ffi Pointer to a struct field and therefore cannot be initialized before constructor execution."
34733473
external: test/ffi_test.dart
34743474

3475-
FfiStructAnnotation:
3475+
FfiExtendsOrImplementsSealedClass:
34763476
# Used by dart:ffi
3477-
template: "Class '#name' is a dart:ffi Pointer but has no struct annotation. Only struct Pointers can have fields."
3477+
template: "Class '#name' cannot be extended or implemented."
3478+
external: test/ffi_test.dart
3479+
3480+
FfiStructGeneric:
3481+
# Used by dart:ffi
3482+
template: "Struct '#name' should not be generic."
3483+
external: test/ffi_test.dart
3484+
3485+
FfiWrongStructInheritance:
3486+
# Used by dart:ffi
3487+
template: "Struct '#name' must inherit from 'Struct<#name>'."
34783488
external: test/ffi_test.dart
34793489

34803490
FfiDartTypeMismatch:

pkg/vm/lib/transformations/ffi.dart

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import 'package:kernel/type_environment.dart' show TypeEnvironment;
1616

1717
/// Represents the (instantiated) ffi.NativeType.
1818
enum NativeType {
19+
kNativeType,
20+
kNativeInteger,
21+
kNativeDouble,
1922
kPointer,
2023
kNativeFunction,
2124
kInt8,
@@ -29,14 +32,18 @@ enum NativeType {
2932
kIntptr,
3033
kFloat,
3134
kDouble,
32-
kVoid
35+
kVoid,
36+
kStruct
3337
}
3438

3539
const NativeType kNativeTypeIntStart = NativeType.kInt8;
3640
const NativeType kNativeTypeIntEnd = NativeType.kIntptr;
3741

3842
/// The [NativeType] class names, indexed by [NativeType].
3943
const List<String> nativeTypeClassNames = [
44+
'NativeType',
45+
'_NativeInteger',
46+
'_NativeDouble',
4047
'Pointer',
4148
'NativeFunction',
4249
'Int8',
@@ -50,14 +57,18 @@ const List<String> nativeTypeClassNames = [
5057
'IntPtr',
5158
'Float',
5259
'Double',
53-
'Void'
60+
'Void',
61+
'Struct'
5462
];
5563

5664
const int UNKNOWN = 0;
5765
const int WORD_SIZE = -1;
5866

5967
/// The [NativeType] sizes in bytes, indexed by [NativeType].
6068
const List<int> nativeTypeSizes = [
69+
UNKNOWN, // NativeType
70+
UNKNOWN, // NativeInteger
71+
UNKNOWN, // NativeDouble
6172
WORD_SIZE, // Pointer
6273
UNKNOWN, // NativeFunction
6374
1, // Int8
@@ -72,6 +83,7 @@ const List<int> nativeTypeSizes = [
7283
4, // Float
7384
8, // Double
7485
UNKNOWN, // Void
86+
UNKNOWN, // Struct
7587
];
7688

7789
/// [FfiTransformer] contains logic which is shared between
@@ -97,7 +109,8 @@ class FfiTransformer extends Transformer {
97109
final Procedure asFunctionMethod;
98110
final Procedure lookupFunctionMethod;
99111
final Procedure fromFunctionMethod;
100-
final Field structField;
112+
final Field addressOfField;
113+
final Constructor structFromPointer;
101114

102115
/// Classes corresponding to [NativeType], indexed by [NativeType].
103116
final List<Class> nativeTypesClasses;
@@ -116,15 +129,17 @@ class FfiTransformer extends Transformer {
116129
loadMethod = index.getMember('dart:ffi', 'Pointer', 'load'),
117130
storeMethod = index.getMember('dart:ffi', 'Pointer', 'store'),
118131
offsetByMethod = index.getMember('dart:ffi', 'Pointer', 'offsetBy'),
132+
addressOfField = index.getMember('dart:ffi', 'Struct', 'addressOf'),
133+
structFromPointer =
134+
index.getMember('dart:ffi', 'Struct', 'fromPointer'),
119135
asFunctionMethod = index.getMember('dart:ffi', 'Pointer', 'asFunction'),
120136
lookupFunctionMethod =
121137
index.getMember('dart:ffi', 'DynamicLibrary', 'lookupFunction'),
122138
fromFunctionMethod =
123-
index.getTopLevelMember('dart:ffi', 'fromFunction'),
124-
structField = index.getTopLevelMember('dart:ffi', 'struct'),
139+
index.getMember('dart:ffi', 'Pointer', 'fromFunction'),
125140
nativeTypesClasses = nativeTypeClassNames
126141
.map((name) => index.getClass('dart:ffi', name))
127-
.toList() {}
142+
.toList();
128143

129144
/// Computes the Dart type corresponding to a ffi.[NativeType], returns null
130145
/// if it is not a valid NativeType.
@@ -145,19 +160,23 @@ class FfiTransformer extends Transformer {
145160
/// T extends [Pointer] -> T
146161
/// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
147162
/// where DartRepresentationOf(Tn) -> Sn
148-
DartType convertNativeTypeToDartType(DartType nativeType) {
163+
DartType convertNativeTypeToDartType(DartType nativeType, bool allowStructs) {
149164
if (nativeType is! InterfaceType) {
150165
return null;
151166
}
152-
Class nativeClass = (nativeType as InterfaceType).classNode;
153-
if (env.isSubtypeOf(
154-
InterfaceType(nativeClass), InterfaceType(pointerClass))) {
155-
return nativeType;
156-
}
167+
InterfaceType native = nativeType;
168+
Class nativeClass = native.classNode;
157169
NativeType nativeType_ = getType(nativeClass);
170+
171+
if (hierarchy.isSubclassOf(nativeClass, structClass)) {
172+
return allowStructs ? nativeType : null;
173+
}
158174
if (nativeType_ == null) {
159175
return null;
160176
}
177+
if (nativeType_ == NativeType.kPointer) {
178+
return nativeType;
179+
}
161180
if (kNativeTypeIntStart.index <= nativeType_.index &&
162181
nativeType_.index <= kNativeTypeIntEnd.index) {
163182
return InterfaceType(intClass);
@@ -168,23 +187,26 @@ class FfiTransformer extends Transformer {
168187
if (nativeType_ == NativeType.kVoid) {
169188
return VoidType();
170189
}
171-
if (nativeType_ == NativeType.kNativeFunction) {
172-
DartType fun = (nativeType as InterfaceType).typeArguments[0];
173-
if (fun is FunctionType) {
174-
if (fun.namedParameters.isNotEmpty) return null;
175-
if (fun.positionalParameters.length != fun.requiredParameterCount)
176-
return null;
177-
if (fun.typeParameters.length != 0) return null;
178-
DartType returnType = convertNativeTypeToDartType(fun.returnType);
179-
if (returnType == null) return null;
180-
List<DartType> argumentTypes = fun.positionalParameters
181-
.map(this.convertNativeTypeToDartType)
182-
.toList();
183-
if (argumentTypes.contains(null)) return null;
184-
return FunctionType(argumentTypes, returnType);
185-
}
190+
if (nativeType_ != NativeType.kNativeFunction ||
191+
native.typeArguments[0] is! FunctionType) {
192+
return null;
193+
}
194+
195+
FunctionType fun = native.typeArguments[0];
196+
if (fun.namedParameters.isNotEmpty) return null;
197+
if (fun.positionalParameters.length != fun.requiredParameterCount) {
198+
return null;
186199
}
187-
return null;
200+
if (fun.typeParameters.length != 0) return null;
201+
// TODO(36730): Structs cannot appear in native function signatures.
202+
DartType returnType =
203+
convertNativeTypeToDartType(fun.returnType, /*allowStructs=*/ false);
204+
if (returnType == null) return null;
205+
List<DartType> argumentTypes = fun.positionalParameters
206+
.map((t) => convertNativeTypeToDartType(t, /*allowStructs=*/ false))
207+
.toList();
208+
if (argumentTypes.contains(null)) return null;
209+
return FunctionType(argumentTypes, returnType);
188210
}
189211

190212
NativeType getType(Class c) {

0 commit comments

Comments
 (0)