blob: f999ed6e3050d77f96e8bf6627041935545908cf [file] [log] [blame]
// 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 = 2.9
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'dylib_utils.dart';
typedef NativeUnaryOp = Int32 Function(Int32);
typedef NativeBinaryOp = Int32 Function(Int32, Int32);
typedef UnaryOp = int Function(int);
typedef BinaryOp = int Function(int, int);
typedef GenericBinaryOp<T> = int Function(int, T);
typedef NativeQuadOpSigned = Int64 Function(Int8, Int16, Int32, Int64);
typedef NativeQuadOpUnsigned = Uint64 Function(Uint8, Uint16, Uint32, Uint64);
typedef NativeFunc4 = IntPtr Function(IntPtr);
typedef NativeDoubleUnaryOp = Double Function(Double);
typedef NativeFloatUnaryOp = Float Function(Float);
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 NativeDoubleDecenaryOp = Double Function(Double, Double, Double, Double,
Double, Double, Double, Double, Double, Double);
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 Int64PointerUnOp = Pointer<Int64> Function(Pointer<Int64>);
typedef QuadOp = int Function(int, int, int, int);
typedef DoubleUnaryOp = double Function(double);
typedef DecenaryOp = int Function(
int, int, int, int, int, int, int, int, int, int);
typedef DoubleDecenaryOp = double Function(double, double, double, double,
double, double, double, double, double, 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);
main() {
print('start main');
DynamicLibrary ffiTestFunctions =
dlopenPlatformSpecific("ffi_test_functions");
{
// A int32 bin op.
BinaryOp sumPlus42 =
ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42");
var result = sumPlus42(3, 17);
print(result);
print(result.runtimeType);
}
{
// As a leaf call.
BinaryOp sumPlus42Leaf = ffiTestFunctions
.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42", isLeaf: true);
final result = sumPlus42Leaf(3, 17);
print(result);
print(result.runtimeType);
}
{
// Various size arguments.
QuadOp intComputation = ffiTestFunctions
.lookupFunction<NativeQuadOpSigned, QuadOp>("IntComputation");
var result = intComputation(125, 250, 500, 1000);
print(result);
print(result.runtimeType);
var mint = 0x7FFFFFFFFFFFFFFF; // 2 ^ 63 - 1
result = intComputation(1, 1, 1, mint);
print(result);
print(result.runtimeType);
}
{
// Unsigned int parameters.
QuadOp uintComputation = ffiTestFunctions
.lookupFunction<NativeQuadOpUnsigned, QuadOp>("UintComputation");
var result = uintComputation(0xFF, 0xFFFF, 0xFFFFFFFF, -1);
result = uintComputation(1, 1, 0, -1);
print(result);
print(result.runtimeType);
print(-0xFF + 0xFFFF - 0xFFFFFFFF);
}
{
// Architecture size argument.
Pointer<NativeFunction<NativeFunc4>> p = ffiTestFunctions.lookup("Times3");
UnaryOp f6 = p.asFunction();
var result = f6(1337);
print(result);
print(result.runtimeType);
}
{
// Function with double.
DoubleUnaryOp times1_337Double = ffiTestFunctions
.lookupFunction<NativeDoubleUnaryOp, DoubleUnaryOp>("Times1_337Double");
var result = times1_337Double(2.0);
print(result);
print(result.runtimeType);
}
{
// Function with float.
DoubleUnaryOp times1_337Float = ffiTestFunctions
.lookupFunction<NativeFloatUnaryOp, DoubleUnaryOp>("Times1_337Float");
var result = times1_337Float(1000.0);
print(result);
print(result.runtimeType);
}
{
// Function with many arguments: arguments get passed in registers and stack.
DecenaryOp sumManyInts = ffiTestFunctions
.lookupFunction<NativeDecenaryOp, DecenaryOp>("SumManyInts");
var result = sumManyInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
print(result);
print(result.runtimeType);
}
{
// Function with many arguments: arguments get passed in registers and stack.
DecenaryOp sumManyInts = ffiTestFunctions
.lookupFunction<NativeDecenaryOp2, DecenaryOp>("SumManySmallInts");
var result = sumManyInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
print(result);
print(result.runtimeType);
}
{
// Function with many double arguments.
DoubleDecenaryOp sumManyDoubles = ffiTestFunctions.lookupFunction<
NativeDoubleDecenaryOp, DoubleDecenaryOp>("SumManyDoubles");
var result =
sumManyDoubles(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0);
print(result);
print(result.runtimeType);
}
{
// Function with many arguments, ints and doubles mixed.
VigesimalOp sumManyNumbers = ffiTestFunctions
.lookupFunction<NativeVigesimalOp, VigesimalOp>("SumManyNumbers");
var result = 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);
print(result);
print(result.runtimeType);
}
{
// pass an array / pointer as argument
Int64PointerUnOp assign1337Index1 = ffiTestFunctions
.lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1");
Pointer<Int64> p2 = calloc(2);
p2.value = 42;
p2[1] = 1000;
print(p2.elementAt(1).address.toRadixString(16));
print(p2[1]);
Pointer<Int64> result = assign1337Index1(p2);
print(p2[1]);
print(assign1337Index1);
print(assign1337Index1.runtimeType);
print(result);
print(result.runtimeType);
print(result.address.toRadixString(16));
print(result.value);
}
{
// Passing in null for an int argument throws a null pointer exception.
BinaryOp sumPlus42 =
ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42");
int x = null;
try {
sumPlus42(43, x);
} on Error {
print('Expected exception on passing null for int');
}
}
{
// Passing in null for a double argument throws a null pointer exception.
DoubleUnaryOp times1_337Double = ffiTestFunctions
.lookupFunction<NativeDoubleUnaryOp, DoubleUnaryOp>("Times1_337Double");
double x = null;
try {
times1_337Double(x);
} on Error {
print('Expected exception on passing null for double');
}
}
{
// Passing in null for an int argument throws a null pointer exception.
VigesimalOp sumManyNumbers = ffiTestFunctions
.lookupFunction<NativeVigesimalOp, VigesimalOp>("SumManyNumbers");
int x = null;
try {
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, x, 20.0);
} on Error {
print('Expected exception on passing null for int');
}
}
{
// Passing in nullptr for a pointer argument results in a nullptr in c.
Int64PointerUnOp nullableInt64ElemAt1 =
ffiTestFunctions.lookupFunction<Int64PointerUnOp, Int64PointerUnOp>(
"NullableInt64ElemAt1");
Pointer<Int64> result = nullableInt64ElemAt1(nullptr);
print(result);
print(result.runtimeType);
Pointer<Int64> p2 = calloc(2);
result = nullableInt64ElemAt1(p2);
print(result);
print(result.runtimeType);
calloc.free(p2);
}
print("end main");
}