Revert "[vm/ffi] Unwrap typed data in FFI calls"

This reverts: https://dart-review.googlesource.com/c/sdk/+/338620

We'd like to support this use case with a different API. See the
discussion in https://github.com/dart-lang/sdk/issues/54739.

TEST=tests/ffi

Bug: https://github.com/dart-lang/sdk/issues/44589
Bug: https://github.com/dart-lang/sdk/issues/54771
Change-Id: Ic22fbcab14d374bb9c81bba1f1bf6ae2dfc9e674
Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_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-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-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-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-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-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-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/+/349340
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Daco Harkes 2024-01-31 09:22:45 +00:00
parent 4dff1b3b0a
commit 70e4ff3e1a
23 changed files with 2 additions and 4235 deletions

View file

@ -5005,29 +5005,6 @@ const MessageCode messageFfiAddressOfMustBeNative = const MessageCode(
problemMessage:
r"""Argument to 'Native.addressOf' must be annotated with @Native.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeFfiCallMustNotReturnTypedData =
messageFfiCallMustNotReturnTypedData;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageFfiCallMustNotReturnTypedData = const MessageCode(
"FfiCallMustNotReturnTypedData",
analyzerCodes: <String>["CALL_MUST_NOT_RETURN_TYPED_DATA"],
problemMessage: r"""FFI calls can't return typed data.""",
correctionMessage: r"""Try changing using `Pointer`s.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeFfiCallbackMustNotUseTypedData =
messageFfiCallbackMustNotUseTypedData;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageFfiCallbackMustNotUseTypedData = const MessageCode(
"FfiCallbackMustNotUseTypedData",
analyzerCodes: <String>["CALLBACK_MUST_NOT_USE_TYPED_DATA"],
problemMessage:
r"""FFI callbacks can't take typed data arguments or return value.""",
correctionMessage: r"""Try changing using `Pointer`s.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String string, String name)>
templateFfiCompoundImplementsFinalizable =
@ -5430,17 +5407,6 @@ Message _withArgumentsFfiNativeUnexpectedNumberOfParametersWithReceiver(
arguments: {'count': count, 'count2': count2});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeFfiNonLeafCallMustNotTakeTypedData =
messageFfiNonLeafCallMustNotTakeTypedData;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageFfiNonLeafCallMustNotTakeTypedData = const MessageCode(
"FfiNonLeafCallMustNotTakeTypedData",
analyzerCodes: <String>["NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA"],
problemMessage: r"""FFI non-leaf calls can't take typed data arguments.""",
correctionMessage: r"""Try changing the call to a leaf call.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(String name)> templateFfiNotStatic = const Template<

View file

@ -1780,12 +1780,6 @@ FfiCode.LEAF_CALL_MUST_NOT_RETURN_HANDLE:
status: noFix
FfiCode.LEAF_CALL_MUST_NOT_TAKE_HANDLE:
status: noFix
FfiCode.CALLBACK_MUST_NOT_USE_TYPED_DATA:
status: noFix
FfiCode.CALL_MUST_NOT_RETURN_TYPED_DATA:
status: noFix
FfiCode.NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA:
status: noFix
FfiCode.MISMATCHED_ANNOTATION_ON_STRUCT_FIELD:
status: noFix
FfiCode.MISSING_ANNOTATION_ON_STRUCT_FIELD:

View file

@ -91,22 +91,6 @@ class FfiCode extends AnalyzerErrorCode {
"Try passing a static function or field annotated with '@Native'",
);
/// No parameters.
static const FfiCode CALLBACK_MUST_NOT_USE_TYPED_DATA = FfiCode(
'CALLBACK_MUST_NOT_USE_TYPED_DATA',
"FFI callbacks can't take typed data arguments or return value.",
correctionMessage: "Try changing using `Pointer`s.",
hasPublishedDocs: true,
);
/// No parameters.
static const FfiCode CALL_MUST_NOT_RETURN_TYPED_DATA = FfiCode(
'CALL_MUST_NOT_RETURN_TYPED_DATA',
"FFI calls can't return typed data.",
correctionMessage: "Try changing using `Pointer`s.",
hasPublishedDocs: true,
);
/// Parameters:
/// 0: the name of the struct or union class
static const FfiCode COMPOUND_IMPLEMENTS_FINALIZABLE = FfiCode(
@ -391,14 +375,6 @@ class FfiCode extends AnalyzerErrorCode {
hasPublishedDocs: true,
);
/// No parameters.
static const FfiCode NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA = FfiCode(
'NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA',
"FFI non-leaf calls can't take typed data arguments.",
correctionMessage: "Try changing the call to a leaf call.",
hasPublishedDocs: true,
);
/// Parameters:
/// 0: the type that should be a valid dart:ffi native type.
static const FfiCode NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER = FfiCode(

View file

@ -585,8 +585,6 @@ const List<ErrorCode> errorCodeValues = [
FfiCode.ANNOTATION_ON_POINTER_FIELD,
FfiCode.ARGUMENT_MUST_BE_A_CONSTANT,
FfiCode.ARGUMENT_MUST_BE_NATIVE,
FfiCode.CALLBACK_MUST_NOT_USE_TYPED_DATA,
FfiCode.CALL_MUST_NOT_RETURN_TYPED_DATA,
FfiCode.COMPOUND_IMPLEMENTS_FINALIZABLE,
FfiCode.CREATION_OF_STRUCT_OR_UNION,
FfiCode.EMPTY_STRUCT,
@ -617,7 +615,6 @@ const List<ErrorCode> errorCodeValues = [
FfiCode.NATIVE_FIELD_MISSING_TYPE,
FfiCode.NATIVE_FIELD_NOT_STATIC,
FfiCode.NON_CONSTANT_TYPE_ARGUMENT,
FfiCode.NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA,
FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER,
FfiCode.NON_POSITIVE_ARRAY_DIMENSION,
FfiCode.NON_SIZED_TYPE_ARGUMENT,

View file

@ -587,14 +587,6 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
[nativeType, dartType, 'Native']);
return;
}
_validateFfiTypedDataUnwrapping(
dartType,
nativeType,
errorNode,
isLeaf: isLeaf,
isCall: true,
);
}
bool _extendsNativeFieldWrapperClass1(InterfaceType? type) {
@ -1027,13 +1019,6 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
if (isLeaf) {
_validateFfiLeafCallUsesNoHandles(TPrime, node);
}
_validateFfiTypedDataUnwrapping(
F,
TPrime,
errorNode,
isLeaf: isLeaf,
isCall: true,
);
}
_validateIsLeafIsConst(node);
}
@ -1193,46 +1178,6 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
}
}
void _validateFfiTypedDataUnwrapping(
DartType dartType,
DartType nativeType,
AstNode errorNode, {
required bool isLeaf,
required bool isCall,
}) {
if (dartType is FunctionType && nativeType is FunctionType) {
if (dartType.returnType.isTypedData && nativeType.returnType.isPointer) {
if (!isCall) {
_errorReporter.reportErrorForNode(
FfiCode.CALLBACK_MUST_NOT_USE_TYPED_DATA, errorNode);
} else {
_errorReporter.reportErrorForNode(
FfiCode.CALL_MUST_NOT_RETURN_TYPED_DATA, errorNode);
}
}
int i = 0;
final nativeParamTypes = nativeType.normalParameterTypes.flattenVarArgs();
for (final dartParam in dartType.normalParameterTypes) {
if (i >= nativeParamTypes.length) {
// Cascading error as not the same amount of arguments.
// Already results in an error earlier.
return;
}
final nativeParam = nativeParamTypes[i];
i++;
if (dartParam.isTypedData && nativeParam.isPointer) {
if (!isCall) {
_errorReporter.reportErrorForNode(
FfiCode.CALLBACK_MUST_NOT_USE_TYPED_DATA, errorNode);
} else if (!isLeaf) {
_errorReporter.reportErrorForNode(
FfiCode.NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA, errorNode);
}
}
}
}
}
/// Validate that the fields declared by the given [node] meet the
/// requirements for fields within a struct or union class.
void _validateFieldsInCompound(FieldDeclaration node) {
@ -1354,7 +1299,6 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
FfiCode.ARGUMENT_MUST_BE_A_CONSTANT, e, ['exceptionalReturn']);
}
}
_validateFfiTypedDataUnwrapping(FT, T, f, isLeaf: false, isCall: false);
}
/// Ensure `isLeaf` is const as we need the value at compile time to know
@ -1406,9 +1350,6 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
if (isLeaf) {
_validateFfiLeafCallUsesNoHandles(S, typeArguments[0]);
}
final AstNode errorNode = typeArguments[1];
_validateFfiTypedDataUnwrapping(F, S, errorNode,
isLeaf: isLeaf, isCall: true);
}
/// Validate the invocation of `Native.addressOf`.
@ -1551,13 +1492,6 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
_errorReporter.reportErrorForNode(
FfiCode.MUST_BE_A_SUBTYPE, e, [eType, natRetType, name]);
}
_validateFfiTypedDataUnwrapping(
funcType,
typeArg,
e,
isLeaf: false,
isCall: false,
);
if (!_isConst(e)) {
_errorReporter.reportErrorForNode(
FfiCode.ARGUMENT_MUST_BE_A_CONSTANT, e, ['exceptionalReturn']);

View file

@ -20032,139 +20032,6 @@ FfiCode:
}
}
```
NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA:
problemMessage: "FFI non-leaf calls can't take typed data arguments."
correctionMessage: Try changing the call to a leaf call.
comment: No parameters.
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the value of the `isLeaf`
argument of `Pointer.asFunction`, `DynamicLibrary.lookupFunction`, or
`@Native` is `false` and the Dart function signature contains a typed
data parameter.
Typed data unwrapping is only supported on arguments for leaf FFI calls.
For more information about FFI, see [C interop using dart:ffi][ffi].
#### Example
The following code produces this diagnostic because the dart function
signature contains a typed data, but the `isLeaf` argument is `false`:
```dart
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<NativeFunction<Void Function(Pointer<Uint8>)>> p) {
p.asFunction<[!void Function(Uint8List)!]>();
}
```
#### Common fixes
If the function has at least one typed data parameter, then add
the `isLeaf` argument:
```dart
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<NativeFunction<Void Function(Pointer<Uint8>)>> p) {
p.asFunction<void Function(Uint8List)>(isLeaf: true);
}
```
If the function also uses `Handle`s, then it must be non-leaf. In That
case use `Pointer`s instead of typed data.
CALL_MUST_NOT_RETURN_TYPED_DATA:
problemMessage: "FFI calls can't return typed data."
correctionMessage: Try changing using `Pointer`s.
comment: No parameters.
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the return type of
`Pointer.asFunction`, `DynamicLibrary.lookupFunction`, or
`@Native` is a typed data.
Typed data unwrapping is only supported on arguments for leaf FFI calls.
For more information about FFI, see [C interop using dart:ffi][ffi].
#### Example
The following code produces this diagnostic because the dart function
signature contains a typed data, but the `isLeaf` argument is `false`:
```dart
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<NativeFunction<Pointer<Uint8> Function()>> p) {
p.asFunction<[!Uint8List Function()!]>();
}
```
#### Common fixes
Use the `Pointer` type instead:
```dart
import 'dart:ffi';
void f(Pointer<NativeFunction<Pointer<Uint8> Function()>> p) {
p.asFunction<Pointer<Uint8> Function()>();
}
```
CALLBACK_MUST_NOT_USE_TYPED_DATA:
problemMessage: "FFI callbacks can't take typed data arguments or return value."
correctionMessage: Try changing using `Pointer`s.
comment: No parameters.
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when an invocation of
`Pointer.fromFunction`, one of`NativeCallable`'s constructors has a
typed data argument or return value."
Typed data unwrapping is only supported on arguments for leaf FFI calls.
For more information about FFI, see [C interop using dart:ffi][ffi].
#### Example
The following code produces this diagnostic because the parameter type
of `g` is a typed data.
```dart
import 'dart:ffi';
import 'dart:typed_data';
void f(Uint8List i) {}
void g() {
Pointer.fromFunction<Void Function(Pointer<Uint8>)>([!f!]);
}
```
#### Common fixes
Use the `Pointer` type instead:
```dart
import 'dart:ffi';
void f(Pointer<Uint8> i) {}
void g() {
Pointer.fromFunction<Void Function(Pointer<Uint8>)>(f);
}
```
NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER:
problemMessage: "Can't invoke 'asFunction' because the function signature '{0}' for the pointer isn't a valid C function signature."
correctionMessage: "Try changing the function argument in 'NativeFunction' to only use NativeTypes."

View file

@ -1,204 +0,0 @@
// Copyright (c) 2023, 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.
import 'package:analyzer/src/dart/error/ffi_code.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(FfiUnwrapTypedDataTest);
});
}
@reflectiveTest
class FfiUnwrapTypedDataTest extends PubPackageResolutionTest {
test_fromFunction_argument() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
external int f(Int8List i);
void g() {
Pointer.fromFunction<Int8 Function(Pointer<Int8>)>(f, 5);
}
''', [
error(FfiCode.CALLBACK_MUST_NOT_USE_TYPED_DATA, 137, 1),
]);
}
test_fromFunction_argument_handle() async {
await assertNoErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
external int f(Int8List i);
void g() {
Pointer.fromFunction<Int8 Function(Handle)>(f, 5);
}
''');
}
test_fromFunction_return() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
external Int8List f(int i);
void g() {
Pointer.fromFunction<Pointer<Int8> Function(Int8)>(f);
}
''', [
error(FfiCode.CALLBACK_MUST_NOT_USE_TYPED_DATA, 137, 1),
]);
}
test_lookupFunction_double() async {
await assertNoErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
final dylib = DynamicLibrary.open('dontcare');
final unwrapFloat64List = dylib.lookupFunction<
Int8 Function(Pointer<Double>, Int64),
int Function(Float64List, int)>('UnwrapFloat64List', isLeaf: true);
''');
}
test_lookupFunction_float() async {
await assertNoErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
final dylib = DynamicLibrary.open('dontcare');
final unwrapFloat32List = dylib.lookupFunction<
Int8 Function(Pointer<Float>, Int64),
int Function(Float32List, int)>('UnwrapFloat32List', isLeaf: true);
''');
}
test_lookupFunction_leaf() async {
await assertNoErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
final dylib = DynamicLibrary.open('dontcare');
final unwrapInt8List = dylib.lookupFunction<
Int8 Function(Pointer<Int8>, Int64),
int Function(Int8List, int)>('UnwrapInt8List', isLeaf: true);
''');
}
test_lookupFunction_non_leaf() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
final dylib = DynamicLibrary.open('dontcare');
final unwrapInt8List = dylib.lookupFunction<
Int8 Function(Pointer<Int8>, Int64),
int Function(Int8List, int)>('UnwrapInt8List');
''', [
error(FfiCode.NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA, 182, 27),
]);
}
test_lookupFunction_non_leaf_handle() async {
await assertNoErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
final dylib = DynamicLibrary.open('dontcare');
final unwrapInt8List = dylib.lookupFunction<
Int8 Function(Handle, Int64),
int Function(Int8List, int)>('UnwrapInt8List');
''');
}
test_mismatched_types() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
final dylib = DynamicLibrary.open('dontcare');
final unwrapInt8List = dylib.lookupFunction<
Int8 Function(Pointer<Uint64>, Int64),
int Function(Int8List, int)>('UnwrapInt8List', isLeaf: true);
''', [
error(FfiCode.MUST_BE_A_SUBTYPE, 184, 27),
]);
}
test_mismatched_types_2() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
final dylib = DynamicLibrary.open('dontcare');
final unwrapInt8List = dylib.lookupFunction<
Int8 Function(Pointer<Int8>, Int64),
int Function(Float32List, int)>('UnwrapInt8List', isLeaf: true);
''', [
error(FfiCode.MUST_BE_A_SUBTYPE, 182, 30),
]);
}
test_native_leaf() async {
await assertNoErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
@Native<Int8 Function(Pointer<Int8>, Int64)>(
symbol: 'UnwrapInt8List', isLeaf: true)
external int unwrapInt8List(Int8List list, int length);
''');
}
test_native_non_leaf() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
@Native<Int8 Function(Pointer<Int8>, Int64)>(
symbol: 'UnwrapInt8List')
external int unwrapInt8List(Int8List list, int length);
''', [
error(FfiCode.NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA, 45, 131),
]);
}
test_native_non_leaf_handle() async {
await assertNoErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
@Native<Int8 Function(Handle, Int64)>(
symbol: 'UnwrapInt8List')
external int unwrapInt8List(Int8List list, int length);
''');
}
test_return_lookupFunction() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
final dylib = DynamicLibrary.open('dontcare');
final unwrapInt8List = dylib.lookupFunction<
Pointer<Int8> Function(),
Int8List Function()>('UnwrapInt8List', isLeaf: true);
''', [
error(FfiCode.CALL_MUST_NOT_RETURN_TYPED_DATA, 171, 19),
]);
}
test_return_native() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
@Native<Pointer<Int8> Function()>(
symbol: 'UnwrapInt8List', isLeaf: true)
external Int8List unwrapInt8List();
''', [
error(FfiCode.CALL_MUST_NOT_RETURN_TYPED_DATA, 45, 114),
]);
}
test_return_native_handle() async {
await assertNoErrorsInCode(r'''
import 'dart:ffi';
import 'dart:typed_data';
@Native<Handle Function()>(
symbol: 'UnwrapInt8List')
external Int8List unwrapInt8List();
''');
}
}

View file

@ -298,7 +298,6 @@ import 'ffi_async_callback_test.dart' as ffi_async_callback_test;
import 'ffi_leaf_call_must_not_use_handle_test.dart'
as ffi_leaf_call_must_not_use_handle;
import 'ffi_native_test.dart' as ffi_native_test;
import 'ffi_unwrap_typed_data_test.dart' as ffi_unwrap_typed_data_test;
import 'field_initialized_by_multiple_initializers_test.dart'
as field_initialized_by_multiple_initializers;
import 'field_initialized_in_initializer_and_declaration_test.dart'
@ -1101,7 +1100,6 @@ main() {
ffi_async_callback_test.main();
ffi_leaf_call_must_not_use_handle.main();
ffi_native_test.main();
ffi_unwrap_typed_data_test.main();
field_initialized_by_multiple_initializers.main();
final_initialized_in_declaration_and_constructor.main();
field_initialized_in_initializer_and_declaration.main();

View file

@ -1918,90 +1918,6 @@ extension [!mixin!] on int {}
Choose a different name for the declaration.
### callback_must_not_use_typed_data
_FFI callbacks can't take typed data arguments or return value._
#### Description
The analyzer produces this diagnostic when an invocation of
`Pointer.fromFunction`, one of`NativeCallable`'s constructors has a
typed data argument or return value."
Typed data unwrapping is only supported on arguments for leaf FFI calls.
For more information about FFI, see [C interop using dart:ffi][ffi].
#### Example
The following code produces this diagnostic because the parameter type
of `g` is a typed data.
{% prettify dart tag=pre+code %}
import 'dart:ffi';
import 'dart:typed_data';
void f(Uint8List i) {}
void g() {
Pointer.fromFunction<Void Function(Pointer<Uint8>)>([!f!]);
}
{% endprettify %}
#### Common fixes
Use the `Pointer` type instead:
{% prettify dart tag=pre+code %}
import 'dart:ffi';
void f(Pointer<Uint8> i) {}
void g() {
Pointer.fromFunction<Void Function(Pointer<Uint8>)>(f);
}
{% endprettify %}
### call_must_not_return_typed_data
_FFI calls can't return typed data._
#### Description
The analyzer produces this diagnostic when the return type of
`Pointer.asFunction`, `DynamicLibrary.lookupFunction`, or
`@Native` is a typed data.
Typed data unwrapping is only supported on arguments for leaf FFI calls.
For more information about FFI, see [C interop using dart:ffi][ffi].
#### Example
The following code produces this diagnostic because the dart function
signature contains a typed data, but the `isLeaf` argument is `false`:
{% prettify dart tag=pre+code %}
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<NativeFunction<Pointer<Uint8> Function()>> p) {
p.asFunction<[!Uint8List Function()!]>();
}
{% endprettify %}
#### Common fixes
Use the `Pointer` type instead:
{% prettify dart tag=pre+code %}
import 'dart:ffi';
void f(Pointer<NativeFunction<Pointer<Uint8> Function()>> p) {
p.asFunction<Pointer<Uint8> Function()>();
}
{% endprettify %}
### case_block_not_terminated
_The last statement of the 'case' should be 'break', 'continue', 'rethrow',
@ -15423,52 +15339,6 @@ class A {
class B implements A {}
{% endprettify %}
### non_leaf_call_must_not_take_typed_data
_FFI non-leaf calls can't take typed data arguments._
#### Description
The analyzer produces this diagnostic when the value of the `isLeaf`
argument of `Pointer.asFunction`, `DynamicLibrary.lookupFunction`, or
`@Native` is `false` and the Dart function signature contains a typed
data parameter.
Typed data unwrapping is only supported on arguments for leaf FFI calls.
For more information about FFI, see [C interop using dart:ffi][ffi].
#### Example
The following code produces this diagnostic because the dart function
signature contains a typed data, but the `isLeaf` argument is `false`:
{% prettify dart tag=pre+code %}
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<NativeFunction<Void Function(Pointer<Uint8>)>> p) {
p.asFunction<[!void Function(Uint8List)!]>();
}
{% endprettify %}
#### Common fixes
If the function has at least one typed data parameter, then add
the `isLeaf` argument:
{% prettify dart tag=pre+code %}
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<NativeFunction<Void Function(Pointer<Uint8>)>> p) {
p.asFunction<void Function(Uint8List)>(isLeaf: true);
}
{% endprettify %}
If the function also uses `Handle`s, then it must be non-leaf. In That
case use `Pointer`s instead of typed data.
### non_native_function_type_argument_to_pointer
_Can't invoke 'asFunction' because the function signature '{0}' for the pointer

View file

@ -61,8 +61,6 @@ export '../fasta/fasta_codes.dart'
messageFfiAbiSpecificIntegerInvalid,
messageFfiAbiSpecificIntegerMappingInvalid,
messageFfiAddressOfMustBeNative,
messageFfiCallbackMustNotUseTypedData,
messageFfiCallMustNotReturnTypedData,
messageFfiCreateOfStructOrUnion,
messageFfiDefaultAssetDuplicate,
messageFfiExceptionalReturnNull,
@ -75,7 +73,6 @@ export '../fasta/fasta_codes.dart'
messageFfiNativeFieldType,
messageFfiNativeMustBeExternal,
messageFfiNativeOnlyNativeFieldWrapperClassCanBePointer,
messageFfiNonLeafCallMustNotTakeTypedData,
messageFfiPackedAnnotationAlignment,
messageNonPositiveArrayDimensions,
messageWeakReferenceMismatchReturnAndArgumentTypes,

View file

@ -5218,27 +5218,6 @@ FfiLeafCallMustNotReturnHandle:
problemMessage: "FFI leaf call must not have Handle return type."
external: test/ffi_test.dart
FfiNonLeafCallMustNotTakeTypedData:
# Used by dart:ffi
problemMessage: "FFI non-leaf calls can't take typed data arguments."
correctionMessage: Try changing the call to a leaf call.
analyzerCode: NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA
external: test/ffi_test.dart
FfiCallMustNotReturnTypedData:
# Used by dart:ffi
problemMessage: "FFI calls can't return typed data."
correctionMessage: Try changing using `Pointer`s.
analyzerCode: CALL_MUST_NOT_RETURN_TYPED_DATA
external: test/ffi_test.dart
FfiCallbackMustNotUseTypedData:
# Used by dart:ffi
problemMessage: "FFI callbacks can't take typed data arguments or return value."
correctionMessage: Try changing using `Pointer`s.
analyzerCode: CALLBACK_MUST_NOT_USE_TYPED_DATA
external: test/ffi_test.dart
FfiNativeUnexpectedNumberOfParametersWithReceiver:
# Used by dart:ffi
problemMessage: "Unexpected number of Native annotation parameters. Expected #count but has #count2. Native instance method annotation must have receiver as first argument."

View file

@ -9,11 +9,8 @@ library vm.transformations.ffi;
import 'package:front_end/src/api_unstable/vm.dart'
show
messageFfiCallMustNotReturnTypedData,
messageFfiCallbackMustNotUseTypedData,
messageFfiLeafCallMustNotReturnHandle,
messageFfiLeafCallMustNotTakeHandle,
messageFfiNonLeafCallMustNotTakeTypedData,
messageNonPositiveArrayDimensions,
templateFfiSizeAnnotation,
templateFfiSizeAnnotationDimensions,
@ -307,9 +304,6 @@ class FfiTransformer extends Transformer {
final Map<NativeType, Class> nativeTypesClasses;
final Map<Class, NativeType> classNativeTypes;
/// Typed data classes.
final Map<NativeType, Class> nativeTypesTypedDataClasses;
Library? _currentLibrary;
Library get currentLibrary => _currentLibrary!;
@ -510,21 +504,6 @@ class FfiTransformer extends Transformer {
MapEntry(nativeType, index.getClass('dart:ffi', name))),
classNativeTypes = nativeTypeClassNames.map((nativeType, name) =>
MapEntry(index.getClass('dart:ffi', name), nativeType)),
nativeTypesTypedDataClasses = {
for (final nativeType in nativeIntTypesFixedSize)
nativeType: index.getClass(
'dart:typed_data',
'${nativeTypeClassNames[nativeType]}List',
),
NativeType.kFloat: index.getClass(
'dart:typed_data',
'Float32List',
),
NativeType.kDouble: index.getClass(
'dart:typed_data',
'Float64List',
),
},
loadMethods = Map.fromIterable(optimizedTypes, value: (t) {
final name = nativeTypeClassNames[t];
return index.getTopLevelProcedure('dart:ffi', "_load$name");
@ -639,27 +618,16 @@ class FfiTransformer extends Transformer {
/// [Bool] -> [bool]
/// [Void] -> [void]
/// [Pointer]<T> -> [Pointer]<T>
/// -> `${T}List` (from dart:typed_data)
/// T extends [Compound] -> T
/// [Handle] -> [Object]
/// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
/// where DartRepresentationOf(Tn) -> Sn
///
/// If [dartType] is provided, it can be used to guide what Dart type is
/// expected. Currently, this is only used if [allowTypedData] is provided,
/// because `Pointer` is a one to many mapping in this case.
///
/// Some Dart types only have one possible native type (and vice-versa). For
/// those types, [convertNativeTypeToDartType] is the inverse of
/// [convertDartTypeToNativeType].
DartType? convertNativeTypeToDartType(
DartType nativeType, {
DartType? dartType,
bool allowCompounds = false,
bool allowHandle = false,
bool allowInlineArray = false,
bool allowVoid = false,
bool allowTypedData = false,
}) {
if (nativeType is! InterfaceType) {
return null;
@ -698,20 +666,6 @@ class FfiTransformer extends Transformer {
return null;
}
if (nativeType_ == NativeType.kPointer) {
if (allowTypedData && dartType != null) {
final elementType = nativeType.typeArguments.single;
if (elementType is InterfaceType) {
final elementType_ = getType(elementType.classNode);
final typedDataClass = nativeTypesTypedDataClasses[elementType_];
if (typedDataClass != null) {
final typedDataType =
InterfaceType(typedDataClass, Nullability.nonNullable);
if (typedDataType == dartType) {
return dartType;
}
}
}
}
return nativeType;
}
if (nativeIntTypesFixedSize.contains(nativeType_)) {
@ -746,29 +700,21 @@ class FfiTransformer extends Transformer {
final DartType? returnType = convertNativeTypeToDartType(
fun.returnType,
dartType: dartType is! FunctionType ? null : dartType.returnType,
allowCompounds: true,
allowHandle: true,
allowVoid: true,
allowTypedData: allowTypedData,
);
if (returnType == null) return null;
final argumentTypes = <DartType>[];
int i = 0;
for (final paramDartType in flattenVarargs(fun).positionalParameters) {
argumentTypes.add(
convertNativeTypeToDartType(
paramDartType,
dartType: dartType is! FunctionType
? null
: dartType.positionalParameters.elementAtOrNull(i),
allowCompounds: true,
allowHandle: true,
allowTypedData: allowTypedData,
) ??
dummyDartType,
);
i++;
}
if (argumentTypes.contains(dummyDartType)) return null;
return FunctionType(argumentTypes, returnType, Nullability.legacy);
@ -1440,90 +1386,20 @@ class FfiTransformer extends Transformer {
}
}
void ensureOnlyLeafCallsUseTypedData(
DartType nativeType,
DartType dartType, {
required bool isLeaf,
required bool isCall,
required TreeNode reportErrorOn,
}) {
if (dartType is! FunctionType || nativeType is! FunctionType) {
return;
}
bool error = false;
final dartReturnType = dartType.returnType;
final nativeReturnType = nativeType.returnType;
if (dartReturnType is InterfaceType && nativeReturnType is InterfaceType) {
if (nativeTypesTypedDataClasses.values
.contains(dartReturnType.classNode)) {
final nativeIsPointer =
getType(nativeReturnType.classNode) == NativeType.kPointer;
if (nativeIsPointer) {
if (!isCall) {
// error callbacks
diagnosticReporter.report(messageFfiCallbackMustNotUseTypedData,
reportErrorOn.fileOffset, 1, reportErrorOn.location?.file);
} else {
// error return of call
diagnosticReporter.report(messageFfiCallMustNotReturnTypedData,
reportErrorOn.fileOffset, 1, reportErrorOn.location?.file);
}
error = true;
}
}
}
int i = 0;
nativeType = flattenVarargs(nativeType);
for (DartType dartParam in dartType.positionalParameters) {
final nativeParam = nativeType.positionalParameters[i];
i++;
if (dartParam is! InterfaceType || nativeParam is! InterfaceType) {
continue;
}
final nativeIsPointer =
getType(nativeParam.classNode) == NativeType.kPointer;
if (!nativeIsPointer) {
continue;
}
if (nativeTypesTypedDataClasses.values.contains(dartParam.classNode)) {
if (!isCall) {
// error callback
diagnosticReporter.report(messageFfiCallbackMustNotUseTypedData,
reportErrorOn.fileOffset, 1, reportErrorOn.location?.file);
error = true;
} else if (!isLeaf) {
// error not leaf
diagnosticReporter.report(messageFfiNonLeafCallMustNotTakeTypedData,
reportErrorOn.fileOffset, 1, reportErrorOn.location?.file);
error = true;
}
}
}
if (error) {
throw FfiStaticTypeError();
}
}
void ensureNativeTypeToDartType(
DartType nativeType,
DartType dartType,
TreeNode reportErrorOn, {
bool allowHandle = false,
bool allowVoid = false,
bool allowTypedData = false,
bool allowArray = false,
}) {
final DartType correspondingDartType = convertNativeTypeToDartType(
nativeType,
dartType: dartType,
allowCompounds: true,
allowHandle: allowHandle,
allowInlineArray: allowArray,
allowVoid: allowVoid,
allowTypedData: allowTypedData,
)!;
if (dartType == correspondingDartType) return;
if (env.isSubtypeOf(correspondingDartType, dartType,

View file

@ -960,20 +960,12 @@ class FfiNativeTransformer extends FfiTransformer {
wrappedDartFunctionType,
node,
allowHandle: true, // Handle-specific errors emitted below.
allowTypedData: true, // TypedData-specific errors emitted below.
);
ensureLeafCallDoesNotUseHandles(
nativeType,
isLeaf,
reportErrorOn: node,
);
ensureOnlyLeafCallsUseTypedData(
ffiFunctionType,
dartFunctionType,
isLeaf: isLeaf,
isCall: true,
reportErrorOn: node,
);
} on FfiStaticTypeError {
// It's OK to swallow the exception because the diagnostics issued will
// cause compilation to fail. By continuing, we can report more

View file

@ -359,20 +359,12 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
dartType,
node,
allowHandle: true, // Handle-specific errors emitted below.
allowTypedData: true, // TypedData-specific errors emitted below.
);
ensureLeafCallDoesNotUseHandles(
nativeType,
isLeaf,
reportErrorOn: node,
);
ensureOnlyLeafCallsUseTypedData(
node.arguments.types[0],
dartType,
isLeaf: isLeaf,
isCall: true,
reportErrorOn: node,
);
return _replaceLookupFunction(node);
} else if (target == asFunctionMethod) {
final dartType = node.arguments.types[1];
@ -388,20 +380,12 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
dartType,
node,
allowHandle: true, // Handle-specific errors emitted below.
allowTypedData: true, // TypedData-specific errors emitted below.
);
ensureLeafCallDoesNotUseHandles(
nativeType,
isLeaf,
reportErrorOn: node,
);
ensureOnlyLeafCallsUseTypedData(
node.arguments.types[0],
dartType,
isLeaf: isLeaf,
isCall: true,
reportErrorOn: node,
);
final DartType nativeSignature = nativeType.typeArguments[0];
return _replaceAsFunction(
@ -807,14 +791,6 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
nativeType,
dartType,
node,
allowTypedData: true, // TypedData-specific errors emitted below.
);
ensureOnlyLeafCallsUseTypedData(
node.arguments.types[0],
dartType,
isLeaf: false,
isCall: false,
reportErrorOn: node,
);
final funcType = dartType as FunctionType;

View file

@ -1087,7 +1087,6 @@ shared_library("ffi_test_functions") {
"ffi_test/ffi_test_fields.c",
"ffi_test/ffi_test_functions.cc",
"ffi_test/ffi_test_functions_generated.cc",
"ffi_test/ffi_test_functions_generated_2.cc",
"ffi_test/ffi_test_functions_vmspecific.cc",
]
if (is_win && current_cpu == "x64") {

View file

@ -1,770 +0,0 @@
// Copyright (c) 2023, 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.
//
// This file has been automatically generated. Please do not edit it manually.
// Generated by tests/ffi/generator/unwrap_typeddata_test_generator.dart.
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <cmath>
#include <iostream>
#include <limits>
#if defined(_WIN32)
#define DART_EXPORT extern "C" __declspec(dllexport)
#else
#define DART_EXPORT \
extern "C" __attribute__((visibility("default"))) __attribute((used))
#endif
namespace dart {
#define CHECK(X) \
if (!(X)) { \
fprintf(stderr, "%s\n", "Check failed: " #X); \
return 1; \
}
#define CHECK_EQ(X, Y) CHECK((X) == (Y))
// Works for positive, negative and zero.
#define CHECK_APPROX(EXPECTED, ACTUAL) \
CHECK(((EXPECTED * 0.99) <= (ACTUAL) && (EXPECTED * 1.01) >= (ACTUAL)) || \
((EXPECTED * 0.99) >= (ACTUAL) && (EXPECTED * 1.01) <= (ACTUAL)))
DART_EXPORT int8_t UnwrapInt8List(int8_t* data, size_t length) {
int8_t result = 0;
for (size_t i = 0; i < length; i++) {
std::cout << "data[" << i << "] = " << static_cast<int>(data[i]) << "\n";
result += data[i];
}
return result;
}
DART_EXPORT int8_t UnwrapInt8ListMany(int8_t* data0,
int8_t* data1,
int8_t* data2,
int8_t* data3,
int8_t* data4,
int8_t* data5,
int8_t* data6,
int8_t* data7,
int8_t* data8,
int8_t* data9,
int8_t* data10,
int8_t* data11,
int8_t* data12,
int8_t* data13,
int8_t* data14,
int8_t* data15,
int8_t* data16,
int8_t* data17,
int8_t* data18,
int8_t* data19) {
int8_t result = 0;
std::cout << "data0[0] = " << static_cast<int>(data0[0]) << "\n";
result += data0[0];
std::cout << "data1[0] = " << static_cast<int>(data1[0]) << "\n";
result += data1[0];
std::cout << "data2[0] = " << static_cast<int>(data2[0]) << "\n";
result += data2[0];
std::cout << "data3[0] = " << static_cast<int>(data3[0]) << "\n";
result += data3[0];
std::cout << "data4[0] = " << static_cast<int>(data4[0]) << "\n";
result += data4[0];
std::cout << "data5[0] = " << static_cast<int>(data5[0]) << "\n";
result += data5[0];
std::cout << "data6[0] = " << static_cast<int>(data6[0]) << "\n";
result += data6[0];
std::cout << "data7[0] = " << static_cast<int>(data7[0]) << "\n";
result += data7[0];
std::cout << "data8[0] = " << static_cast<int>(data8[0]) << "\n";
result += data8[0];
std::cout << "data9[0] = " << static_cast<int>(data9[0]) << "\n";
result += data9[0];
std::cout << "data10[0] = " << static_cast<int>(data10[0]) << "\n";
result += data10[0];
std::cout << "data11[0] = " << static_cast<int>(data11[0]) << "\n";
result += data11[0];
std::cout << "data12[0] = " << static_cast<int>(data12[0]) << "\n";
result += data12[0];
std::cout << "data13[0] = " << static_cast<int>(data13[0]) << "\n";
result += data13[0];
std::cout << "data14[0] = " << static_cast<int>(data14[0]) << "\n";
result += data14[0];
std::cout << "data15[0] = " << static_cast<int>(data15[0]) << "\n";
result += data15[0];
std::cout << "data16[0] = " << static_cast<int>(data16[0]) << "\n";
result += data16[0];
std::cout << "data17[0] = " << static_cast<int>(data17[0]) << "\n";
result += data17[0];
std::cout << "data18[0] = " << static_cast<int>(data18[0]) << "\n";
result += data18[0];
std::cout << "data19[0] = " << static_cast<int>(data19[0]) << "\n";
result += data19[0];
return result;
}
DART_EXPORT int16_t UnwrapInt16List(int16_t* data, size_t length) {
int16_t result = 0;
for (size_t i = 0; i < length; i++) {
std::cout << "data[" << i << "] = " << data[i] << "\n";
result += data[i];
}
return result;
}
DART_EXPORT int16_t UnwrapInt16ListMany(int16_t* data0,
int16_t* data1,
int16_t* data2,
int16_t* data3,
int16_t* data4,
int16_t* data5,
int16_t* data6,
int16_t* data7,
int16_t* data8,
int16_t* data9,
int16_t* data10,
int16_t* data11,
int16_t* data12,
int16_t* data13,
int16_t* data14,
int16_t* data15,
int16_t* data16,
int16_t* data17,
int16_t* data18,
int16_t* data19) {
int16_t result = 0;
std::cout << "data0[0] = " << data0[0] << "\n";
result += data0[0];
std::cout << "data1[0] = " << data1[0] << "\n";
result += data1[0];
std::cout << "data2[0] = " << data2[0] << "\n";
result += data2[0];
std::cout << "data3[0] = " << data3[0] << "\n";
result += data3[0];
std::cout << "data4[0] = " << data4[0] << "\n";
result += data4[0];
std::cout << "data5[0] = " << data5[0] << "\n";
result += data5[0];
std::cout << "data6[0] = " << data6[0] << "\n";
result += data6[0];
std::cout << "data7[0] = " << data7[0] << "\n";
result += data7[0];
std::cout << "data8[0] = " << data8[0] << "\n";
result += data8[0];
std::cout << "data9[0] = " << data9[0] << "\n";
result += data9[0];
std::cout << "data10[0] = " << data10[0] << "\n";
result += data10[0];
std::cout << "data11[0] = " << data11[0] << "\n";
result += data11[0];
std::cout << "data12[0] = " << data12[0] << "\n";
result += data12[0];
std::cout << "data13[0] = " << data13[0] << "\n";
result += data13[0];
std::cout << "data14[0] = " << data14[0] << "\n";
result += data14[0];
std::cout << "data15[0] = " << data15[0] << "\n";
result += data15[0];
std::cout << "data16[0] = " << data16[0] << "\n";
result += data16[0];
std::cout << "data17[0] = " << data17[0] << "\n";
result += data17[0];
std::cout << "data18[0] = " << data18[0] << "\n";
result += data18[0];
std::cout << "data19[0] = " << data19[0] << "\n";
result += data19[0];
return result;
}
DART_EXPORT int32_t UnwrapInt32List(int32_t* data, size_t length) {
int32_t result = 0;
for (size_t i = 0; i < length; i++) {
std::cout << "data[" << i << "] = " << data[i] << "\n";
result += data[i];
}
return result;
}
DART_EXPORT int32_t UnwrapInt32ListMany(int32_t* data0,
int32_t* data1,
int32_t* data2,
int32_t* data3,
int32_t* data4,
int32_t* data5,
int32_t* data6,
int32_t* data7,
int32_t* data8,
int32_t* data9,
int32_t* data10,
int32_t* data11,
int32_t* data12,
int32_t* data13,
int32_t* data14,
int32_t* data15,
int32_t* data16,
int32_t* data17,
int32_t* data18,
int32_t* data19) {
int32_t result = 0;
std::cout << "data0[0] = " << data0[0] << "\n";
result += data0[0];
std::cout << "data1[0] = " << data1[0] << "\n";
result += data1[0];
std::cout << "data2[0] = " << data2[0] << "\n";
result += data2[0];
std::cout << "data3[0] = " << data3[0] << "\n";
result += data3[0];
std::cout << "data4[0] = " << data4[0] << "\n";
result += data4[0];
std::cout << "data5[0] = " << data5[0] << "\n";
result += data5[0];
std::cout << "data6[0] = " << data6[0] << "\n";
result += data6[0];
std::cout << "data7[0] = " << data7[0] << "\n";
result += data7[0];
std::cout << "data8[0] = " << data8[0] << "\n";
result += data8[0];
std::cout << "data9[0] = " << data9[0] << "\n";
result += data9[0];
std::cout << "data10[0] = " << data10[0] << "\n";
result += data10[0];
std::cout << "data11[0] = " << data11[0] << "\n";
result += data11[0];
std::cout << "data12[0] = " << data12[0] << "\n";
result += data12[0];
std::cout << "data13[0] = " << data13[0] << "\n";
result += data13[0];
std::cout << "data14[0] = " << data14[0] << "\n";
result += data14[0];
std::cout << "data15[0] = " << data15[0] << "\n";
result += data15[0];
std::cout << "data16[0] = " << data16[0] << "\n";
result += data16[0];
std::cout << "data17[0] = " << data17[0] << "\n";
result += data17[0];
std::cout << "data18[0] = " << data18[0] << "\n";
result += data18[0];
std::cout << "data19[0] = " << data19[0] << "\n";
result += data19[0];
return result;
}
DART_EXPORT int64_t UnwrapInt64List(int64_t* data, size_t length) {
int64_t result = 0;
for (size_t i = 0; i < length; i++) {
std::cout << "data[" << i << "] = " << data[i] << "\n";
result += data[i];
}
return result;
}
DART_EXPORT int64_t UnwrapInt64ListMany(int64_t* data0,
int64_t* data1,
int64_t* data2,
int64_t* data3,
int64_t* data4,
int64_t* data5,
int64_t* data6,
int64_t* data7,
int64_t* data8,
int64_t* data9,
int64_t* data10,
int64_t* data11,
int64_t* data12,
int64_t* data13,
int64_t* data14,
int64_t* data15,
int64_t* data16,
int64_t* data17,
int64_t* data18,
int64_t* data19) {
int64_t result = 0;
std::cout << "data0[0] = " << data0[0] << "\n";
result += data0[0];
std::cout << "data1[0] = " << data1[0] << "\n";
result += data1[0];
std::cout << "data2[0] = " << data2[0] << "\n";
result += data2[0];
std::cout << "data3[0] = " << data3[0] << "\n";
result += data3[0];
std::cout << "data4[0] = " << data4[0] << "\n";
result += data4[0];
std::cout << "data5[0] = " << data5[0] << "\n";
result += data5[0];
std::cout << "data6[0] = " << data6[0] << "\n";
result += data6[0];
std::cout << "data7[0] = " << data7[0] << "\n";
result += data7[0];
std::cout << "data8[0] = " << data8[0] << "\n";
result += data8[0];
std::cout << "data9[0] = " << data9[0] << "\n";
result += data9[0];
std::cout << "data10[0] = " << data10[0] << "\n";
result += data10[0];
std::cout << "data11[0] = " << data11[0] << "\n";
result += data11[0];
std::cout << "data12[0] = " << data12[0] << "\n";
result += data12[0];
std::cout << "data13[0] = " << data13[0] << "\n";
result += data13[0];
std::cout << "data14[0] = " << data14[0] << "\n";
result += data14[0];
std::cout << "data15[0] = " << data15[0] << "\n";
result += data15[0];
std::cout << "data16[0] = " << data16[0] << "\n";
result += data16[0];
std::cout << "data17[0] = " << data17[0] << "\n";
result += data17[0];
std::cout << "data18[0] = " << data18[0] << "\n";
result += data18[0];
std::cout << "data19[0] = " << data19[0] << "\n";
result += data19[0];
return result;
}
DART_EXPORT uint8_t UnwrapUint8List(uint8_t* data, size_t length) {
uint8_t result = 0;
for (size_t i = 0; i < length; i++) {
std::cout << "data[" << i << "] = " << static_cast<int>(data[i]) << "\n";
result += data[i];
}
return result;
}
DART_EXPORT uint8_t UnwrapUint8ListMany(uint8_t* data0,
uint8_t* data1,
uint8_t* data2,
uint8_t* data3,
uint8_t* data4,
uint8_t* data5,
uint8_t* data6,
uint8_t* data7,
uint8_t* data8,
uint8_t* data9,
uint8_t* data10,
uint8_t* data11,
uint8_t* data12,
uint8_t* data13,
uint8_t* data14,
uint8_t* data15,
uint8_t* data16,
uint8_t* data17,
uint8_t* data18,
uint8_t* data19) {
uint8_t result = 0;
std::cout << "data0[0] = " << static_cast<int>(data0[0]) << "\n";
result += data0[0];
std::cout << "data1[0] = " << static_cast<int>(data1[0]) << "\n";
result += data1[0];
std::cout << "data2[0] = " << static_cast<int>(data2[0]) << "\n";
result += data2[0];
std::cout << "data3[0] = " << static_cast<int>(data3[0]) << "\n";
result += data3[0];
std::cout << "data4[0] = " << static_cast<int>(data4[0]) << "\n";
result += data4[0];
std::cout << "data5[0] = " << static_cast<int>(data5[0]) << "\n";
result += data5[0];
std::cout << "data6[0] = " << static_cast<int>(data6[0]) << "\n";
result += data6[0];
std::cout << "data7[0] = " << static_cast<int>(data7[0]) << "\n";
result += data7[0];
std::cout << "data8[0] = " << static_cast<int>(data8[0]) << "\n";
result += data8[0];
std::cout << "data9[0] = " << static_cast<int>(data9[0]) << "\n";
result += data9[0];
std::cout << "data10[0] = " << static_cast<int>(data10[0]) << "\n";
result += data10[0];
std::cout << "data11[0] = " << static_cast<int>(data11[0]) << "\n";
result += data11[0];
std::cout << "data12[0] = " << static_cast<int>(data12[0]) << "\n";
result += data12[0];
std::cout << "data13[0] = " << static_cast<int>(data13[0]) << "\n";
result += data13[0];
std::cout << "data14[0] = " << static_cast<int>(data14[0]) << "\n";
result += data14[0];
std::cout << "data15[0] = " << static_cast<int>(data15[0]) << "\n";
result += data15[0];
std::cout << "data16[0] = " << static_cast<int>(data16[0]) << "\n";
result += data16[0];
std::cout << "data17[0] = " << static_cast<int>(data17[0]) << "\n";
result += data17[0];
std::cout << "data18[0] = " << static_cast<int>(data18[0]) << "\n";
result += data18[0];
std::cout << "data19[0] = " << static_cast<int>(data19[0]) << "\n";
result += data19[0];
return result;
}
DART_EXPORT uint16_t UnwrapUint16List(uint16_t* data, size_t length) {
uint16_t result = 0;
for (size_t i = 0; i < length; i++) {
std::cout << "data[" << i << "] = " << data[i] << "\n";
result += data[i];
}
return result;
}
DART_EXPORT uint16_t UnwrapUint16ListMany(uint16_t* data0,
uint16_t* data1,
uint16_t* data2,
uint16_t* data3,
uint16_t* data4,
uint16_t* data5,
uint16_t* data6,
uint16_t* data7,
uint16_t* data8,
uint16_t* data9,
uint16_t* data10,
uint16_t* data11,
uint16_t* data12,
uint16_t* data13,
uint16_t* data14,
uint16_t* data15,
uint16_t* data16,
uint16_t* data17,
uint16_t* data18,
uint16_t* data19) {
uint16_t result = 0;
std::cout << "data0[0] = " << data0[0] << "\n";
result += data0[0];
std::cout << "data1[0] = " << data1[0] << "\n";
result += data1[0];
std::cout << "data2[0] = " << data2[0] << "\n";
result += data2[0];
std::cout << "data3[0] = " << data3[0] << "\n";
result += data3[0];
std::cout << "data4[0] = " << data4[0] << "\n";
result += data4[0];
std::cout << "data5[0] = " << data5[0] << "\n";
result += data5[0];
std::cout << "data6[0] = " << data6[0] << "\n";
result += data6[0];
std::cout << "data7[0] = " << data7[0] << "\n";
result += data7[0];
std::cout << "data8[0] = " << data8[0] << "\n";
result += data8[0];
std::cout << "data9[0] = " << data9[0] << "\n";
result += data9[0];
std::cout << "data10[0] = " << data10[0] << "\n";
result += data10[0];
std::cout << "data11[0] = " << data11[0] << "\n";
result += data11[0];
std::cout << "data12[0] = " << data12[0] << "\n";
result += data12[0];
std::cout << "data13[0] = " << data13[0] << "\n";
result += data13[0];
std::cout << "data14[0] = " << data14[0] << "\n";
result += data14[0];
std::cout << "data15[0] = " << data15[0] << "\n";
result += data15[0];
std::cout << "data16[0] = " << data16[0] << "\n";
result += data16[0];
std::cout << "data17[0] = " << data17[0] << "\n";
result += data17[0];
std::cout << "data18[0] = " << data18[0] << "\n";
result += data18[0];
std::cout << "data19[0] = " << data19[0] << "\n";
result += data19[0];
return result;
}
DART_EXPORT uint32_t UnwrapUint32List(uint32_t* data, size_t length) {
uint32_t result = 0;
for (size_t i = 0; i < length; i++) {
std::cout << "data[" << i << "] = " << data[i] << "\n";
result += data[i];
}
return result;
}
DART_EXPORT uint32_t UnwrapUint32ListMany(uint32_t* data0,
uint32_t* data1,
uint32_t* data2,
uint32_t* data3,
uint32_t* data4,
uint32_t* data5,
uint32_t* data6,
uint32_t* data7,
uint32_t* data8,
uint32_t* data9,
uint32_t* data10,
uint32_t* data11,
uint32_t* data12,
uint32_t* data13,
uint32_t* data14,
uint32_t* data15,
uint32_t* data16,
uint32_t* data17,
uint32_t* data18,
uint32_t* data19) {
uint32_t result = 0;
std::cout << "data0[0] = " << data0[0] << "\n";
result += data0[0];
std::cout << "data1[0] = " << data1[0] << "\n";
result += data1[0];
std::cout << "data2[0] = " << data2[0] << "\n";
result += data2[0];
std::cout << "data3[0] = " << data3[0] << "\n";
result += data3[0];
std::cout << "data4[0] = " << data4[0] << "\n";
result += data4[0];
std::cout << "data5[0] = " << data5[0] << "\n";
result += data5[0];
std::cout << "data6[0] = " << data6[0] << "\n";
result += data6[0];
std::cout << "data7[0] = " << data7[0] << "\n";
result += data7[0];
std::cout << "data8[0] = " << data8[0] << "\n";
result += data8[0];
std::cout << "data9[0] = " << data9[0] << "\n";
result += data9[0];
std::cout << "data10[0] = " << data10[0] << "\n";
result += data10[0];
std::cout << "data11[0] = " << data11[0] << "\n";
result += data11[0];
std::cout << "data12[0] = " << data12[0] << "\n";
result += data12[0];
std::cout << "data13[0] = " << data13[0] << "\n";
result += data13[0];
std::cout << "data14[0] = " << data14[0] << "\n";
result += data14[0];
std::cout << "data15[0] = " << data15[0] << "\n";
result += data15[0];
std::cout << "data16[0] = " << data16[0] << "\n";
result += data16[0];
std::cout << "data17[0] = " << data17[0] << "\n";
result += data17[0];
std::cout << "data18[0] = " << data18[0] << "\n";
result += data18[0];
std::cout << "data19[0] = " << data19[0] << "\n";
result += data19[0];
return result;
}
DART_EXPORT uint64_t UnwrapUint64List(uint64_t* data, size_t length) {
uint64_t result = 0;
for (size_t i = 0; i < length; i++) {
std::cout << "data[" << i << "] = " << data[i] << "\n";
result += data[i];
}
return result;
}
DART_EXPORT uint64_t UnwrapUint64ListMany(uint64_t* data0,
uint64_t* data1,
uint64_t* data2,
uint64_t* data3,
uint64_t* data4,
uint64_t* data5,
uint64_t* data6,
uint64_t* data7,
uint64_t* data8,
uint64_t* data9,
uint64_t* data10,
uint64_t* data11,
uint64_t* data12,
uint64_t* data13,
uint64_t* data14,
uint64_t* data15,
uint64_t* data16,
uint64_t* data17,
uint64_t* data18,
uint64_t* data19) {
uint64_t result = 0;
std::cout << "data0[0] = " << data0[0] << "\n";
result += data0[0];
std::cout << "data1[0] = " << data1[0] << "\n";
result += data1[0];
std::cout << "data2[0] = " << data2[0] << "\n";
result += data2[0];
std::cout << "data3[0] = " << data3[0] << "\n";
result += data3[0];
std::cout << "data4[0] = " << data4[0] << "\n";
result += data4[0];
std::cout << "data5[0] = " << data5[0] << "\n";
result += data5[0];
std::cout << "data6[0] = " << data6[0] << "\n";
result += data6[0];
std::cout << "data7[0] = " << data7[0] << "\n";
result += data7[0];
std::cout << "data8[0] = " << data8[0] << "\n";
result += data8[0];
std::cout << "data9[0] = " << data9[0] << "\n";
result += data9[0];
std::cout << "data10[0] = " << data10[0] << "\n";
result += data10[0];
std::cout << "data11[0] = " << data11[0] << "\n";
result += data11[0];
std::cout << "data12[0] = " << data12[0] << "\n";
result += data12[0];
std::cout << "data13[0] = " << data13[0] << "\n";
result += data13[0];
std::cout << "data14[0] = " << data14[0] << "\n";
result += data14[0];
std::cout << "data15[0] = " << data15[0] << "\n";
result += data15[0];
std::cout << "data16[0] = " << data16[0] << "\n";
result += data16[0];
std::cout << "data17[0] = " << data17[0] << "\n";
result += data17[0];
std::cout << "data18[0] = " << data18[0] << "\n";
result += data18[0];
std::cout << "data19[0] = " << data19[0] << "\n";
result += data19[0];
return result;
}
DART_EXPORT float UnwrapFloat32List(float* data, size_t length) {
float result = 0;
for (size_t i = 0; i < length; i++) {
std::cout << "data[" << i << "] = " << data[i] << "\n";
result += data[i];
}
return result;
}
DART_EXPORT float UnwrapFloat32ListMany(float* data0,
float* data1,
float* data2,
float* data3,
float* data4,
float* data5,
float* data6,
float* data7,
float* data8,
float* data9,
float* data10,
float* data11,
float* data12,
float* data13,
float* data14,
float* data15,
float* data16,
float* data17,
float* data18,
float* data19) {
float result = 0;
std::cout << "data0[0] = " << data0[0] << "\n";
result += data0[0];
std::cout << "data1[0] = " << data1[0] << "\n";
result += data1[0];
std::cout << "data2[0] = " << data2[0] << "\n";
result += data2[0];
std::cout << "data3[0] = " << data3[0] << "\n";
result += data3[0];
std::cout << "data4[0] = " << data4[0] << "\n";
result += data4[0];
std::cout << "data5[0] = " << data5[0] << "\n";
result += data5[0];
std::cout << "data6[0] = " << data6[0] << "\n";
result += data6[0];
std::cout << "data7[0] = " << data7[0] << "\n";
result += data7[0];
std::cout << "data8[0] = " << data8[0] << "\n";
result += data8[0];
std::cout << "data9[0] = " << data9[0] << "\n";
result += data9[0];
std::cout << "data10[0] = " << data10[0] << "\n";
result += data10[0];
std::cout << "data11[0] = " << data11[0] << "\n";
result += data11[0];
std::cout << "data12[0] = " << data12[0] << "\n";
result += data12[0];
std::cout << "data13[0] = " << data13[0] << "\n";
result += data13[0];
std::cout << "data14[0] = " << data14[0] << "\n";
result += data14[0];
std::cout << "data15[0] = " << data15[0] << "\n";
result += data15[0];
std::cout << "data16[0] = " << data16[0] << "\n";
result += data16[0];
std::cout << "data17[0] = " << data17[0] << "\n";
result += data17[0];
std::cout << "data18[0] = " << data18[0] << "\n";
result += data18[0];
std::cout << "data19[0] = " << data19[0] << "\n";
result += data19[0];
return result;
}
DART_EXPORT double UnwrapFloat64List(double* data, size_t length) {
double result = 0;
for (size_t i = 0; i < length; i++) {
std::cout << "data[" << i << "] = " << data[i] << "\n";
result += data[i];
}
return result;
}
DART_EXPORT double UnwrapFloat64ListMany(double* data0,
double* data1,
double* data2,
double* data3,
double* data4,
double* data5,
double* data6,
double* data7,
double* data8,
double* data9,
double* data10,
double* data11,
double* data12,
double* data13,
double* data14,
double* data15,
double* data16,
double* data17,
double* data18,
double* data19) {
double result = 0;
std::cout << "data0[0] = " << data0[0] << "\n";
result += data0[0];
std::cout << "data1[0] = " << data1[0] << "\n";
result += data1[0];
std::cout << "data2[0] = " << data2[0] << "\n";
result += data2[0];
std::cout << "data3[0] = " << data3[0] << "\n";
result += data3[0];
std::cout << "data4[0] = " << data4[0] << "\n";
result += data4[0];
std::cout << "data5[0] = " << data5[0] << "\n";
result += data5[0];
std::cout << "data6[0] = " << data6[0] << "\n";
result += data6[0];
std::cout << "data7[0] = " << data7[0] << "\n";
result += data7[0];
std::cout << "data8[0] = " << data8[0] << "\n";
result += data8[0];
std::cout << "data9[0] = " << data9[0] << "\n";
result += data9[0];
std::cout << "data10[0] = " << data10[0] << "\n";
result += data10[0];
std::cout << "data11[0] = " << data11[0] << "\n";
result += data11[0];
std::cout << "data12[0] = " << data12[0] << "\n";
result += data12[0];
std::cout << "data13[0] = " << data13[0] << "\n";
result += data13[0];
std::cout << "data14[0] = " << data14[0] << "\n";
result += data14[0];
std::cout << "data15[0] = " << data15[0] << "\n";
result += data15[0];
std::cout << "data16[0] = " << data16[0] << "\n";
result += data16[0];
std::cout << "data17[0] = " << data17[0] << "\n";
result += data17[0];
std::cout << "data18[0] = " << data18[0] << "\n";
result += data18[0];
std::cout << "data19[0] = " << data19[0] << "\n";
result += data19[0];
return result;
}
} // namespace dart

View file

@ -7417,7 +7417,7 @@ void FfiCallInstr::EmitParamMoves(FlowGraphCompiler* compiler,
// FfiCall to the right native location based on calling convention.
for (intptr_t i = 0; i < num_defs; i++) {
__ Comment(" def_index %" Pd, def_index);
Location origin = rebase.Rebase(locs()->in(def_index));
const Location origin = rebase.Rebase(locs()->in(def_index));
const Representation origin_rep =
RequiredInputRepresentation(def_index) == kTagged
? kUnboxedFfiIntPtr // When arg_target.IsPointerToMemory().
@ -7437,17 +7437,14 @@ void FfiCallInstr::EmitParamMoves(FlowGraphCompiler* compiler,
if (origin.IsConstant()) {
__ Comment("origin.IsConstant()");
ASSERT(!marshaller_.IsHandle(arg_index));
ASSERT(!marshaller_.IsTypedData(arg_index));
compiler->EmitMoveConst(def_target, origin, origin_rep, &temp_alloc);
} else if (origin.IsPairLocation() &&
(origin.AsPairLocation()->At(0).IsConstant() ||
origin.AsPairLocation()->At(1).IsConstant())) {
ASSERT(!marshaller_.IsTypedData(arg_index));
// Note: half of the pair can be constant.
__ Comment("origin.IsPairLocation() and constant");
compiler->EmitMoveConst(def_target, origin, origin_rep, &temp_alloc);
} else if (marshaller_.IsHandle(arg_index)) {
ASSERT(!marshaller_.IsTypedData(arg_index));
__ Comment("marshaller_.IsHandle(arg_index)");
// Handles are passed into FfiCalls as Tagged values on the stack, and
// then we pass pointers to these handles to the native function here.
@ -7486,20 +7483,6 @@ void FfiCallInstr::EmitParamMoves(FlowGraphCompiler* compiler,
marshaller_.RequiredStackSpaceInBytes());
}
#endif
if (marshaller_.IsTypedData(arg_index)) {
// Unwrap typed data before move to native location.
__ Comment("marshaller_.IsTypedData(arg_index)");
if (origin.IsStackSlot()) {
compiler->EmitMove(Location::RegisterLocation(temp0), origin,
&temp_alloc);
origin = Location::RegisterLocation(temp0);
}
ASSERT(origin.IsRegister());
__ LoadField(
origin.reg(),
compiler::FieldAddress(
origin.reg(), compiler::target::PointerBase::data_offset()));
}
compiler->EmitMoveToNative(def_target, origin, origin_rep, &temp_alloc);
}
def_index++;

View file

@ -143,56 +143,6 @@ AbstractTypePtr BaseMarshaller::CType(intptr_t arg_index) const {
return c_signature_.ParameterTypeAt(real_arg_index);
}
AbstractTypePtr BaseMarshaller::DartType(intptr_t arg_index) const {
if (arg_index == kResultIndex) {
return dart_signature_.result_type();
}
const intptr_t real_arg_index = arg_index + dart_signature_params_start_at_;
ASSERT(!Array::Handle(dart_signature_.parameter_types()).IsNull());
ASSERT(real_arg_index <
Array::Handle(dart_signature_.parameter_types()).Length());
ASSERT(!AbstractType::Handle(dart_signature_.ParameterTypeAt(real_arg_index))
.IsNull());
return dart_signature_.ParameterTypeAt(real_arg_index);
}
bool BaseMarshaller::IsTypedData(intptr_t arg_index) const {
if (IsHandle(arg_index)) {
return false;
}
if (Array::Handle(zone_, dart_signature_.parameter_types()).IsNull()) {
// TODO(https://dartbug.com/54173): BuildGraphOfSyncFfiCallback provides a
// function object with its type arguments not initialized. Change this
// to an assert when addressing that issue.
return false;
}
const auto& type = AbstractType::Handle(zone_, DartType(arg_index));
// The classes here are not the recognized classes, but the interface types.
// Consequently, the class ids are not predefined.
const auto& klass = Class::Handle(zone_, type.type_class());
if (klass.library() != Library::TypedDataLibrary()) {
return false;
}
#define CHECK_SYMBOL(symbol) \
if (klass.UserVisibleName() == Symbols::symbol().ptr()) { \
return true; \
}
CHECK_SYMBOL(Int8List)
CHECK_SYMBOL(Int16List)
CHECK_SYMBOL(Int32List)
CHECK_SYMBOL(Int64List)
CHECK_SYMBOL(Uint8List)
CHECK_SYMBOL(Uint16List)
CHECK_SYMBOL(Uint32List)
CHECK_SYMBOL(Uint64List)
CHECK_SYMBOL(Float32List)
CHECK_SYMBOL(Float64List)
#undef CHECK_SYMBOL
return false;
}
// Keep consistent with Function::FfiCSignatureReturnsStruct.
bool BaseMarshaller::IsCompound(intptr_t arg_index) const {
const auto& type = AbstractType::Handle(zone_, CType(arg_index));
@ -389,9 +339,6 @@ Representation BaseMarshaller::RepInFfiCall(intptr_t def_index_global) const {
Representation CallMarshaller::RepInFfiCall(intptr_t def_index_global) const {
intptr_t arg_index = ArgumentIndex(def_index_global);
if (IsTypedData(arg_index)) {
return kTagged;
}
const auto& location = Location(arg_index);
if (location.IsPointerToMemory()) {
if (ArgumentIndexIsReturn(arg_index)) {

View file

@ -108,13 +108,11 @@ class BaseMarshaller : public ZoneAllocated {
// Recurses into VarArgs if needed.
AbstractTypePtr CType(intptr_t arg_index) const;
AbstractTypePtr DartType(intptr_t arg_index) const;
// The Dart and C Type is Pointer.
//
// Requires boxing or unboxing the Pointer object to int.
bool IsPointer(intptr_t arg_index) const {
if (IsHandle(arg_index) || IsTypedData(arg_index)) {
if (IsHandle(arg_index)) {
return false;
}
return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
@ -128,12 +126,6 @@ class BaseMarshaller : public ZoneAllocated {
return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
kFfiHandleCid;
}
// The Dart type is a TypedData and C Type is Pointer.
//
// Requires unboxing the typed data to an int address.
bool IsTypedData(intptr_t arg_index) const;
bool IsBool(intptr_t arg_index) const {
return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
kFfiBoolCid;

View file

@ -5240,10 +5240,6 @@ Fragment FlowGraphBuilder::FfiConvertPrimitiveToDart(
if (marshaller.IsPointer(arg_index)) {
body += Box(kUnboxedFfiIntPtr);
body += FfiPointerFromAddress();
} else if (marshaller.IsTypedData(arg_index)) {
// Only FFI call arguments can be TypedData, so only reachable in
// `FfiConvertPrimitiveToNative`.
UNREACHABLE();
} else if (marshaller.IsHandle(arg_index)) {
body += UnwrapHandle();
} else if (marshaller.IsVoid(arg_index)) {
@ -5276,8 +5272,6 @@ Fragment FlowGraphBuilder::FfiConvertPrimitiveToNative(
body += LoadNativeField(Slot::PointerBase_data(),
InnerPointerAccess::kCannotBeInnerPointer);
body += ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr);
} else if (marshaller.IsTypedData(arg_index)) {
// Nothing to do yet. Unwrap in `FfiCallInstr::EmitNativeCode`.
} else if (marshaller.IsHandle(arg_index)) {
body += WrapHandle();
} else {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,101 +0,0 @@
// Copyright (c) 2023, 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';
import 'dart:typed_data';
import 'dylib_utils.dart';
void main() {}
final testLibrary = dlopenPlatformSpecific("ffi_test_functions");
final unwrapInt8List = testLibrary.lookupFunction<
Int8 Function(Pointer<Int8>, Int64),
int Function(Int8List, int)>('UnwrapInt8List', isLeaf: true);
final unwrapFloat64List = testLibrary.lookupFunction<
Int8 Function(Pointer<Double>, Int64),
int Function(Float64List, int)>('UnwrapFloat64List', isLeaf: true);
final unwrapFloat32List = testLibrary.lookupFunction<
Int8 Function(Pointer<Float>, Int64),
int Function(Float32List, int)>('UnwrapFloat32List', isLeaf: true);
final typedDataInHandle = testLibrary.lookupFunction<
Int8 Function(Handle, Int64),
int Function(Int8List, int)>('TypedDataInHandle');
final unwrapInt8List2 = testLibrary.lookupFunction<
// ^
// [cfe] FFI non-leaf calls can't take typed data arguments.
Int8 Function(Pointer<Int8>, Int64),
int Function(Int8List, int)>('UnwrapInt8List');
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.NON_LEAF_CALL_MUST_NOT_TAKE_TYPED_DATA
final unwrapInt8List3 = testLibrary.lookupFunction<
// ^
// [cfe] Expected type 'int Function(Int8List, int)' to be 'int Function(Pointer<Uint64>, int)', which is the Dart type corresponding to 'NativeFunction<Int8 Function(Pointer<Uint64>, Int64)>'.
Int8 Function(Pointer<Uint64>, Int64),
int Function(Int8List, int)>('UnwrapInt8List', isLeaf: true);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.MUST_BE_A_SUBTYPE
final unwrapInt8List4 = testLibrary.lookupFunction<
// ^
// [cfe] Expected type 'int Function(Float32List, int)' to be 'int Function(Pointer<Int8>, int)', which is the Dart type corresponding to 'NativeFunction<Int8 Function(Pointer<Int8>, Int64)>'.
Int8 Function(Pointer<Int8>, Int64),
int Function(Float32List, int)>('UnwrapInt8List', isLeaf: true);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.MUST_BE_A_SUBTYPE
@Native<Int8 Function(Pointer<Int8>, Int64)>(
symbol: 'UnwrapInt8List', isLeaf: true)
external int unwrapInt8List5(Int8List list, int length);
final unwrapInt8List7 =
testLibrary.lookupFunction<Pointer<Int8> Function(), Int8List Function()>(
// ^
// [cfe] FFI calls can't return typed data.
// ^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CALL_MUST_NOT_RETURN_TYPED_DATA
'UnwrapInt8List',
);
external int f1(Int8List i);
void g1() {
Pointer.fromFunction<Int8 Function(Pointer<Int8>)>(f1, 5);
// ^
// [cfe] FFI callbacks can't take typed data arguments or return value.
// ^^
// [analyzer] COMPILE_TIME_ERROR.CALLBACK_MUST_NOT_USE_TYPED_DATA
Pointer.fromFunction<Int8 Function(Handle)>(f1, 5);
}
external Int8List f2(int i);
void g2() {
Pointer.fromFunction<Pointer<Int8> Function(Int8)>(f2);
// ^
// [cfe] FFI callbacks can't take typed data arguments or return value.
// ^^
// [analyzer] COMPILE_TIME_ERROR.CALLBACK_MUST_NOT_USE_TYPED_DATA
}
void foo1(Pointer<NativeFunction<Pointer<Uint8> Function()>> p) {
p.asFunction<Uint8List Function()>(isLeaf: true);
//^
// [cfe] FFI calls can't return typed data.
// ^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CALL_MUST_NOT_RETURN_TYPED_DATA
}
// TODO(https://dartbug.com/54181): Write negative tests for @Natives.