@@ -26,14 +26,6 @@ namespace dart {
26
26
// Some checks are only performed at runtime to allow for generic code, these
27
27
// throw ArgumentExceptions.
28
28
29
- static void ThrowTypeArgumentError (const AbstractType& type_arg,
30
- const char * expected) {
31
- const String& error = String::Handle (String::NewFormatted (
32
- " Type argument (%s) should be a %s" ,
33
- String::Handle (type_arg.UserVisibleName ()).ToCString (), expected));
34
- Exceptions::ThrowArgumentError (error);
35
- }
36
-
37
29
static bool IsPointerType (const AbstractType& type) {
38
30
// Do a fast check for predefined types.
39
31
classid_t type_cid = type.type_class_id ();
@@ -54,38 +46,15 @@ static bool IsPointerType(const AbstractType& type) {
54
46
return type.IsSubtypeOf (pointer_type, Heap::kNew );
55
47
}
56
48
57
- static bool IsConcreteNativeType (const AbstractType& type) {
58
- // Do a fast check for predefined types.
59
- classid_t type_cid = type.type_class_id ();
60
- if (RawObject::IsFfiNativeTypeTypeClassId (type_cid)) {
61
- return false ;
62
- }
63
- if (RawObject::IsFfiTypeClassId (type_cid)) {
64
- return true ;
65
- }
66
-
67
- // Do a slow check for subtyping.
68
- const Class& native_type_class = Class::Handle (
69
- Isolate::Current ()->object_store ()->ffi_native_type_class ());
70
- AbstractType& native_type_type =
71
- AbstractType::Handle (native_type_class.DeclarationType ());
72
- return type.IsSubtypeOf (native_type_type, Heap::kNew );
73
- }
74
-
75
- static void CheckIsConcreteNativeType (const AbstractType& type) {
76
- if (!IsConcreteNativeType (type)) {
77
- ThrowTypeArgumentError (type, " concrete sub type of NativeType" );
78
- }
79
- }
80
-
81
49
static bool IsNativeFunction (const AbstractType& type_arg) {
82
50
classid_t type_cid = type_arg.type_class_id ();
83
51
return RawObject::IsFfiTypeNativeFunctionClassId (type_cid);
84
52
}
85
53
86
54
static void CheckSized (const AbstractType& type_arg) {
87
- classid_t type_cid = type_arg.type_class_id ();
88
- if (RawObject::IsFfiTypeVoidClassId (type_cid) ||
55
+ const classid_t type_cid = type_arg.type_class_id ();
56
+ if (RawObject::IsFfiNativeTypeTypeClassId (type_cid) ||
57
+ RawObject::IsFfiTypeVoidClassId (type_cid) ||
89
58
RawObject::IsFfiTypeNativeFunctionClassId (type_cid)) {
90
59
const String& error = String::Handle (String::NewFormatted (
91
60
" %s does not have a predefined size (@unsized). "
@@ -98,6 +67,8 @@ static void CheckSized(const AbstractType& type_arg) {
98
67
}
99
68
}
100
69
70
+ enum class FfiVariance { kInvariant = 0 , kCovariant = 1 , kContravariant = 2 };
71
+
101
72
// Checks that a dart type correspond to a [NativeType].
102
73
// Because this is checked already in a kernel transformation, it does not throw
103
74
// an ArgumentException but a boolean which should be asserted.
@@ -118,7 +89,8 @@ static void CheckSized(const AbstractType& type_arg) {
118
89
// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
119
90
// where DartRepresentationOf(Tn) -> Sn
120
91
static bool DartAndCTypeCorrespond (const AbstractType& native_type,
121
- const AbstractType& dart_type) {
92
+ const AbstractType& dart_type,
93
+ FfiVariance variance) {
122
94
classid_t native_type_cid = native_type.type_class_id ();
123
95
if (RawObject::IsFfiTypeIntClassId (native_type_cid)) {
124
96
return dart_type.IsSubtypeOf (AbstractType::Handle (Type::IntType ()),
@@ -129,7 +101,13 @@ static bool DartAndCTypeCorrespond(const AbstractType& native_type,
129
101
Heap::kNew );
130
102
}
131
103
if (RawObject::IsFfiPointerClassId (native_type_cid)) {
132
- return native_type.Equals (dart_type) || dart_type.IsNullType ();
104
+ return (variance == FfiVariance::kInvariant &&
105
+ dart_type.Equals (native_type)) ||
106
+ (variance == FfiVariance::kCovariant &&
107
+ dart_type.IsSubtypeOf (native_type, Heap::kNew )) ||
108
+ (variance == FfiVariance::kContravariant &&
109
+ native_type.IsSubtypeOf (dart_type, Heap::kNew )) ||
110
+ dart_type.IsNullType ();
133
111
}
134
112
if (RawObject::IsFfiTypeNativeFunctionClassId (native_type_cid)) {
135
113
if (!dart_type.IsFunctionType ()) {
@@ -161,20 +139,34 @@ static bool DartAndCTypeCorrespond(const AbstractType& native_type,
161
139
}
162
140
if (!DartAndCTypeCorrespond (
163
141
AbstractType::Handle (nativefunction_function.result_type ()),
164
- AbstractType::Handle (dart_function.result_type ()))) {
142
+ AbstractType::Handle (dart_function.result_type ()), variance )) {
165
143
return false ;
166
144
}
167
145
for (intptr_t i = 0 ; i < dart_function.NumParameters (); i++) {
168
146
if (!DartAndCTypeCorrespond (
169
147
AbstractType::Handle (nativefunction_function.ParameterTypeAt (i)),
170
- AbstractType::Handle (dart_function.ParameterTypeAt (i)))) {
148
+ AbstractType::Handle (dart_function.ParameterTypeAt (i)),
149
+ variance)) {
171
150
return false ;
172
151
}
173
152
}
174
153
}
175
154
return true ;
176
155
}
177
156
157
+ static void CheckDartAndCTypeCorrespond (const AbstractType& native_type,
158
+ const AbstractType& dart_type,
159
+ FfiVariance variance) {
160
+ if (!DartAndCTypeCorrespond (native_type, dart_type, variance)) {
161
+ const String& error = String::Handle (String::NewFormatted (
162
+ " Expected type '%s' to be different, it should be "
163
+ " DartRepresentationOf('%s')." ,
164
+ String::Handle (dart_type.UserVisibleName ()).ToCString (),
165
+ String::Handle (native_type.UserVisibleName ()).ToCString ()));
166
+ Exceptions::ThrowArgumentError (error);
167
+ }
168
+ }
169
+
178
170
// The following functions are runtime checks on arguments.
179
171
180
172
// Note that expected_from and expected_to are inclusive.
@@ -224,7 +216,6 @@ DEFINE_NATIVE_ENTRY(Ffi_allocate, 1, 1) {
224
216
// Pointer. https://github.com/dart-lang/sdk/issues/35782
225
217
GET_NATIVE_TYPE_ARGUMENT (type_arg, arguments->NativeTypeArgAt (0 ));
226
218
227
- CheckIsConcreteNativeType (type_arg);
228
219
CheckSized (type_arg);
229
220
230
221
GET_NON_NULL_NATIVE_ARGUMENT (Integer, argCount, arguments->NativeArgAt (0 ));
@@ -251,7 +242,6 @@ DEFINE_NATIVE_ENTRY(Ffi_fromAddress, 1, 1) {
251
242
TypeArguments& type_args = TypeArguments::Handle (type_arg.arguments ());
252
243
AbstractType& native_type = AbstractType::Handle (
253
244
type_args.TypeAtNullSafe (Pointer::kNativeTypeArgPos ));
254
- CheckIsConcreteNativeType (native_type);
255
245
GET_NON_NULL_NATIVE_ARGUMENT (Integer, arg_ptr, arguments->NativeArgAt (0 ));
256
246
257
247
// TODO(dacoharkes): should this return NULL if address is 0?
@@ -298,7 +288,6 @@ DEFINE_NATIVE_ENTRY(Ffi_cast, 1, 1) {
298
288
TypeArguments& type_args = TypeArguments::Handle (type_arg.arguments ());
299
289
AbstractType& native_type = AbstractType::Handle (
300
290
type_args.TypeAtNullSafe (Pointer::kNativeTypeArgPos ));
301
- CheckIsConcreteNativeType (native_type);
302
291
303
292
const Integer& address = Integer::Handle (zone, pointer.GetCMemoryAddress ());
304
293
RawPointer* result =
@@ -379,7 +368,8 @@ DEFINE_NATIVE_ENTRY(Ffi_load, 1, 1) {
379
368
AbstractType& pointer_type_arg =
380
369
AbstractType::Handle (pointer.type_argument ());
381
370
CheckSized (pointer_type_arg);
382
- ASSERT (DartAndCTypeCorrespond (pointer_type_arg, type_arg));
371
+ CheckDartAndCTypeCorrespond (pointer_type_arg, type_arg,
372
+ FfiVariance::kContravariant );
383
373
384
374
uint8_t * address = reinterpret_cast <uint8_t *>(
385
375
Integer::Handle (pointer.GetCMemoryAddress ()).AsInt64Value ());
@@ -460,7 +450,8 @@ DEFINE_NATIVE_ENTRY(Ffi_store, 0, 2) {
460
450
AbstractType& pointer_type_arg =
461
451
AbstractType::Handle (pointer.type_argument ());
462
452
CheckSized (pointer_type_arg);
463
- ASSERT (DartAndCTypeCorrespond (pointer_type_arg, arg_type));
453
+ CheckDartAndCTypeCorrespond (pointer_type_arg, arg_type,
454
+ FfiVariance::kCovariant );
464
455
465
456
classid_t type_cid = pointer_type_arg.type_class_id ();
466
457
StoreValue (zone, pointer, type_cid, new_value);
@@ -469,7 +460,6 @@ DEFINE_NATIVE_ENTRY(Ffi_store, 0, 2) {
469
460
470
461
DEFINE_NATIVE_ENTRY (Ffi_sizeOf, 1 , 0 ) {
471
462
GET_NATIVE_TYPE_ARGUMENT (type_arg, arguments->NativeTypeArgAt (0 ));
472
- CheckIsConcreteNativeType (type_arg);
473
463
CheckSized (type_arg);
474
464
475
465
classid_t type_cid = type_arg.type_class_id ();
@@ -523,7 +513,8 @@ DEFINE_NATIVE_ENTRY(Ffi_asFunction, 1, 1) {
523
513
AbstractType::Handle (pointer.type_argument ());
524
514
ASSERT (IsNativeFunction (pointer_type_arg));
525
515
GET_NATIVE_TYPE_ARGUMENT (type_arg, arguments->NativeTypeArgAt (0 ));
526
- ASSERT (DartAndCTypeCorrespond (pointer_type_arg, type_arg));
516
+ CheckDartAndCTypeCorrespond (pointer_type_arg, type_arg,
517
+ FfiVariance::kInvariant );
527
518
528
519
Function& dart_signature = Function::Handle (Type::Cast (type_arg).signature ());
529
520
TypeArguments& nativefunction_type_args =
0 commit comments