dart-sdk/tests/ffi_2/abi_specific_int_incomplete_jit_test.dart
Martin Kustermann 4be2981c2d [vm/ffi] Ensure there's a single Function object per ffi-callback + exceptional-return combination
Right each `Pointer.fromFunction()` invocation will lead to creation of
a new ffi trampoline function & it's following JITed code. In AOT we
have exactly one ffi trampoline per target/native-signature/exceptional-return
combination.
=> This CL ensures we have only one such function.

Furthermore each `Pointer.fromFunction()` will currently perform 2
runtime calls in JIT: One to create a `Function` object, the other to
JIT that function & register callback metadata.
=> This CL ensures we won't do a runtime call to get a function, instead
   do it at compile-time (as in AOT)

Furthermore we eagerly assign a callback-id to the unique/deduped ffi
trampoline callbacks. Only when the application requests a pointer, do
we populate metadata on the `Thread` object.

This CL doesn't (yet) change the fact that in JIT mode we have
isolate-specific jit trampolines (that will call now shared ffi trampoline
functions).

We also avoid baking in C++ runtime function pointers in generated
code. As a result we can now preserve ffi trampolines across AppJIT
serialization.

As a nice side-effect, we remove 100 lines of code.

TEST=ffi{,_2}/ffi_callback_unique_test

Issue https://github.com/dart-lang/sdk/issues/50611

Change-Id: I458831a47b041a088086f28f825de2a3849f6adc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/273420
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2022-12-07 20:47:13 +00:00

138 lines
2.7 KiB
Dart

// Copyright (c) 2021, 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
// SharedObjects=ffi_test_functions
import 'dart:ffi';
import 'package:expect/expect.dart';
import 'package:ffi/ffi.dart';
// We want at least 1 mapping to satisfy the static checks.
const notTestingOn = Abi.fuchsiaArm64;
@AbiSpecificIntegerMapping({
notTestingOn: Int8(),
})
class Incomplete extends AbiSpecificInteger {
const Incomplete();
}
void main() {
if (Abi.current() == notTestingOn) {
return;
}
testSizeOf();
testStoreLoad();
testStoreLoadIndexed();
testStruct();
testInlineArray();
testInlineArray2();
testAsFunction();
}
void testSizeOf() {
Expect.throws(() {
sizeOf<Incomplete>();
});
}
void testStoreLoad() {
final p = calloc<Int64>().cast<Incomplete>();
Expect.throws(() {
p.value = 10;
});
Expect.throws(() {
p.value;
});
calloc.free(p);
}
void testStoreLoadIndexed() {
final p = calloc<Int64>().cast<Incomplete>();
Expect.throws(() {
p[0] = 10;
});
Expect.throws(() {
p[1];
});
calloc.free(p);
}
class IncompleteStruct extends Struct {
@Incomplete()
int a0;
@Incomplete()
int a1;
}
void testStruct() {
final p = calloc<Int64>(2).cast<IncompleteStruct>();
Expect.throws(() {
p.ref.a0 = 1;
});
Expect.throws(() {
p.ref.a0;
});
calloc.free(p);
}
class IncompleteArrayStruct extends Struct {
@Array(100)
Array<Incomplete> a0;
}
void testInlineArray() {
final p = calloc<Int64>(100).cast<IncompleteArrayStruct>();
final array = p.ref.a0;
Expect.throws(() {
array[3] = 4;
});
Expect.throws(() {
array[3];
});
calloc.free(p);
}
const _dim1 = 8;
const _dim2 = 4;
class IncompleteArrayArrayStruct extends Struct {
@Array(_dim1, _dim2)
Array<Array<Incomplete>> a0;
}
void testInlineArray2() {
final p = calloc<Int64>(100).cast<IncompleteArrayArrayStruct>();
Expect.throws(() {
p.elementAt(3);
});
calloc.free(p);
}
void testAsFunction() {
Expect.throws(() {
nullptr
.cast<NativeFunction<Int32 Function(Incomplete)>>()
.asFunction<int Function(int)>();
});
Expect.throws(() {
nullptr
.cast<NativeFunction<Incomplete Function(Int32)>>()
.asFunction<int Function(int)>();
});
Expect.throws(() {
nullptr
.cast<NativeFunction<Int32 Function(IncompleteArrayStruct)>>()
.asFunction<int Function(IncompleteArrayStruct)>();
});
Expect.throws(() {
nullptr
.cast<NativeFunction<IncompleteArrayStruct Function()>>()
.asFunction<IncompleteArrayStruct Function()>();
});
}