mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 22:49:53 +00:00
4d5055805f
This CL adds FFI leaf calls by adding `lookupFunction(.., isLeaf)` and `_asFunctionInternal(.., isLeaf)`, which generate FFI leaf calls. These calls skip a lot of the usual frame building and generated <-> native transition overhead. `benchmark/FfiCall/` shows a 1.1x - 4.3x speed-up between the regular FFI calls and their leaf call counterparts (JIT, x64, release). TEST=Adds `tests/ffi{,_2}/vmspecific_leaf_call_test.dart`. Tested FFI tests. Closes: https://github.com/dart-lang/sdk/issues/36707 Cq-Include-Trybots: luci.dart.try:vm-precomp-ffi-qemu-linux-release-arm-try,vm-ffi-android-release-arm64-try,vm-ffi-android-release-arm-try,vm-ffi-android-product-arm64-try,vm-ffi-android-product-arm-try,vm-ffi-android-debug-arm64-try,vm-ffi-android-debug-arm-try,vm-kernel-linux-debug-ia32-try,vm-kernel-win-debug-ia32-try,vm-kernel-win-debug-x64-try,vm-kernel-win-release-x64-try,vm-kernel-mac-debug-x64-try,vm-kernel-precomp-nnbd-mac-release-simarm64-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-precomp-asan-linux-release-x64-try,vm-kernel-precomp-linux-release-simarm_x64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-precomp-ubsan-linux-release-x64-try,vm-kernel-precomp-tsan-linux-release-x64-try,vm-kernel-precomp-win-release-x64-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-reload-linux-debug-x64-try Bug: https://github.com/dart-lang/sdk/issues/36707 Change-Id: Id8824f36b0006bf09951207bd004356fe6e9f46e Cq-Do-Not-Cancel-Tryjobs: true Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/179768 Commit-Queue: Clement Skau <cskau@google.com> Reviewed-by: Daco Harkes <dacoharkes@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
231 lines
6.6 KiB
Dart
231 lines
6.6 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.
|
|
|
|
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 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");
|
|
}
|