mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 15:01:30 +00:00
827d166ea0
All `Pointer`s will now have the `Never` type argument at runtime. TEST=tests/ffi(_2)/* Bug: https://github.com/dart-lang/sdk/issues/49935 Change-Id: I83c8bba9461c2cab22992ba2e3cf42b7b5f43c36 Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-kernel-win-debug-x64-try,vm-kernel-precomp-win-debug-x64c-try,vm-kernel-mac-debug-x64-try,dart-sdk-mac-arm64-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-ffi-android-debug-arm64c-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/272201 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
237 lines
8.2 KiB
Dart
237 lines
8.2 KiB
Dart
// Copyright (c) 2019, 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.
|
|
//
|
|
// VMOptions=
|
|
// VMOptions=--deterministic --optimization-counter-threshold=90
|
|
// VMOptions=--use-slow-path
|
|
// SharedObjects=ffi_test_functions
|
|
//
|
|
// This file tests subtyping relationships (at compile time and at runtime) of
|
|
// parameters and return types of ffi trampolines and ffi callback trampolines.
|
|
|
|
import 'dart:ffi';
|
|
|
|
import "package:expect/expect.dart";
|
|
import "package:ffi/ffi.dart";
|
|
|
|
import 'dylib_utils.dart';
|
|
|
|
typedef Int64PointerParamOpDart = void Function(Pointer<Int64>);
|
|
typedef Int64PointerParamOp = Void Function(Pointer<Int64>);
|
|
typedef NaTyPointerParamOpDart = void Function(Pointer<NativeType>);
|
|
typedef NaTyPointerParamOp = Void Function(Pointer<NativeType>);
|
|
typedef Int64PointerReturnOp = Pointer<Int64> Function();
|
|
typedef NaTyPointerReturnOp = Pointer<NativeType> Function();
|
|
|
|
final paramOpName = "NativeTypePointerParam";
|
|
final returnOpName = "NativeTypePointerReturn";
|
|
|
|
final DynamicLibrary ffiTestFunctions =
|
|
dlopenPlatformSpecific("ffi_test_functions");
|
|
|
|
// =============================================
|
|
// Tests calls from Dart to native (asFunction).
|
|
// =============================================
|
|
|
|
void paramInvariant1() {
|
|
final fp =
|
|
ffiTestFunctions.lookup<NativeFunction<Int64PointerParamOp>>(paramOpName);
|
|
final f = fp.asFunction<Int64PointerParamOpDart>();
|
|
final arg = calloc<Int64>();
|
|
f(arg);
|
|
calloc.free(arg);
|
|
}
|
|
|
|
void paramInvariant2() {
|
|
final fp =
|
|
ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
|
|
final f = fp.asFunction<NaTyPointerParamOpDart>();
|
|
final arg = calloc<Int64>().cast<NativeType>();
|
|
Expect.type<Pointer<NativeType>>(arg);
|
|
f(arg);
|
|
calloc.free(arg);
|
|
}
|
|
|
|
// Pass a statically and dynamically subtyped argument.
|
|
void paramSubtype1() {
|
|
final fp =
|
|
ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
|
|
final f = fp.asFunction<NaTyPointerParamOpDart>();
|
|
final arg = calloc<Int64>();
|
|
Expect.type<Pointer<Int64>>(arg);
|
|
f(arg);
|
|
calloc.free(arg);
|
|
}
|
|
|
|
// Pass a statically subtyped but dynamically invariant argument.
|
|
void paramSubtype2() {
|
|
final fp =
|
|
ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
|
|
final f = fp.asFunction<NaTyPointerParamOpDart>();
|
|
final Pointer<NativeType> arg = calloc<Int64>();
|
|
Expect.type<Pointer<Int64>>(arg);
|
|
f(arg);
|
|
calloc.free(arg);
|
|
}
|
|
|
|
void returnInvariant1() {
|
|
final fp = ffiTestFunctions
|
|
.lookup<NativeFunction<Int64PointerReturnOp>>(returnOpName);
|
|
final f = fp.asFunction<Int64PointerReturnOp>();
|
|
final result = f();
|
|
Expect.type<Pointer<Int64>>(result);
|
|
}
|
|
|
|
void returnInvariant2() {
|
|
final fp = ffiTestFunctions
|
|
.lookup<NativeFunction<NaTyPointerReturnOp>>(returnOpName);
|
|
final f = fp.asFunction<NaTyPointerReturnOp>();
|
|
final result = f();
|
|
Expect.type<Pointer<NativeType>>(result);
|
|
}
|
|
|
|
void returnSubtype() {
|
|
final fp = ffiTestFunctions
|
|
.lookup<NativeFunction<Int64PointerReturnOp>>(returnOpName);
|
|
final f = fp.asFunction<Int64PointerReturnOp>();
|
|
final NaTyPointerReturnOp f2 = f;
|
|
Expect.type<Int64PointerReturnOp>(f2);
|
|
final result = f2();
|
|
Expect.type<Pointer<NativeType>>(result);
|
|
}
|
|
|
|
void functionArgumentVariance() {
|
|
final p = Pointer<
|
|
NativeFunction<
|
|
Pointer<NativeFunction<Pointer<Int8> Function(Pointer<NativeType>)>> Function(
|
|
Pointer<
|
|
NativeFunction<
|
|
Pointer<NativeType> Function(
|
|
Pointer<Int8>)>>)>>.fromAddress(0x1234);
|
|
final f = p.asFunction<
|
|
Pointer<NativeFunction<Pointer<NativeType> Function(Pointer<Int8>)>> Function(
|
|
Pointer<
|
|
NativeFunction<Pointer<Int8> Function(Pointer<NativeType>)>>)>();
|
|
}
|
|
|
|
void asFunctionTests() {
|
|
for (int i = 0; i < 100; ++i) {
|
|
paramInvariant1(); // Parameter invariant: Pointer<Int64>.
|
|
paramInvariant2(); // Parameter invariant: Pointer<NativeType>.
|
|
paramSubtype1(); // Parameter statically and dynamically subtyped.
|
|
paramSubtype2(); // Parameter statically invariant, dynamically subtyped.
|
|
returnInvariant1(); // Return value invariant: Pointer<Int64>.
|
|
returnInvariant2(); // Return value invariant: Pointer<NativeType>.
|
|
returnSubtype(); // Return value static subtyped, dynamically invariant.
|
|
functionArgumentVariance(); // Check nested function signatures.
|
|
}
|
|
}
|
|
|
|
// =======================================================
|
|
// Test with callbacks from native to Dart (fromFunction).
|
|
// =======================================================
|
|
|
|
typedef CallbackInt64PointerParamOpDart = void Function(
|
|
Pointer<NativeFunction<Int64PointerParamOp>>);
|
|
typedef CallbackInt64PointerParamOp = Void Function(
|
|
Pointer<NativeFunction<Int64PointerParamOp>>);
|
|
|
|
typedef CallbackNaTyPointerParamOpDart = void Function(
|
|
Pointer<NativeFunction<NaTyPointerParamOp>>);
|
|
typedef CallbackNaTyPointerParamOp = Void Function(
|
|
Pointer<NativeFunction<NaTyPointerParamOp>>);
|
|
|
|
typedef CallbackInt64PointerReturnOpDart = void Function(
|
|
Pointer<NativeFunction<Int64PointerReturnOp>>);
|
|
typedef CallbackInt64PointerReturnOp = Void Function(
|
|
Pointer<NativeFunction<Int64PointerReturnOp>>);
|
|
|
|
typedef CallbackNaTyPointerReturnOpDart = void Function(
|
|
Pointer<NativeFunction<NaTyPointerReturnOp>>);
|
|
typedef CallbackNaTyPointerReturnOp = Void Function(
|
|
Pointer<NativeFunction<NaTyPointerReturnOp>>);
|
|
|
|
final callbackParamOpName = "CallbackNativeTypePointerParam";
|
|
final callbackReturnOpName = "CallbackNativeTypePointerReturn";
|
|
|
|
void int64PointerParamOp(Pointer<Int64> p) {
|
|
p.value = 42;
|
|
}
|
|
|
|
void naTyPointerParamOp(Pointer<NativeType> p) {
|
|
final Pointer<Int8> asInt8 = p.cast();
|
|
asInt8.value = 42;
|
|
}
|
|
|
|
// Pointer to return to C when C calls back into Dart and asks for a Pointer.
|
|
Pointer<Int64> data = nullptr;
|
|
|
|
Pointer<Int64> int64PointerReturnOp() {
|
|
return data;
|
|
}
|
|
|
|
Pointer<NativeType> naTyPointerReturnOp() {
|
|
return data;
|
|
}
|
|
|
|
void callbackParamInvariant1() {
|
|
final callback = ffiTestFunctions.lookupFunction<CallbackInt64PointerParamOp,
|
|
CallbackInt64PointerParamOpDart>(callbackParamOpName);
|
|
final fp = Pointer.fromFunction<Int64PointerParamOp>(int64PointerParamOp);
|
|
callback(fp);
|
|
}
|
|
|
|
void callbackParamInvariant2() {
|
|
final callback = ffiTestFunctions.lookupFunction<CallbackNaTyPointerParamOp,
|
|
CallbackNaTyPointerParamOpDart>(callbackParamOpName);
|
|
final fp = Pointer.fromFunction<NaTyPointerParamOp>(naTyPointerParamOp);
|
|
callback(fp);
|
|
}
|
|
|
|
void callbackParamImplicitDowncast1() {
|
|
final callback = ffiTestFunctions.lookupFunction<CallbackNaTyPointerParamOp,
|
|
CallbackNaTyPointerParamOpDart>(callbackParamOpName);
|
|
final fp = Pointer.fromFunction<Int64PointerParamOp>(int64PointerParamOp);
|
|
// Pointer type arguments are not reified, any cast will succeed.
|
|
callback(fp as Pointer<NativeFunction<NaTyPointerParamOp>>);
|
|
}
|
|
|
|
void callbackParamSubtype1() {
|
|
final callback = ffiTestFunctions.lookupFunction<CallbackNaTyPointerParamOp,
|
|
CallbackNaTyPointerParamOpDart>(callbackParamOpName);
|
|
final fp = Pointer.fromFunction<NaTyPointerParamOp>(int64PointerParamOp);
|
|
callback(fp);
|
|
}
|
|
|
|
void callbackReturnInvariant1() {
|
|
final callback = ffiTestFunctions.lookupFunction<CallbackInt64PointerReturnOp,
|
|
CallbackInt64PointerReturnOpDart>(callbackReturnOpName);
|
|
final fp = Pointer.fromFunction<Int64PointerReturnOp>(int64PointerReturnOp);
|
|
callback(fp);
|
|
}
|
|
|
|
void callbackReturnInvariant2() {
|
|
final callback = ffiTestFunctions.lookupFunction<CallbackNaTyPointerReturnOp,
|
|
CallbackNaTyPointerReturnOpDart>(callbackReturnOpName);
|
|
final fp = Pointer.fromFunction<NaTyPointerReturnOp>(naTyPointerReturnOp);
|
|
callback(fp);
|
|
}
|
|
|
|
void fromFunctionTests() {
|
|
data = calloc();
|
|
for (int i = 0; i < 100; ++i) {
|
|
callbackParamInvariant1(); // Pointer<Int64> invariant
|
|
callbackParamInvariant2(); // Pointer<NativeType> invariant
|
|
callbackParamImplicitDowncast1(); // static and dynamically supertyped
|
|
callbackParamSubtype1(); // static and dynamically subtyped
|
|
callbackReturnInvariant1(); // Pointer<Int64> invariant
|
|
callbackReturnInvariant2(); // Pointer<NativeType> invariant
|
|
}
|
|
calloc.free(data);
|
|
}
|
|
|
|
void main() {
|
|
asFunctionTests();
|
|
fromFunctionTests();
|
|
}
|