dart-sdk/tests/ffi_2/ffi_callback_unique_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

38 lines
1.2 KiB
Dart

// Copyright (c) 2022, 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:expect/expect.dart';
void main() {
final a = <int>[];
final b = <int>[];
for (int i = 0; i < 10; ++i) {
// Several pointers for same call site.
a.add(
Pointer.fromFunction<Int Function()>(nativeToDartCallback, 0).address);
b.add(
Pointer.fromFunction<Int Function()>(nativeToDartCallback, 1).address);
}
// Another pointer from a different call site.
a.add(Pointer.fromFunction<Int Function()>(nativeToDartCallback, 0).address);
b.add(Pointer.fromFunction<Int Function()>(nativeToDartCallback, 1).address);
ensureEqualEntries(a);
ensureEqualEntries(b);
// The two functions have different exceptional return and should have
// therefore a different ffi trampoline.
Expect.notEquals(a.first, b.first);
}
void ensureEqualEntries(List<int> entries) {
final first = entries.first;
for (int i = 1; i < entries.length; ++i) {
Expect.equals(first, entries[i]);
}
}
int nativeToDartCallback() => 42;