38e250b4d5
Includes all the files which required no manual treatment. Change-Id: I3d493bcbc238a2016579a0f804d32f4829efb87b Cq-Include-Trybots: dart/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-win-debug-x64c-try,vm-checked-mac-release-arm64-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-win-release-ia32-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/399102 Reviewed-by: Bob Nystrom <rnystrom@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
621 lines
16 KiB
Dart
621 lines
16 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.
|
|
//
|
|
// Dart test program for testing dart:ffi function pointers.
|
|
//
|
|
// VMOptions=
|
|
// VMOptions=--deterministic --optimization-counter-threshold=10
|
|
// VMOptions=--use-slow-path
|
|
// VMOptions=--use-slow-path --stacktrace-every=100
|
|
// SharedObjects=ffi_test_functions
|
|
|
|
import 'dart:ffi';
|
|
|
|
import "package:ffi/ffi.dart";
|
|
import "package:expect/expect.dart";
|
|
|
|
import 'dylib_utils.dart';
|
|
|
|
void main() {
|
|
for (int i = 0; i < 100; ++i) {
|
|
testNativeFunctionFromCast();
|
|
testNativeFunctionFromLookup();
|
|
test64bitInterpretations();
|
|
testExtension();
|
|
testTruncation();
|
|
testNativeFunctionDoubles();
|
|
testNativeFunctionFloats();
|
|
testNativeFunctionManyArguments1();
|
|
testNativeFunctionManyArguments2();
|
|
testNativeFunctionManyArguments3();
|
|
testNativeFunctionManyArguments4();
|
|
testNativeFunctionManyArguments5();
|
|
testNativeFunctionPointer();
|
|
testNullPointers();
|
|
testFloatRounding();
|
|
testVoidReturn();
|
|
testNoArgs();
|
|
testNativeFunctionNullableInt();
|
|
}
|
|
}
|
|
|
|
final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
|
|
|
|
typedef NativeBinaryOp = Int32 Function(Int32, Int32);
|
|
typedef UnaryOp = int Function(int);
|
|
typedef BinaryOp = int Function(int, int);
|
|
typedef GenericBinaryOp<T> = int Function(int, T);
|
|
|
|
void testNativeFunctionFromCast() {
|
|
Pointer<IntPtr> p1 = calloc();
|
|
Pointer<NativeFunction<NativeBinaryOp>> p2 = p1.cast();
|
|
p2.asFunction<BinaryOp>();
|
|
p2.asFunction<GenericBinaryOp<int>>();
|
|
calloc.free(p1);
|
|
}
|
|
|
|
typedef NativeQuadOpSigned = Int64 Function(Int8, Int16, Int32, Int64);
|
|
typedef QuadOp = int Function(int, int, int, int);
|
|
typedef NativeQuadOpUnsigned = Uint64 Function(Uint8, Uint16, Uint32, Uint64);
|
|
|
|
BinaryOp sumPlus42 = ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>(
|
|
"SumPlus42",
|
|
);
|
|
|
|
QuadOp intComputation = ffiTestFunctions
|
|
.lookupFunction<NativeQuadOpSigned, QuadOp>("IntComputation");
|
|
|
|
void testNativeFunctionFromLookup() {
|
|
Expect.equals(49, sumPlus42(3, 4));
|
|
Expect.equals(49, (sumPlus42 as dynamic)(3, 4));
|
|
Expect.throwsNoSuchMethodError(() => (sumPlus42 as dynamic)());
|
|
Expect.throwsTypeError(() => (sumPlus42 as dynamic)(3, 4.0));
|
|
|
|
Expect.equals(625, intComputation(125, 250, 500, 1000));
|
|
Expect.equals(625, (intComputation as dynamic)(125, 250, 500, 1000));
|
|
|
|
Expect.equals(
|
|
0x7FFFFFFFFFFFFFFF,
|
|
intComputation(0, 0, 0, 0x7FFFFFFFFFFFFFFF),
|
|
);
|
|
Expect.equals(
|
|
-0x8000000000000000,
|
|
intComputation(0, 0, 0, -0x8000000000000000),
|
|
);
|
|
|
|
Expect.equals(
|
|
0x7FFFFFFFFFFFFFFF,
|
|
(intComputation as dynamic)(0, 0, 0, 0x7FFFFFFFFFFFFFFF),
|
|
);
|
|
Expect.equals(
|
|
-0x8000000000000000,
|
|
(intComputation as dynamic)(0, 0, 0, -0x8000000000000000),
|
|
);
|
|
}
|
|
|
|
typedef NativeReturnMaxUint8 = Uint8 Function();
|
|
int Function() returnMaxUint8 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMaxUint8")
|
|
.cast<NativeFunction<NativeReturnMaxUint8>>()
|
|
.asFunction();
|
|
int Function() returnMaxUint8v2 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMaxUint8v2")
|
|
.cast<NativeFunction<NativeReturnMaxUint8>>()
|
|
.asFunction();
|
|
|
|
typedef NativeReturnMaxUint16 = Uint16 Function();
|
|
int Function() returnMaxUint16 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMaxUint16")
|
|
.cast<NativeFunction<NativeReturnMaxUint16>>()
|
|
.asFunction();
|
|
int Function() returnMaxUint16v2 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMaxUint16v2")
|
|
.cast<NativeFunction<NativeReturnMaxUint16>>()
|
|
.asFunction();
|
|
|
|
typedef NativeReturnMaxUint32 = Uint32 Function();
|
|
int Function() returnMaxUint32 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMaxUint32")
|
|
.cast<NativeFunction<NativeReturnMaxUint32>>()
|
|
.asFunction();
|
|
int Function() returnMaxUint32v2 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMaxUint32v2")
|
|
.cast<NativeFunction<NativeReturnMaxUint32>>()
|
|
.asFunction();
|
|
|
|
typedef NativeReturnMinInt8 = Int8 Function();
|
|
int Function() returnMinInt8 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMinInt8")
|
|
.cast<NativeFunction<NativeReturnMinInt8>>()
|
|
.asFunction();
|
|
int Function() returnMinInt8v2 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMinInt8v2")
|
|
.cast<NativeFunction<NativeReturnMinInt8>>()
|
|
.asFunction();
|
|
|
|
typedef NativeReturnMinInt16 = Int16 Function();
|
|
int Function() returnMinInt16 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMinInt16")
|
|
.cast<NativeFunction<NativeReturnMinInt16>>()
|
|
.asFunction();
|
|
int Function() returnMinInt16v2 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMinInt16v2")
|
|
.cast<NativeFunction<NativeReturnMinInt16>>()
|
|
.asFunction();
|
|
|
|
typedef NativeReturnMinInt32 = Int32 Function();
|
|
int Function() returnMinInt32 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMinInt32")
|
|
.cast<NativeFunction<NativeReturnMinInt32>>()
|
|
.asFunction();
|
|
int Function() returnMinInt32v2 =
|
|
ffiTestFunctions
|
|
.lookup("ReturnMinInt32v2")
|
|
.cast<NativeFunction<NativeReturnMinInt32>>()
|
|
.asFunction();
|
|
|
|
typedef NativeTakeMaxUint8 = IntPtr Function(Uint8);
|
|
int Function(int) takeMaxUint8 =
|
|
ffiTestFunctions
|
|
.lookup("TakeMaxUint8")
|
|
.cast<NativeFunction<NativeTakeMaxUint8>>()
|
|
.asFunction();
|
|
|
|
typedef NativeTakeMaxUint16 = IntPtr Function(Uint16);
|
|
int Function(int) takeMaxUint16 =
|
|
ffiTestFunctions
|
|
.lookup("TakeMaxUint16")
|
|
.cast<NativeFunction<NativeTakeMaxUint16>>()
|
|
.asFunction();
|
|
|
|
typedef NativeTakeMaxUint32 = IntPtr Function(Uint32);
|
|
int Function(int) takeMaxUint32 =
|
|
ffiTestFunctions
|
|
.lookup("TakeMaxUint32")
|
|
.cast<NativeFunction<NativeTakeMaxUint32>>()
|
|
.asFunction();
|
|
|
|
typedef NativeTakeMinInt8 = IntPtr Function(Int8);
|
|
int Function(int) takeMinInt8 =
|
|
ffiTestFunctions
|
|
.lookup("TakeMinInt8")
|
|
.cast<NativeFunction<NativeTakeMinInt8>>()
|
|
.asFunction();
|
|
|
|
typedef NativeTakeMinInt16 = IntPtr Function(Int16);
|
|
int Function(int) takeMinInt16 =
|
|
ffiTestFunctions
|
|
.lookup("TakeMinInt16")
|
|
.cast<NativeFunction<NativeTakeMinInt16>>()
|
|
.asFunction();
|
|
|
|
typedef NativeTakeMinInt32 = IntPtr Function(Int32);
|
|
int Function(int) takeMinInt32 =
|
|
ffiTestFunctions
|
|
.lookup("TakeMinInt32")
|
|
.cast<NativeFunction<NativeTakeMinInt32>>()
|
|
.asFunction();
|
|
|
|
typedef NativeTakeMaxUint8x10 =
|
|
IntPtr Function(
|
|
Uint8,
|
|
Uint8,
|
|
Uint8,
|
|
Uint8,
|
|
Uint8,
|
|
Uint8,
|
|
Uint8,
|
|
Uint8,
|
|
Uint8,
|
|
Uint8,
|
|
);
|
|
int Function(int, int, int, int, int, int, int, int, int, int) takeMaxUint8x10 =
|
|
ffiTestFunctions
|
|
.lookup("TakeMaxUint8x10")
|
|
.cast<NativeFunction<NativeTakeMaxUint8x10>>()
|
|
.asFunction();
|
|
|
|
void testExtension() {
|
|
// Sign extension on the way back to Dart.
|
|
Expect.equals(0xff, returnMaxUint8());
|
|
Expect.equals(0xffff, returnMaxUint16());
|
|
Expect.equals(0xffffffff, returnMaxUint32());
|
|
Expect.equals(-0x80, returnMinInt8());
|
|
Expect.equals(-0x8000, returnMinInt16());
|
|
Expect.equals(-0x80000000, returnMinInt32());
|
|
// Truncation in C, and sign extension back to Dart.
|
|
Expect.equals(0xff, returnMaxUint8v2());
|
|
Expect.equals(0xffff, returnMaxUint16v2());
|
|
Expect.equals(0xffffffff, returnMaxUint32v2());
|
|
Expect.equals(-0x80, returnMinInt8v2());
|
|
Expect.equals(-0x8000, returnMinInt16v2());
|
|
Expect.equals(-0x80000000, returnMinInt32v2());
|
|
|
|
// Upper bits propper, should work without truncation.
|
|
Expect.equals(1, takeMaxUint8(0xff));
|
|
Expect.equals(1, takeMaxUint16(0xffff));
|
|
Expect.equals(1, takeMaxUint32(0xffffffff));
|
|
Expect.equals(1, takeMinInt8(-0x80));
|
|
Expect.equals(1, takeMinInt16(-0x8000));
|
|
Expect.equals(1, takeMinInt32(-0x80000000));
|
|
Expect.equals(
|
|
1,
|
|
takeMaxUint8x10(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
|
|
);
|
|
// Upper bits garbage, needs to truncate.
|
|
Expect.equals(1, takeMaxUint8(0xabcff));
|
|
Expect.equals(1, takeMaxUint16(0xabcffff));
|
|
Expect.equals(1, takeMaxUint32(0xabcffffffff));
|
|
Expect.equals(1, takeMinInt8(0x8abc80));
|
|
Expect.equals(1, takeMinInt16(0x8abc8000));
|
|
Expect.equals(1, takeMinInt32(0x8abc80000000));
|
|
Expect.equals(
|
|
1,
|
|
takeMaxUint8x10(
|
|
0xabcff,
|
|
0xabcff,
|
|
0xabcff,
|
|
0xabcff,
|
|
0xabcff,
|
|
0xabcff,
|
|
0xabcff,
|
|
0xabcff,
|
|
0xabcff,
|
|
0xabcff,
|
|
),
|
|
);
|
|
}
|
|
|
|
QuadOp uintComputation = ffiTestFunctions
|
|
.lookupFunction<NativeQuadOpUnsigned, QuadOp>("UintComputation");
|
|
|
|
void test64bitInterpretations() {
|
|
// 2 ^ 63 - 1
|
|
Expect.equals(
|
|
0x7FFFFFFFFFFFFFFF,
|
|
uintComputation(0, 0, 0, 0x7FFFFFFFFFFFFFFF),
|
|
);
|
|
// -2 ^ 63 interpreted as 2 ^ 63
|
|
Expect.equals(
|
|
-0x8000000000000000,
|
|
uintComputation(0, 0, 0, -0x8000000000000000),
|
|
);
|
|
// -1 interpreted as 2 ^ 64 - 1
|
|
Expect.equals(-1, uintComputation(0, 0, 0, -1));
|
|
}
|
|
|
|
typedef NativeSenaryOp =
|
|
Int64 Function(Int8, Int16, Int32, Uint8, Uint16, Uint32);
|
|
typedef SenaryOp = int Function(int, int, int, int, int, int);
|
|
|
|
SenaryOp sumSmallNumbers = ffiTestFunctions
|
|
.lookupFunction<NativeSenaryOp, SenaryOp>("SumSmallNumbers");
|
|
|
|
void testTruncation() {
|
|
sumSmallNumbers(128, 0, 0, 0, 0, 0);
|
|
sumSmallNumbers(-129, 0, 0, 0, 0, 0);
|
|
sumSmallNumbers(0, 0, 0, 256, 0, 0);
|
|
sumSmallNumbers(0, 0, 0, -1, 0, 0);
|
|
|
|
sumSmallNumbers(0, 0x8000, 0, 0, 0, 0);
|
|
sumSmallNumbers(0, 0xFFFFFFFFFFFF7FFF, 0, 0, 0, 0);
|
|
sumSmallNumbers(0, 0, 0, 0, 0x10000, 0);
|
|
sumSmallNumbers(0, 0, 0, 0, -1, 0);
|
|
|
|
Expect.equals(0xFFFFFFFF80000000, sumSmallNumbers(0, 0, 0x80000000, 0, 0, 0));
|
|
Expect.equals(
|
|
0x000000007FFFFFFF,
|
|
sumSmallNumbers(0, 0, 0xFFFFFFFF7FFFFFFF, 0, 0, 0),
|
|
);
|
|
Expect.equals(0, sumSmallNumbers(0, 0, 0, 0, 0, 0x100000000));
|
|
Expect.equals(0xFFFFFFFF, sumSmallNumbers(0, 0, 0, 0, 0, -1));
|
|
}
|
|
|
|
typedef NativeDoubleUnaryOp = Double Function(Double);
|
|
typedef DoubleUnaryOp = double Function(double);
|
|
|
|
DoubleUnaryOp times1_337Double = ffiTestFunctions
|
|
.lookupFunction<NativeDoubleUnaryOp, DoubleUnaryOp>("Times1_337Double");
|
|
|
|
void testNativeFunctionDoubles() {
|
|
Expect.approxEquals(2.0 * 1.337, times1_337Double(2.0));
|
|
}
|
|
|
|
typedef NativeFloatUnaryOp = Float Function(Float);
|
|
|
|
DoubleUnaryOp times1_337Float = ffiTestFunctions
|
|
.lookupFunction<NativeFloatUnaryOp, DoubleUnaryOp>("Times1_337Float");
|
|
|
|
void testNativeFunctionFloats() {
|
|
Expect.approxEquals(1337.0, times1_337Float(1000.0));
|
|
}
|
|
|
|
typedef NativeDecenaryOp =
|
|
IntPtr Function(
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
);
|
|
typedef NativeDecenaryOp2 =
|
|
Int16 Function(
|
|
Int8,
|
|
Int16,
|
|
Int8,
|
|
Int16,
|
|
Int8,
|
|
Int16,
|
|
Int8,
|
|
Int16,
|
|
Int8,
|
|
Int16,
|
|
);
|
|
typedef DecenaryOp =
|
|
int Function(int, int, int, int, int, int, int, int, int, int);
|
|
|
|
DecenaryOp sumManyInts = ffiTestFunctions
|
|
.lookupFunction<NativeDecenaryOp, DecenaryOp>("SumManyInts");
|
|
|
|
void testNativeFunctionManyArguments1() {
|
|
Expect.equals(55, sumManyInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
|
|
}
|
|
|
|
DecenaryOp sumManySmallInts = ffiTestFunctions
|
|
.lookupFunction<NativeDecenaryOp2, DecenaryOp>("SumManySmallInts");
|
|
|
|
void testNativeFunctionManyArguments5() {
|
|
Expect.equals(55, sumManySmallInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
|
|
}
|
|
|
|
typedef NativeUndenaryOp =
|
|
IntPtr Function(
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
IntPtr,
|
|
);
|
|
typedef UndenaryOp =
|
|
int Function(int, int, int, int, int, int, int, int, int, int, int);
|
|
|
|
UndenaryOp sumManyIntsOdd = ffiTestFunctions
|
|
.lookupFunction<NativeUndenaryOp, UndenaryOp>("SumManyIntsOdd");
|
|
|
|
void testNativeFunctionManyArguments4() {
|
|
Expect.equals(66, sumManyIntsOdd(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
|
|
}
|
|
|
|
typedef NativeDoubleDecenaryOp =
|
|
Double Function(
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
);
|
|
typedef DoubleDecenaryOp =
|
|
double Function(
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
);
|
|
|
|
DoubleDecenaryOp sumManyDoubles = ffiTestFunctions
|
|
.lookupFunction<NativeDoubleDecenaryOp, DoubleDecenaryOp>("SumManyDoubles");
|
|
|
|
void testNativeFunctionManyArguments2() {
|
|
Expect.approxEquals(
|
|
55.0,
|
|
sumManyDoubles(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0),
|
|
);
|
|
}
|
|
|
|
typedef NativeVigesimalOp =
|
|
Double Function(
|
|
IntPtr,
|
|
Float,
|
|
IntPtr,
|
|
Double,
|
|
IntPtr,
|
|
Float,
|
|
IntPtr,
|
|
Double,
|
|
IntPtr,
|
|
Float,
|
|
IntPtr,
|
|
Double,
|
|
IntPtr,
|
|
Float,
|
|
IntPtr,
|
|
Double,
|
|
IntPtr,
|
|
Float,
|
|
IntPtr,
|
|
Double,
|
|
);
|
|
typedef VigesimalOp =
|
|
double Function(
|
|
int,
|
|
double,
|
|
int,
|
|
double,
|
|
int,
|
|
double,
|
|
int,
|
|
double,
|
|
int,
|
|
double,
|
|
int,
|
|
double,
|
|
int,
|
|
double,
|
|
int,
|
|
double,
|
|
int,
|
|
double,
|
|
int,
|
|
double,
|
|
);
|
|
|
|
VigesimalOp sumManyNumbers = ffiTestFunctions
|
|
.lookupFunction<NativeVigesimalOp, VigesimalOp>("SumManyNumbers");
|
|
|
|
void testNativeFunctionManyArguments3() {
|
|
Expect.approxEquals(
|
|
210.0,
|
|
sumManyNumbers(
|
|
1,
|
|
2.0,
|
|
3,
|
|
4.0,
|
|
5,
|
|
6.0,
|
|
7,
|
|
8.0,
|
|
9,
|
|
10.0,
|
|
11,
|
|
12.0,
|
|
13,
|
|
14.0,
|
|
15,
|
|
16.0,
|
|
17,
|
|
18.0,
|
|
19,
|
|
20.0,
|
|
),
|
|
);
|
|
}
|
|
|
|
typedef Int64PointerUnOp = Pointer<Int64> Function(Pointer<Int64>);
|
|
|
|
Int64PointerUnOp assign1337Index1 = ffiTestFunctions
|
|
.lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1");
|
|
|
|
void testNativeFunctionPointer() {
|
|
Pointer<Int64> p2 = calloc(2);
|
|
p2.value = 42;
|
|
p2[1] = 1000;
|
|
Pointer<Int64> result = assign1337Index1(p2);
|
|
Expect.equals(1337, result.value);
|
|
Expect.equals(1337, p2[1]);
|
|
Expect.equals(p2.elementAt(1).address, result.address);
|
|
calloc.free(p2);
|
|
}
|
|
|
|
Int64PointerUnOp nullableInt64ElemAt1 = ffiTestFunctions
|
|
.lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("NullableInt64ElemAt1");
|
|
|
|
void testNullPointers() {
|
|
Pointer<Int64> result = nullableInt64ElemAt1(nullptr);
|
|
Expect.equals(result, nullptr);
|
|
|
|
Pointer<Int64> p2 = calloc(2);
|
|
result = nullableInt64ElemAt1(p2);
|
|
Expect.notEquals(result, nullptr);
|
|
calloc.free(p2);
|
|
}
|
|
|
|
typedef NativeFloatPointerToBool = Uint8 Function(Pointer<Float>);
|
|
typedef FloatPointerToBool = int Function(Pointer<Float>);
|
|
|
|
FloatPointerToBool isRoughly1337 = ffiTestFunctions
|
|
.lookupFunction<NativeFloatPointerToBool, FloatPointerToBool>(
|
|
"IsRoughly1337",
|
|
);
|
|
|
|
void testFloatRounding() {
|
|
Pointer<Float> p2 = calloc();
|
|
p2.value = 1337.0;
|
|
|
|
int result = isRoughly1337(p2);
|
|
Expect.equals(1, result);
|
|
|
|
calloc.free(p2);
|
|
}
|
|
|
|
typedef NativeFloatToVoid = Void Function(Float);
|
|
typedef DoubleToVoid = void Function(double);
|
|
|
|
DoubleToVoid devNullFloat = ffiTestFunctions
|
|
.lookupFunction<NativeFloatToVoid, DoubleToVoid>("DevNullFloat");
|
|
|
|
void testVoidReturn() {
|
|
devNullFloat(1337.0);
|
|
|
|
dynamic loseSignature = devNullFloat;
|
|
dynamic result = loseSignature(1337.0);
|
|
Expect.isNull(result);
|
|
}
|
|
|
|
typedef NativeVoidToFloat = Float Function();
|
|
typedef VoidToDouble = double Function();
|
|
|
|
VoidToDouble inventFloatValue = ffiTestFunctions
|
|
.lookupFunction<NativeVoidToFloat, VoidToDouble>("InventFloatValue");
|
|
|
|
void testNoArgs() {
|
|
double result = inventFloatValue();
|
|
Expect.approxEquals(1337.0, result);
|
|
}
|
|
|
|
// Returns a possibly ofuscated 'arg2' identifier.
|
|
String get arg2ObfuscatedName {
|
|
final str = (arg2: 0).toString();
|
|
return str.substring('('.length, str.length - ': 0)'.length);
|
|
}
|
|
|
|
void testNativeFunctionNullableInt() {
|
|
final sumPlus42 = ffiTestFunctions
|
|
.lookupFunction<Int32 Function(Int32, Int32), int Function(int, int?)>(
|
|
"SumPlus42",
|
|
);
|
|
|
|
try {
|
|
sumPlus42(3, null);
|
|
} catch (e) {
|
|
// TODO(http://dartbug.com/47098): Save param names to dwarf.
|
|
Expect.isTrue(
|
|
e.toString().contains(arg2ObfuscatedName) ||
|
|
e.toString().contains('<optimized out>'),
|
|
);
|
|
}
|
|
}
|