Skip to content

Commit 8682ca7

Browse files
dcharkesCommit Queue
authored and
Commit Queue
committed
[vm/ffi] Example with deeply-immutable Finalizable and dart_api_dl
A test exercising isolate group finalizers with `Finalizable` and `pragma('vm:deeply-immutable')`. Note that we cannot fully do without C code due to the signature of `Dart_HandleFinalizer` which also passes a `void* isolate_callback_data` in addition to the peer. TEST=tests/ffi/deeply_immutable_c_api_finalizer_test.dart Bug: #55062 Bug: #55120 Change-Id: Ibaf4899ca678ffb0c5d227ac4f10deb38d49fe6f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/356720 Reviewed-by: Martin Kustermann <[email protected]> Reviewed-by: Hossein Yousefi <[email protected]> Commit-Queue: Daco Harkes <[email protected]>
1 parent 06d6ef3 commit 8682ca7

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-1
lines changed

runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ DART_EXPORT void ExecuteCallback(Work* work_ptr) {
617617

618618
Dart_Port send_port_;
619619

620-
static void FreeFinalizer(void*, void* value) {
620+
DART_EXPORT void FreeFinalizer(void*, void* value) {
621621
free(value);
622622
}
623623

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// SharedObjects=ffi_test_functions
6+
7+
import 'dart:async';
8+
import 'dart:ffi';
9+
import 'dart:isolate';
10+
11+
import 'package:ffi/ffi.dart';
12+
13+
import 'dylib_utils.dart';
14+
15+
void main() async {
16+
final myFinalizable2 = await Isolate.run(() => MyFinalizable());
17+
print(myFinalizable2);
18+
print(myFinalizable2.pointer);
19+
// This would crash if a NativeFinalizer would have been attached and run
20+
// eagerly on `Isolate.exit`.
21+
print(myFinalizable2.pointer.value);
22+
}
23+
24+
@pragma('vm:deeply-immutable')
25+
final class MyFinalizable implements Finalizable {
26+
final Pointer<Int> pointer;
27+
28+
MyFinalizable._(this.pointer);
29+
30+
factory MyFinalizable() {
31+
final pointer = calloc<Int>(10);
32+
pointer.value = 123;
33+
final result = MyFinalizable._(pointer);
34+
newFinalizableHandle(
35+
result,
36+
pointer.cast(),
37+
0,
38+
freeFinalizer, // Not the signature of `free`!
39+
);
40+
return result;
41+
}
42+
}
43+
44+
final freeFinalizer = dlopenPlatformSpecific("ffi_test_functions")
45+
.lookup<NativeFunction<Dart_HandleFinalizerFunction>>('FreeFinalizer');
46+
47+
final Dart_FinalizableHandle Function(
48+
Object,
49+
Pointer<Void>,
50+
int,
51+
Dart_HandleFinalizer,
52+
) newFinalizableHandle = _findDartApiFunction('Dart_NewFinalizableHandle')
53+
.cast<
54+
NativeFunction<
55+
Dart_FinalizableHandle Function(
56+
Handle,
57+
Pointer<Void>,
58+
IntPtr,
59+
Dart_HandleFinalizer,
60+
)>>()
61+
.asFunction();
62+
63+
final void Function(
64+
Dart_FinalizableHandle,
65+
Object,
66+
) deleteFinalizableHandle = _findDartApiFunction('Dart_DeleteFinalizableHandle')
67+
.cast<
68+
NativeFunction<
69+
Void Function(
70+
Dart_FinalizableHandle,
71+
Handle,
72+
)>>()
73+
.asFunction();
74+
75+
Pointer<Void> _findDartApiFunction(String name) {
76+
final dartApi = NativeApi.initializeApiDLData.cast<DartApi>();
77+
var entry = dartApi.ref.functions;
78+
while (true) {
79+
final entryName = entry.ref.name.cast<Utf8>().toDartString();
80+
if (entryName == name) {
81+
return entry.ref.function;
82+
}
83+
if (name == 'Dart_Null') {
84+
throw StateError('Dart API function with $name not found.');
85+
}
86+
entry++;
87+
}
88+
}
89+
90+
final class DartApi extends Struct {
91+
@Int()
92+
external int major;
93+
94+
@Int()
95+
external int minor;
96+
97+
external Pointer<DartApiEntry> functions;
98+
}
99+
100+
final class DartApiEntry extends Struct {
101+
external Pointer<Char> name;
102+
103+
external Pointer<Void> function;
104+
}
105+
106+
final class _Dart_FinalizableHandle extends Opaque {}
107+
108+
typedef Dart_HandleFinalizer
109+
= Pointer<NativeFunction<Dart_HandleFinalizerFunction>>;
110+
typedef Dart_HandleFinalizerFunction = Void Function(
111+
Pointer<Void> isolate_callback_data, Pointer<Void> peer);
112+
typedef DartDart_HandleFinalizerFunction = void Function(
113+
Pointer<Void> isolate_callback_data, Pointer<Void> peer);
114+
typedef Dart_FinalizableHandle = Pointer<_Dart_FinalizableHandle>;

0 commit comments

Comments
 (0)