[vm/ffi] Add Opaque type

Issue: https://github.com/dart-lang/sdk/issues/44622
Issue: https://github.com/dart-lang/sdk/issues/43974

TEST=samples/ffi/sqlite/lib/src/bindings/types.dart
TEST=tests/ffi/vmspecific_static_checks_test.dart

Change-Id: Ib9e72df6a07b1bc2b72a7db66f945652814baf51
Cq-Include-Trybots: luci.dart.try:vm-precomp-ffi-qemu-linux-release-arm-try,analyzer-analysis-server-linux-try,analyzer-linux-release-try,analyzer-nnbd-linux-release-try,front-end-linux-release-x64-try,front-end-nnbd-linux-release-x64-try,benchmark-linux-try,dart-sdk-linux-try,pkg-linux-release-try,vm-ffi-android-release-arm-try,vm-ffi-android-release-arm64-try,vm-kernel-nnbd-win-debug-x64-try,vm-kernel-win-debug-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/178984
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Clement Skau <cskau@google.com>
This commit is contained in:
Daco Harkes 2021-01-13 17:04:08 +00:00 committed by commit-bot@chromium.org
parent 4e2343c290
commit 5d40d52fca
23 changed files with 67 additions and 27 deletions

View file

@ -18,6 +18,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
static const _allocateExtensionMethodName = 'call';
static const _allocatorExtensionName = 'AllocatorAlloc';
static const _dartFfiLibraryName = 'dart.ffi';
static const _opaqueClassName = 'Opaque';
static const List<String> _primitiveIntegerNativeTypes = [
'Int8',
@ -54,7 +55,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
@override
void visitClassDeclaration(ClassDeclaration node) {
inStruct = false;
// Only the Struct class may be extended.
// Only the Allocator, Opaque and Struct class may be extended.
ExtendsClause extendsClause = node.extendsClause;
if (extendsClause != null) {
final TypeName superclass = extendsClause.superclass;
@ -62,7 +63,8 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
final className = superclass.name.staticElement.name;
if (className == _structClassName) {
inStruct = true;
} else if (className != _allocatorClassName) {
} else if (className != _allocatorClassName &&
className != _opaqueClassName) {
_errorReporter.reportErrorForNode(
FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS,
superclass.name,
@ -245,6 +247,21 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
return false;
}
/// Returns `true` iff [nativeType] is a opaque type, i.e. a subtype of `Opaque`.
bool _isOpaqueClass(DartType nativeType) {
if (nativeType is InterfaceType) {
final superType = nativeType.element.supertype;
if (superType == null) {
return false;
}
final superClassElement = superType.element;
if (superClassElement.library.name == _dartFfiLibraryName) {
return superClassElement.name == _opaqueClassName;
}
}
return false;
}
/// Return `true` if the given [element] represents the class `Pointer`.
bool _isPointer(Element element) =>
element.name == 'Pointer' && element.library.name == _dartFfiLibraryName;
@ -345,6 +362,9 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
}
return true;
}
if (_isOpaqueClass(nativeType)) {
return true;
}
} else if (nativeType is FunctionType) {
return _isValidFfiNativeFunctionType(nativeType);
}

View file

@ -41,4 +41,4 @@ constants {
Constructor coverage from constants:
org-dartlang-testcase:///ffi_sample.dart:
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)

View file

@ -72,4 +72,4 @@ constants {
Constructor coverage from constants:
org-dartlang-testcase:///ffi_sample.dart:
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)

View file

@ -35,4 +35,4 @@ constants {
Constructor coverage from constants:
org-dartlang-testcase:///ffi_sample.dart:
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)

View file

@ -66,4 +66,4 @@ constants {
Constructor coverage from constants:
org-dartlang-testcase:///ffi_sample.dart:
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)

View file

@ -35,4 +35,4 @@ constants {
Constructor coverage from constants:
org-dartlang-testcase:///ffi_sample.dart:
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)

View file

@ -66,4 +66,4 @@ constants {
Constructor coverage from constants:
org-dartlang-testcase:///ffi_sample.dart:
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:116:9)
- Double. (from org-dartlang-sdk:///sdk/lib/ffi/native_type.dart:122:9)

View file

@ -34,6 +34,7 @@ enum NativeType {
kFloat,
kDouble,
kVoid,
kOpaque,
kStruct,
kHandle,
}
@ -60,6 +61,7 @@ const List<String> nativeTypeClassNames = [
'Float',
'Double',
'Void',
'Opaque',
'Struct',
'Handle'
];
@ -86,6 +88,7 @@ const List<int> nativeTypeSizes = [
4, // Float
8, // Double
UNKNOWN, // Void
UNKNOWN, // Opaque
UNKNOWN, // Struct
WORD_SIZE, // Handle
];
@ -207,6 +210,7 @@ class FfiTransformer extends Transformer {
final Library ffiLibrary;
final Class allocatorClass;
final Class nativeFunctionClass;
final Class opaqueClass;
final Class pointerClass;
final Class structClass;
final Procedure allocateMethod;
@ -263,6 +267,7 @@ class FfiTransformer extends Transformer {
ffiLibrary = index.getLibrary('dart:ffi'),
allocatorClass = index.getClass('dart:ffi', 'Allocator'),
nativeFunctionClass = index.getClass('dart:ffi', 'NativeFunction'),
opaqueClass = index.getClass('dart:ffi', 'Opaque'),
pointerClass = index.getClass('dart:ffi', 'Pointer'),
structClass = index.getClass('dart:ffi', 'Struct'),
allocateMethod = index.getMember('dart:ffi', 'AllocatorAlloc', 'call'),

View file

@ -488,10 +488,15 @@ class _FfiUseSiteTransformer extends FfiTransformer {
Class _extendsOrImplementsSealedClass(Class klass) {
final Class superClass = klass.supertype?.classNode;
// The Struct class can be extended, but subclasses of Struct cannot be (nor
// implemented).
if (klass != structClass && hierarchy.isSubtypeOf(klass, structClass)) {
return superClass != structClass ? superClass : null;
// The Opaque and Struct classes can be extended, but subclasses
// cannot be (nor implemented).
if (klass != opaqueClass &&
klass != structClass &&
(hierarchy.isSubtypeOf(klass, opaqueClass) ||
hierarchy.isSubtypeOf(klass, structClass))) {
return superClass != opaqueClass && superClass != structClass
? superClass
: null;
}
if (!nativeTypesClasses.contains(klass)) {

View file

@ -105,7 +105,7 @@ final stopWorkSimulator =
final executeCallback = dl.lookupFunction<Void Function(Pointer<Work>),
void Function(Pointer<Work>)>('ExecuteCallback');
class Work extends Struct {}
class Work extends Opaque {}
Future asyncSleep(int ms) {
return new Future.delayed(Duration(milliseconds: ms));

View file

@ -86,4 +86,4 @@ final releaseResource = ffiTestDynamicLibrary.lookupFunction<
void Function(Pointer<SomeResource>)>("ReleaseResource");
/// Represents some opaque resource being managed by a library.
class SomeResource extends Struct {}
class SomeResource extends Opaque {}

View file

@ -110,4 +110,4 @@ main() {
}
/// Represents some opaque resource being managed by a library.
class SomeResource extends Struct {}
class SomeResource extends Opaque {}

View file

@ -111,4 +111,4 @@ main() {
}
/// Represents some opaque resource being managed by a library.
class SomeResource extends Struct {}
class SomeResource extends Opaque {}

View file

@ -13,7 +13,7 @@ import "dart:ffi";
/// is its destructor. There are many other interfaces (such as
/// [sqlite3_prepare_v2()], [sqlite3_create_function()], and
/// [sqlite3_busy_timeout()] to name but three) that are methods on an
class Database extends Struct {}
class Database extends Opaque {}
/// SQL Statement Object
///
@ -36,7 +36,7 @@ class Database extends Struct {}
///
/// Refer to documentation on individual methods above for additional
/// information.
class Statement extends Struct {}
class Statement extends Opaque {}
/// Dynamically Typed Value Object
///
@ -72,4 +72,4 @@ class Statement extends Struct {}
/// [sqlite3_result_value()] and [sqlite3_bind_value()].
/// The [sqlite3_value_blob | sqlite3_value_type()] family of
/// interfaces require protected sqlite3_value objects.
class Value extends Struct {}
class Value extends Opaque {}

View file

@ -107,7 +107,7 @@ final stopWorkSimulator =
final executeCallback = dl.lookupFunction<Void Function(Pointer<Work>),
void Function(Pointer<Work>)>('ExecuteCallback');
class Work extends Struct {}
class Work extends Opaque {}
Future asyncSleep(int ms) {
return new Future.delayed(Duration(milliseconds: ms));

View file

@ -88,4 +88,4 @@ final releaseResource = ffiTestDynamicLibrary.lookupFunction<
void Function(Pointer<SomeResource>)>("ReleaseResource");
/// Represents some opaque resource being managed by a library.
class SomeResource extends Struct {}
class SomeResource extends Opaque {}

View file

@ -112,4 +112,4 @@ main() {
}
/// Represents some opaque resource being managed by a library.
class SomeResource extends Struct {}
class SomeResource extends Opaque {}

View file

@ -113,4 +113,4 @@ main() {
}
/// Represents some opaque resource being managed by a library.
class SomeResource extends Struct {}
class SomeResource extends Opaque {}

View file

@ -15,7 +15,7 @@ import "dart:ffi";
/// is its destructor. There are many other interfaces (such as
/// [sqlite3_prepare_v2()], [sqlite3_create_function()], and
/// [sqlite3_busy_timeout()] to name but three) that are methods on an
class Database extends Struct {}
class Database extends Opaque {}
/// SQL Statement Object
///
@ -38,7 +38,7 @@ class Database extends Struct {}
///
/// Refer to documentation on individual methods above for additional
/// information.
class Statement extends Struct {}
class Statement extends Opaque {}
/// Dynamically Typed Value Object
///
@ -74,4 +74,4 @@ class Statement extends Struct {}
/// [sqlite3_result_value()] and [sqlite3_bind_value()].
/// The [sqlite3_value_blob | sqlite3_value_type()] family of
/// interfaces require protected sqlite3_value objects.
class Value extends Struct {}
class Value extends Opaque {}

View file

@ -559,7 +559,7 @@ extension NativePort on SendPort {
}
/// Opaque, not exposing it's members.
class Dart_CObject extends Struct {}
class Dart_CObject extends Opaque {}
typedef Dart_NativeMessageHandler = Void Function(Int64, Pointer<Dart_CObject>);

View file

@ -12,6 +12,12 @@ abstract class NativeType {
const NativeType();
}
/// [Opaque]'s subtypes represent opaque types in C.
///
/// [Opaque]'s subtypes are not constructible in the Dart code and serve purely
/// as markers in type signatures.
abstract class Opaque extends NativeType {}
/// [_NativeInteger]'s subtypes represent a native integer in C.
///
/// [_NativeInteger]'s subtypes are not constructible in the Dart code and serve

View file

@ -477,6 +477,8 @@ class IPointer implements Pointer {} //# 814: compile-time error
class IStruct implements Struct {} //# 815: compile-time error
class IOpaque implements Opaque {} //# 816: compile-time error
class MyClass {
int x;
MyClass(this.x);

View file

@ -477,6 +477,8 @@ class IPointer implements Pointer {} //# 814: compile-time error
class IStruct implements Struct {} //# 815: compile-time error
class IOpaque implements Opaque {} //# 816: compile-time error
class MyClass {
int x;
MyClass(this.x);