| // Copyright (c) 2024, 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. |
| |
| // SharedObjects=ffi_test_functions |
| |
| import 'dart:ffi'; |
| import 'dart:isolate'; |
| |
| import 'package:ffi/ffi.dart'; |
| |
| import 'dylib_utils.dart'; |
| |
| void main() async { |
| final myFinalizable2 = await Isolate.run(() => MyFinalizable()); |
| print(myFinalizable2); |
| print(myFinalizable2.pointer); |
| // This would crash if a NativeFinalizer would have been attached and run |
| // eagerly on `Isolate.exit`. |
| print(myFinalizable2.pointer.value); |
| } |
| |
| @pragma('vm:deeply-immutable') |
| final class MyFinalizable implements Finalizable { |
| final Pointer<Int> pointer; |
| |
| MyFinalizable._(this.pointer); |
| |
| factory MyFinalizable() { |
| final pointer = calloc(sizeOf<Int>(), 10).cast<Int>(); |
| pointer.value = 123; |
| final result = MyFinalizable._(pointer); |
| newFinalizableHandle( |
| result, |
| pointer.cast(), |
| 0, |
| freeFinalizer, // Not the signature of `free`! |
| ); |
| return result; |
| } |
| } |
| |
| final calloc = |
| dlopenPlatformSpecific("ffi_test_functions") |
| .lookup<NativeFunction<Pointer<Void> Function(Size, Size)>>('Calloc') |
| .asFunction<Pointer<Void> Function(int, int)>(); |
| |
| final freeFinalizer = dlopenPlatformSpecific( |
| "ffi_test_functions", |
| ).lookup<NativeFunction<Dart_HandleFinalizerFunction>>('FreeFinalizer'); |
| |
| final Dart_FinalizableHandle Function( |
| Object, |
| Pointer<Void>, |
| int, |
| Dart_HandleFinalizer, |
| ) |
| newFinalizableHandle = |
| _findDartApiFunction('Dart_NewFinalizableHandle') |
| .cast< |
| NativeFunction< |
| Dart_FinalizableHandle Function( |
| Handle, |
| Pointer<Void>, |
| IntPtr, |
| Dart_HandleFinalizer, |
| ) |
| > |
| >() |
| .asFunction(); |
| |
| final void Function(Dart_FinalizableHandle, Object) deleteFinalizableHandle = |
| _findDartApiFunction('Dart_DeleteFinalizableHandle') |
| .cast<NativeFunction<Void Function(Dart_FinalizableHandle, Handle)>>() |
| .asFunction(); |
| |
| Pointer<Void> _findDartApiFunction(String name) { |
| final dartApi = NativeApi.initializeApiDLData.cast<DartApi>(); |
| var entry = dartApi.ref.functions; |
| while (true) { |
| final entryName = entry.ref.name.cast<Utf8>().toDartString(); |
| if (entryName == name) { |
| return entry.ref.function; |
| } |
| if (name == 'Dart_Null') { |
| throw StateError('Dart API function with $name not found.'); |
| } |
| entry++; |
| } |
| } |
| |
| final class DartApi extends Struct { |
| @Int() |
| external int major; |
| |
| @Int() |
| external int minor; |
| |
| external Pointer<DartApiEntry> functions; |
| } |
| |
| final class DartApiEntry extends Struct { |
| external Pointer<Char> name; |
| |
| external Pointer<Void> function; |
| } |
| |
| final class _Dart_FinalizableHandle extends Opaque {} |
| |
| typedef Dart_HandleFinalizer = |
| Pointer<NativeFunction<Dart_HandleFinalizerFunction>>; |
| typedef Dart_HandleFinalizerFunction = |
| Void Function(Pointer<Void> isolate_callback_data, Pointer<Void> peer); |
| typedef DartDart_HandleFinalizerFunction = |
| void Function(Pointer<Void> isolate_callback_data, Pointer<Void> peer); |
| typedef Dart_FinalizableHandle = Pointer<_Dart_FinalizableHandle>; |