From e151a81108ba0689349af5741d1179ef050f3b3f Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Fri, 25 Mar 2022 10:29:30 +0000 Subject: [PATCH] Reland "[vm] Implement `Finalizer`" Original CL in patchset 1. Split-off https://dart-review.googlesource.com/c/sdk/+/238341 And pulled in fix https://dart-review.googlesource.com/c/sdk/+/238582 (Should merge cleanly when this lands later.) This CL implements the `Finalizer` in the GC. The GC is specially aware of two types of objects for the purposes of running finalizers. 1) `FinalizerEntry` 2) `Finalizer` (`FinalizerBase`, `_FinalizerImpl`) A `FinalizerEntry` contains the `value`, the optional `detach` key, and the `token`, and a reference to the `finalizer`. An entry only holds on weakly to the value, detach key, and finalizer. (Similar to how `WeakReference` only holds on weakly to target). A `Finalizer` contains all entries, a list of entries of which the value is collected, and a reference to the isolate. When a the value of an entry is GCed, the enry is added over to the collected list. If any entry is moved to the collected list, a message is sent that invokes the finalizer to call the callback on all entries in that list. When a finalizer is detached by the user, the entry token is set to the entry itself and is removed from the all entries set. This ensures that if the entry was already moved to the collected list, the finalizer is not executed. To speed up detaching, we use a weak map from detach keys to list of entries. This ensures entries can be GCed. Both the scavenger and marker tasks process finalizer entries in parallel. Parallel tasks use an atomic exchange on the head of the collected entries list, ensuring no entries get lost. The mutator thread is guaranteed to be stopped when processing entries. This ensures that we do not need barriers for moving entries into the finalizers collected list. Dart reads and replaces the collected entries list also with an atomic exchange, ensuring the GC doesn't run in between a load/store. When a finalizer gets posted a message to process finalized objects, it is being kept alive by the message. An alternative design would be to pre-allocate a `WeakReference` in the finalizer pointing to the finalizer, and send that itself. This would be at the cost of an extra object. Send and exit is not supported in this CL, support will be added in a follow up CL. Trying to send will throw. Bug: https://github.com/dart-lang/sdk/issues/47777 TEST=runtime/tests/vm/dart/finalizer/* TEST=runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart TEST=runtime/vm/object_test.cc Change-Id: Ibdfeadc16d5d69ade50aae5b9f794284c4c4dbab Cq-Include-Trybots: luci.dart.try:vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-ffi-android-debug-arm64c-try,dart-sdk-mac-arm64-try,vm-kernel-mac-release-arm64-try,pkg-mac-release-arm64-try,vm-kernel-precomp-nnbd-mac-release-arm64-try,vm-kernel-win-debug-x64c-try,vm-kernel-win-debug-x64-try,vm-kernel-precomp-win-debug-x64c-try,vm-kernel-nnbd-win-release-ia32-try,vm-ffi-android-debug-arm-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-mac-debug-x64-try,vm-kernel-nnbd-mac-debug-x64-try,vm-kernel-nnbd-linux-debug-ia32-try,benchmark-linux-try,flutter-analyze-try,flutter-frontend-try,pkg-linux-debug-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-gcc-linux-try,vm-kernel-optcounter-threshold-linux-release-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64c-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/238086 Reviewed-by: Martin Kustermann Reviewed-by: Ryan Macnak Commit-Queue: Daco Harkes --- runtime/docs/gc.md | 36 +- runtime/lib/isolate.cc | 10 +- ...inalizer_isolate_groups_run_gc_helper.dart | 36 + .../finalizer_isolate_groups_run_gc_test.dart | 93 ++ .../finalizer_isolates_run_gc_test.dart | 103 ++ .../finalizer_nullable_run_gc_test.dart | 43 + .../dart/finalizer/finalizer_run_gc_test.dart | 90 ++ .../finalizer/finalizer_zone_run_gc_test.dart | 73 ++ runtime/tests/vm/dart/finalizer/helpers.dart | 55 + .../finalizer/weak_reference_run_gc_test.dart | 17 +- .../dart/isolates/fast_object_copy_test.dart | 9 + ...inalizer_isolate_groups_run_gc_helper.dart | 38 + .../finalizer_isolate_groups_run_gc_test.dart | 95 ++ .../finalizer_isolates_run_gc_test.dart | 104 ++ .../finalizer_nullable_run_gc_test.dart | 45 + .../finalizer/finalizer_run_gc_test.dart | 92 ++ .../finalizer/finalizer_zone_run_gc_test.dart | 75 ++ .../tests/vm/dart_2/finalizer/helpers.dart | 57 + .../finalizer/weak_reference_run_gc_test.dart | 17 +- .../isolates/fast_object_copy_test.dart | 9 + runtime/tests/vm/vm.status | 3 + runtime/vm/class_finalizer.cc | 4 + runtime/vm/class_id.h | 3 + runtime/vm/compiler/backend/range_analysis.cc | 10 + runtime/vm/compiler/backend/slot.cc | 10 + runtime/vm/compiler/backend/slot.h | 11 + runtime/vm/compiler/frontend/kernel_to_il.cc | 67 ++ runtime/vm/compiler/frontend/kernel_to_il.h | 6 + runtime/vm/compiler/recognized_methods_list.h | 22 + runtime/vm/compiler/runtime_api.cc | 4 + runtime/vm/compiler/runtime_api.h | 29 + .../vm/compiler/runtime_offsets_extracted.h | 952 ++++++++++++--- runtime/vm/compiler/runtime_offsets_list.h | 14 + runtime/vm/dart.cc | 1 + runtime/vm/dart_entry.cc | 70 +- runtime/vm/dart_entry.h | 8 +- runtime/vm/flag_list.h | 1 + runtime/vm/heap/gc_shared.h | 112 +- runtime/vm/heap/marker.cc | 25 + runtime/vm/heap/scavenger.cc | 23 + runtime/vm/isolate.cc | 40 +- runtime/vm/isolate.h | 11 +- runtime/vm/kernel_loader.cc | 3 +- runtime/vm/message.cc | 10 +- runtime/vm/message.h | 16 +- runtime/vm/message_handler.h | 2 + runtime/vm/message_snapshot.cc | 14 +- runtime/vm/object.cc | 84 +- runtime/vm/object.h | 130 ++- runtime/vm/object_graph_copy.cc | 6 +- runtime/vm/object_service.cc | 23 + runtime/vm/object_store.cc | 26 +- runtime/vm/object_store.h | 8 +- runtime/vm/object_test.cc | 1035 +++++++++++++++++ runtime/vm/raw_object.cc | 3 + runtime/vm/raw_object.h | 100 ++ runtime/vm/symbols.h | 4 + runtime/vm/tagged_pointer.h | 3 + sdk/lib/_internal/vm/lib/core_patch.dart | 11 +- sdk/lib/_internal/vm/lib/expando_patch.dart | 35 +- sdk/lib/_internal/vm/lib/finalizer_patch.dart | 82 +- sdk/lib/_internal/vm/lib/internal_patch.dart | 224 +++- sdk/lib/core/weak.dart | 8 +- sdk/lib/isolate/isolate.dart | 1 + 64 files changed, 4077 insertions(+), 274 deletions(-) create mode 100644 runtime/tests/vm/dart/finalizer/finalizer_isolate_groups_run_gc_helper.dart create mode 100644 runtime/tests/vm/dart/finalizer/finalizer_isolate_groups_run_gc_test.dart create mode 100644 runtime/tests/vm/dart/finalizer/finalizer_isolates_run_gc_test.dart create mode 100644 runtime/tests/vm/dart/finalizer/finalizer_nullable_run_gc_test.dart create mode 100644 runtime/tests/vm/dart/finalizer/finalizer_run_gc_test.dart create mode 100644 runtime/tests/vm/dart/finalizer/finalizer_zone_run_gc_test.dart create mode 100644 runtime/tests/vm/dart/finalizer/helpers.dart create mode 100644 runtime/tests/vm/dart_2/finalizer/finalizer_isolate_groups_run_gc_helper.dart create mode 100644 runtime/tests/vm/dart_2/finalizer/finalizer_isolate_groups_run_gc_test.dart create mode 100644 runtime/tests/vm/dart_2/finalizer/finalizer_isolates_run_gc_test.dart create mode 100644 runtime/tests/vm/dart_2/finalizer/finalizer_nullable_run_gc_test.dart create mode 100644 runtime/tests/vm/dart_2/finalizer/finalizer_run_gc_test.dart create mode 100644 runtime/tests/vm/dart_2/finalizer/finalizer_zone_run_gc_test.dart create mode 100644 runtime/tests/vm/dart_2/finalizer/helpers.dart diff --git a/runtime/docs/gc.md b/runtime/docs/gc.md index 7c2fd9aab38..ac9696d47b2 100644 --- a/runtime/docs/gc.md +++ b/runtime/docs/gc.md @@ -13,7 +13,7 @@ A tag of 1 has no penalty on heap object access because removing the tag can be Heap objects are always allocated in double-word increments. Objects in old-space are kept at double-word alignment (address % double-word == 0), and objects in new-space are kept offset from double-word alignment (address % double-word == word). This allows checking an object's age without comparing to a boundary address, avoiding restrictions on heap placement and avoiding loading the boundary from thread-local storage. Additionally, the scavenger can quickly skip over both immediates and old objects with a single branch. | Pointer | Referent | -| --- | --- | +| ---------- | --------------------------------------- | | 0x00000002 | Small integer 1 | | 0xFFFFFFFE | Small integer -1 | | 0x00A00001 | Heap object at 0x00A00000, in old-space | @@ -75,7 +75,7 @@ The Dart VM includes a sliding compactor. The forwarding table is compactly repr ## Concurrent Marking -To reduce the time the mutator is paused for old-space GCs, we allow the mutator to continue running during most of the marking work. +To reduce the time the mutator is paused for old-space GCs, we allow the mutator to continue running during most of the marking work. ### Barrier @@ -204,3 +204,35 @@ container <- AllocateObject StoreInstanceField(container, value, NoBarrier) ``` + +## Finalizers + +The GC is aware of two types of objects for the purposes of running finalizers. + +1) `FinalizerEntry` +2) `Finalizer` (`FinalizerBase`, `_FinalizerImpl`) + +A `FinalizerEntry` contains the `value`, the optional `detach` key, and the `token`, and a reference to the `finalizer`. +An entry only holds on weakly to the value, detach key, and finalizer. (Similar to how `WeakReference` only holds on weakly to target). + +A `Finalizer` contains all entries, a list of entries of which the value is collected, and a reference to the isolate. + +When the value of an entry is GCed, the entry is added over to the collected list. +If any entry is moved to the collected list, a message is sent that invokes the finalizer to call the callback on all entries in that list. + +When a finalizer is detached by the user, the entry token is set to the entry itself and is removed from the all entries set. +This ensures that if the entry was already moved to the collected list, the finalizer is not executed. + +To speed up detaching, we use a weak map from detach keys to list of entries. This ensures entries can be GCed. + +Both the scavenger and marker can process finalizer entries in parallel. +Parallel tasks use an atomic exchange on the head of the collected entries list, ensuring no entries get lost. +Mutator threads are guaranteed to be stopped when processing entries. +This ensures that we do not need barriers for moving entries into the finalizers collected list. +Dart reads and replaces the collected entries list also with an atomic exchange, ensuring the GC doesn't run in between a load/store. + +When a finalizer gets posted a message to process finalized objects, it is being kept alive by the message. +An alternative design would be to pre-allocate a `WeakReference` in the finalizer pointing to the finalizer, and send that itself. +This would be at the cost of an extra object. + +If the finalizer object itself is GCed, the callback is not run for any of the attachments. diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc index 3d2a0f093f5..e2ef579add2 100644 --- a/runtime/lib/isolate.cc +++ b/runtime/lib/isolate.cc @@ -242,6 +242,8 @@ static ObjectPtr ValidateMessageObject(Zone* zone, break; MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary); + // TODO(http://dartbug.com/47777): Send and exit support: remove this. + MESSAGE_SNAPSHOT_ILLEGAL(Finalizer); MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference); MESSAGE_SNAPSHOT_ILLEGAL(Pointer); MESSAGE_SNAPSHOT_ILLEGAL(ReceivePort); @@ -284,6 +286,7 @@ static ObjectPtr ValidateMessageObject(Zone* zone, return obj.ptr(); } +// TODO(http://dartbug.com/47777): Add support for Finalizers. DEFINE_NATIVE_ENTRY(Isolate_exit_, 0, 2) { GET_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0)); if (!port.IsNull()) { @@ -638,9 +641,10 @@ class SpawnIsolateTask : public ThreadPool::Task { // Make a copy of the state's isolate flags and hand it to the callback. Dart_IsolateFlags api_flags = *(state_->isolate_flags()); api_flags.is_system_isolate = false; - Dart_Isolate isolate = (create_group_callback)( - state_->script_url(), name, nullptr, state_->package_config(), - &api_flags, parent_isolate_->init_callback_data(), &error); + Dart_Isolate isolate = + (create_group_callback)(state_->script_url(), name, nullptr, + state_->package_config(), &api_flags, + parent_isolate_->init_callback_data(), &error); parent_isolate_->DecrementSpawnCount(); parent_isolate_ = nullptr; diff --git a/runtime/tests/vm/dart/finalizer/finalizer_isolate_groups_run_gc_helper.dart b/runtime/tests/vm/dart/finalizer/finalizer_isolate_groups_run_gc_helper.dart new file mode 100644 index 00000000000..c0dfdebfe4f --- /dev/null +++ b/runtime/tests/vm/dart/finalizer/finalizer_isolate_groups_run_gc_helper.dart @@ -0,0 +1,36 @@ +// 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:isolate'; + +import 'helpers.dart'; + +int callbackCount = 0; + +void callback(Nonce token) { + callbackCount++; + print('$name: Running finalizer: token: $token'); +} + +final finalizer = Finalizer(callback); + +late String name; + +void main(List arguments, SendPort port) async { + name = arguments[0]; + + final token = Nonce(42); + makeObjectWithFinalizer(finalizer, token); + + final awaitBeforeShuttingDown = ReceivePort(); + port.send(awaitBeforeShuttingDown.sendPort); + final message = await awaitBeforeShuttingDown.first; + print('$name: $message'); + + await Future.delayed(Duration(milliseconds: 1)); + print('$name: Awaited to see if there were any callbacks.'); + + print('$name: Helper isolate exiting. num callbacks: $callbackCount.'); + port.send(callbackCount); +} diff --git a/runtime/tests/vm/dart/finalizer/finalizer_isolate_groups_run_gc_test.dart b/runtime/tests/vm/dart/finalizer/finalizer_isolate_groups_run_gc_test.dart new file mode 100644 index 00000000000..ba5216fd60d --- /dev/null +++ b/runtime/tests/vm/dart/finalizer/finalizer_isolate_groups_run_gc_test.dart @@ -0,0 +1,93 @@ +// 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. + +// VMOptions= +// VMOptions=--use_compactor +// VMOptions=--use_compactor --force_evacuation + +import 'dart:async'; +import 'dart:isolate'; + +import 'package:async/async.dart'; +import 'package:expect/expect.dart'; + +import 'helpers.dart'; + +void main() async { + await testFinalizerInOtherIsolateGroupGCBeforeExit(); + await testFinalizerInOtherIsolateGroupGCAfterExit(); + await testFinalizerInOtherIsolateGroupNoGC(); + + print('$name: End of test, shutting down.'); +} + +const name = 'main'; + +late bool hotReloadBot; + +Future testFinalizerInOtherIsolateGroupGCBeforeExit() async { + final receivePort = ReceivePort(); + final messagesQueue = StreamQueue(receivePort); + + await Isolate.spawnUri( + Uri.parse('finalizer_isolate_groups_run_gc_helper.dart'), + ['helper 1'], + receivePort.sendPort, + ); + final signalHelperIsolate = await messagesQueue.next as SendPort; + + doGC(name: name); + await yieldToMessageLoop(name: name); + + signalHelperIsolate.send('Done GCing.'); + + final helperCallbacks = await messagesQueue.next as int; + messagesQueue.cancel(); + print('$name: Helper exited.'); + // Different isolate group, so we don't expect a GC in this isolate to cause + // collected objects in the helper. + // Except for in --hot-reload-test-mode, then the GC is triggered. + hotReloadBot = helperCallbacks == 1; +} + +Future testFinalizerInOtherIsolateGroupGCAfterExit() async { + final receivePort = ReceivePort(); + final messagesQueue = StreamQueue(receivePort); + await Isolate.spawnUri( + Uri.parse('finalizer_isolate_groups_run_gc_helper.dart'), + ['helper 2'], + receivePort.sendPort, + ); + + final signalHelperIsolate = await messagesQueue.next as SendPort; + + signalHelperIsolate.send('Before GCing.'); + + final helperCallbacks = await messagesQueue.next as int; + messagesQueue.cancel(); + print('$name: Helper exited.'); + Expect.equals(hotReloadBot ? 1 : 0, helperCallbacks); + + doGC(name: name); + await yieldToMessageLoop(name: name); +} + +Future testFinalizerInOtherIsolateGroupNoGC() async { + final receivePort = ReceivePort(); + final messagesQueue = StreamQueue(receivePort); + + await Isolate.spawnUri( + Uri.parse('finalizer_isolate_groups_run_gc_helper.dart'), + ['helper 3'], + receivePort.sendPort, + ); + final signalHelperIsolate = await messagesQueue.next as SendPort; + + signalHelperIsolate.send('Before quitting main isolate.'); + + final helperCallbacks = await messagesQueue.next as int; + messagesQueue.cancel(); + print('$name: Helper exited.'); + Expect.equals(hotReloadBot ? 1 : 0, helperCallbacks); +} diff --git a/runtime/tests/vm/dart/finalizer/finalizer_isolates_run_gc_test.dart b/runtime/tests/vm/dart/finalizer/finalizer_isolates_run_gc_test.dart new file mode 100644 index 00000000000..5750bf438ec --- /dev/null +++ b/runtime/tests/vm/dart/finalizer/finalizer_isolates_run_gc_test.dart @@ -0,0 +1,103 @@ +// 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. + +// VMOptions= +// VMOptions=--use_compactor +// VMOptions=--use_compactor --force_evacuation + +import 'dart:async'; +import 'dart:isolate'; + +import 'package:expect/expect.dart'; + +import 'helpers.dart'; + +void main() async { + await testNormalExit(); + await testSendAndExit(); + await testSendAndExitFinalizer(); + print('End of test, shutting down.'); +} + +final finalizerTokens = {}; + +void callback(Nonce token) { + print('Running finalizer: token: $token'); + finalizerTokens.add(token); +} + +void runIsolateAttachFinalizer(Object? message) { + final finalizer = Finalizer(callback); + final value = Nonce(1001); + final token = Nonce(1002); + finalizer.attach(value, token); + final token9 = Nonce(9002); + makeObjectWithFinalizer(finalizer, token9); + if (message == null) { + print('Isolate done.'); + return; + } + final list = message as List; + assert(list.length == 2); + final sendPort = list[0] as SendPort; + final tryToSendFinalizer = list[1] as bool; + if (tryToSendFinalizer) { + Expect.throws(() { + // TODO(http://dartbug.com/47777): Send and exit support. + print('Trying to send and exit finalizer.'); + Isolate.exit(sendPort, [value, finalizer]); + }); + } + print('Isolate sending and exit.'); + Isolate.exit(sendPort, [value]); +} + +Future testNormalExit() async { + final portExitMessage = ReceivePort(); + await Isolate.spawn( + runIsolateAttachFinalizer, + null, + onExit: portExitMessage.sendPort, + ); + await portExitMessage.first; + + doGC(); + await yieldToMessageLoop(); + + Expect.equals(0, finalizerTokens.length); +} + +@pragma('vm:never-inline') +Future testSendAndExitHelper( + {bool trySendFinalizer = false}) async { + final port = ReceivePort(); + await Isolate.spawn( + runIsolateAttachFinalizer, + [port.sendPort, trySendFinalizer], + ); + final message = await port.first as List; + print('Received message ($message).'); + final value = message[0] as Nonce; + print('Received value ($value), but now forgetting about it.'); + + Expect.equals(1, message.length); + // TODO(http://dartbug.com/47777): Send and exit support. + return null; +} + +Future testSendAndExit() async { + await testSendAndExitHelper(trySendFinalizer: false); + + doGC(); + await yieldToMessageLoop(); + + Expect.equals(0, finalizerTokens.length); +} + +Future testSendAndExitFinalizer() async { + final finalizer = await testSendAndExitHelper(trySendFinalizer: true); + + // TODO(http://dartbug.com/47777): Send and exit support. + Expect.isNull(finalizer); +} diff --git a/runtime/tests/vm/dart/finalizer/finalizer_nullable_run_gc_test.dart b/runtime/tests/vm/dart/finalizer/finalizer_nullable_run_gc_test.dart new file mode 100644 index 00000000000..8000a41a8e7 --- /dev/null +++ b/runtime/tests/vm/dart/finalizer/finalizer_nullable_run_gc_test.dart @@ -0,0 +1,43 @@ +// 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 'package:expect/expect.dart'; + +import 'helpers.dart'; + +void main() { + testFinalizer(); +} + +void testFinalizer() async { + final finalizerTokens = {}; + void callback(Nonce? token) { + print('Running finalizer: token: $token'); + finalizerTokens.add(token); + } + + final finalizer = Finalizer(callback); + + { + final detach = Nonce(2022); + final token = null; + + makeObjectWithFinalizer(finalizer, token, detach: detach); + + doGC(); + + // We haven't stopped running synchronous dart code yet. + Expect.isFalse(finalizerTokens.contains(token)); + + await Future.delayed(Duration(milliseconds: 1)); + + // Now we have. + Expect.isTrue(finalizerTokens.contains(token)); + + // Try detaching after finalizer ran. + finalizer.detach(detach); + } + + print('End of test, shutting down.'); +} diff --git a/runtime/tests/vm/dart/finalizer/finalizer_run_gc_test.dart b/runtime/tests/vm/dart/finalizer/finalizer_run_gc_test.dart new file mode 100644 index 00000000000..a278b5db88d --- /dev/null +++ b/runtime/tests/vm/dart/finalizer/finalizer_run_gc_test.dart @@ -0,0 +1,90 @@ +// 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. + +// VMOptions= +// VMOptions=--use_compactor +// VMOptions=--use_compactor --force_evacuation + +import 'package:expect/expect.dart'; + +import 'helpers.dart'; + +void main() { + testWrongArguments(); + testFinalizer(); +} + +void testWrongArguments() { + void callback(Object token) { + throw 'This should never happen!'; + } + + final finalizer = Finalizer(callback); + final myFinalizable = Nonce(1000); + final token = Nonce(2000); + final detach = Nonce(3000); + + Expect.throws(() { + finalizer.attach(myFinalizable, token, detach: 123); + }); + Expect.throws(() { + finalizer.attach(123, token, detach: detach); + }); +} + +void testFinalizer() async { + final finalizerTokens = {}; + void callback(Object token) { + print('Running finalizer: token: $token'); + finalizerTokens.add(token); + } + + final finalizer = Finalizer(callback); + + { + final detach = Nonce(2022); + final token = Nonce(42); + + makeObjectWithFinalizer(finalizer, token, detach: detach); + + doGC(); + + // We haven't stopped running synchronous dart code yet. + Expect.isFalse(finalizerTokens.contains(token)); + + await Future.delayed(Duration(milliseconds: 1)); + + // Now we have. + Expect.isTrue(finalizerTokens.contains(token)); + + // Try detaching after finalizer ran. + finalizer.detach(detach); + } + + { + final token = Nonce(1337); + final token2 = Nonce(1338); + final detachkey = Nonce(1984); + { + final value = Nonce(2); + final value2 = Nonce(2000000); + finalizer.attach(value, token, detach: detachkey); + finalizer.attach(value2, token2, detach: detachkey); + // Should detach 2 finalizers. + finalizer.detach(detachkey); + // Try detaching again, should do nothing. + finalizer.detach(detachkey); + } + doGC(); + await yieldToMessageLoop(); + Expect.isFalse(finalizerTokens.contains(token)); + Expect.isFalse(finalizerTokens.contains(token2)); + } + + // Not running finalizer on shutdown. + final value = Nonce(3); + final token = Nonce(1337); + finalizer.attach(value, token); + print('End of test, shutting down.'); +} diff --git a/runtime/tests/vm/dart/finalizer/finalizer_zone_run_gc_test.dart b/runtime/tests/vm/dart/finalizer/finalizer_zone_run_gc_test.dart new file mode 100644 index 00000000000..bcc6d9e1d04 --- /dev/null +++ b/runtime/tests/vm/dart/finalizer/finalizer_zone_run_gc_test.dart @@ -0,0 +1,73 @@ +// 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. + +// VMOptions= +// VMOptions=--use_compactor +// VMOptions=--use_compactor --force_evacuation + +import 'dart:async'; + +import 'package:expect/expect.dart'; + +import 'helpers.dart'; + +void main() async { + await testFinalizerZone(); + await testFinalizerException(); +} + +Future testFinalizerZone() async { + Zone? expectedZone; + Zone? actualZone; + + final finalizer = runZoned(() { + expectedZone = Zone.current; + + void callback(Object token) { + actualZone = Zone.current; + } + + return Finalizer(callback); + }); + + final detach = Nonce(2022); + final token = Nonce(42); + + makeObjectWithFinalizer(finalizer, token, detach: detach); + + doGC(); + + // We haven't stopped running synchronous dart code yet. + Expect.isNull(actualZone); + + await yieldToMessageLoop(); + + // Now we have. + Expect.equals(expectedZone, actualZone); +} + +Future testFinalizerException() async { + Object? caughtError; + + final finalizer = runZonedGuarded(() { + void callback(Object token) { + throw 'uncaught!'; + } + + return Finalizer(callback); + }, (Object error, StackTrace stack) { + caughtError = error; + })!; + + final detach = Nonce(2022); + final token = Nonce(42); + + makeObjectWithFinalizer(finalizer, token, detach: detach); + + doGC(); + + Expect.isNull(caughtError); + await yieldToMessageLoop(); + Expect.isNotNull(caughtError); +} diff --git a/runtime/tests/vm/dart/finalizer/helpers.dart b/runtime/tests/vm/dart/finalizer/helpers.dart new file mode 100644 index 00000000000..d776098aced --- /dev/null +++ b/runtime/tests/vm/dart/finalizer/helpers.dart @@ -0,0 +1,55 @@ +// 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. + +// ignore: import_internal_library, unused_import +import 'dart:_internal'; +import 'dart:async'; + +/// A user-defined class of which objects can be identified with a field value. +class Nonce { + final int value; + + Nonce(this.value); + + String toString() => 'Nonce($value)'; +} + +/// Never inline to ensure `object` becomes unreachable. +@pragma('vm:never-inline') +void makeObjectWithFinalizer(Finalizer finalizer, T token, + {Object? detach}) { + final value = Nonce(1); + finalizer.attach(value, token, detach: detach); +} + +/// Triggers garbage collection. +// Defined in `dart:_internal`. +// ignore: undefined_identifier +void triggerGc() => VMInternalsForTesting.collectAllGarbage(); + +void Function(String) _namedPrint(String? name) { + if (name != null) { + return (String value) => print('$name: $value'); + } + return (String value) => print(value); +} + +/// Does a GC and if [doAwait] awaits a future to enable running finalizers. +/// +/// Also prints for debug purposes. +/// +/// If provided, [name] prefixes the debug prints. +void doGC({String? name}) { + final _print = _namedPrint(name); + + _print('Do GC.'); + triggerGc(); + _print('GC done'); +} + +Future yieldToMessageLoop({String? name}) async { + await Future.delayed(Duration(milliseconds: 1)); + _namedPrint(name)('Await done.'); + return null; +} diff --git a/runtime/tests/vm/dart/finalizer/weak_reference_run_gc_test.dart b/runtime/tests/vm/dart/finalizer/weak_reference_run_gc_test.dart index 15b330d16b7..da365b98f9d 100644 --- a/runtime/tests/vm/dart/finalizer/weak_reference_run_gc_test.dart +++ b/runtime/tests/vm/dart/finalizer/weak_reference_run_gc_test.dart @@ -2,25 +2,16 @@ // 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. -// ignore: import_internal_library, unused_import -import 'dart:_internal'; - import 'package:expect/expect.dart'; +import 'helpers.dart'; + void main() { testWeakReferenceNonExpandoKey(); testWeakReferenceTypeArgument(); testWeakReference(); } -class Nonce { - final int value; - - Nonce(this.value); - - String toString() => 'Nonce($value)'; -} - void testWeakReferenceNonExpandoKey() { Expect.throwsArgumentError(() { WeakReference("Hello world!"); @@ -55,7 +46,3 @@ void testWeakReference() { print('End of test, shutting down.'); } - -// Defined in `dart:_internal`. -// ignore: undefined_identifier -void triggerGc() => VMInternalsForTesting.collectAllGarbage(); diff --git a/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart b/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart index cd24fbc5143..d714c560be8 100644 --- a/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart +++ b/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart @@ -245,6 +245,7 @@ class SendReceiveTest extends SendReceiveTestBase { await testWeakProperty(); await testWeakReference(); + await testFinalizer(); await testForbiddenClosures(); } @@ -756,6 +757,14 @@ class SendReceiveTest extends SendReceiveTestBase { } } + Future testFinalizer() async { + print('testFinalizer'); + + void callback(Object token) {} + final finalizer = Finalizer(callback); + Expect.throwsArgumentError(() => sendPort.send(finalizer)); + } + Future testForbiddenClosures() async { print('testForbiddenClosures'); for (final closure in nonCopyableClosures) { diff --git a/runtime/tests/vm/dart_2/finalizer/finalizer_isolate_groups_run_gc_helper.dart b/runtime/tests/vm/dart_2/finalizer/finalizer_isolate_groups_run_gc_helper.dart new file mode 100644 index 00000000000..58ff5bbcbba --- /dev/null +++ b/runtime/tests/vm/dart_2/finalizer/finalizer_isolate_groups_run_gc_helper.dart @@ -0,0 +1,38 @@ +// 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. + +// @dart = 2.9 + +import 'dart:isolate'; + +import 'helpers.dart'; + +int callbackCount = 0; + +void callback(Nonce token) { + callbackCount++; + print('$name: Running finalizer: token: $token'); +} + +final finalizer = Finalizer(callback); + +String name; + +void main(List arguments, SendPort port) async { + name = arguments[0]; + + final token = Nonce(42); + makeObjectWithFinalizer(finalizer, token); + + final awaitBeforeShuttingDown = ReceivePort(); + port.send(awaitBeforeShuttingDown.sendPort); + final message = await awaitBeforeShuttingDown.first; + print('$name: $message'); + + await Future.delayed(Duration(milliseconds: 1)); + print('$name: Awaited to see if there were any callbacks.'); + + print('$name: Helper isolate exiting. num callbacks: $callbackCount.'); + port.send(callbackCount); +} diff --git a/runtime/tests/vm/dart_2/finalizer/finalizer_isolate_groups_run_gc_test.dart b/runtime/tests/vm/dart_2/finalizer/finalizer_isolate_groups_run_gc_test.dart new file mode 100644 index 00000000000..afd09bba078 --- /dev/null +++ b/runtime/tests/vm/dart_2/finalizer/finalizer_isolate_groups_run_gc_test.dart @@ -0,0 +1,95 @@ +// 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. + +// VMOptions= +// VMOptions=--use_compactor +// VMOptions=--use_compactor --force_evacuation + +// @dart = 2.9 + +import 'dart:async'; +import 'dart:isolate'; + +import 'package:async/async.dart'; +import 'package:expect/expect.dart'; + +import 'helpers.dart'; + +void main() async { + await testFinalizerInOtherIsolateGroupGCBeforeExit(); + await testFinalizerInOtherIsolateGroupGCAfterExit(); + await testFinalizerInOtherIsolateGroupNoGC(); + + print('$name: End of test, shutting down.'); +} + +const name = 'main'; + +bool hotReloadBot; + +Future testFinalizerInOtherIsolateGroupGCBeforeExit() async { + final receivePort = ReceivePort(); + final messagesQueue = StreamQueue(receivePort); + + await Isolate.spawnUri( + Uri.parse('finalizer_isolate_groups_run_gc_helper.dart'), + ['helper 1'], + receivePort.sendPort, + ); + final signalHelperIsolate = await messagesQueue.next as SendPort; + + doGC(name: name); + await yieldToMessageLoop(name: name); + + signalHelperIsolate.send('Done GCing.'); + + final helperCallbacks = await messagesQueue.next as int; + messagesQueue.cancel(); + print('$name: Helper exited.'); + // Different isolate group, so we don't expect a GC in this isolate to cause + // collected objects in the helper. + // Except for in --hot-reload-test-mode, then the GC is triggered. + hotReloadBot = helperCallbacks == 1; +} + +Future testFinalizerInOtherIsolateGroupGCAfterExit() async { + final receivePort = ReceivePort(); + final messagesQueue = StreamQueue(receivePort); + await Isolate.spawnUri( + Uri.parse('finalizer_isolate_groups_run_gc_helper.dart'), + ['helper 2'], + receivePort.sendPort, + ); + + final signalHelperIsolate = await messagesQueue.next as SendPort; + + signalHelperIsolate.send('Before GCing.'); + + final helperCallbacks = await messagesQueue.next as int; + messagesQueue.cancel(); + print('$name: Helper exited.'); + Expect.equals(hotReloadBot ? 1 : 0, helperCallbacks); + + doGC(name: name); + await yieldToMessageLoop(name: name); +} + +Future testFinalizerInOtherIsolateGroupNoGC() async { + final receivePort = ReceivePort(); + final messagesQueue = StreamQueue(receivePort); + + await Isolate.spawnUri( + Uri.parse('finalizer_isolate_groups_run_gc_helper.dart'), + ['helper 3'], + receivePort.sendPort, + ); + final signalHelperIsolate = await messagesQueue.next as SendPort; + + signalHelperIsolate.send('Before quitting main isolate.'); + + final helperCallbacks = await messagesQueue.next as int; + messagesQueue.cancel(); + print('$name: Helper exited.'); + Expect.equals(hotReloadBot ? 1 : 0, helperCallbacks); +} diff --git a/runtime/tests/vm/dart_2/finalizer/finalizer_isolates_run_gc_test.dart b/runtime/tests/vm/dart_2/finalizer/finalizer_isolates_run_gc_test.dart new file mode 100644 index 00000000000..7c2103d881e --- /dev/null +++ b/runtime/tests/vm/dart_2/finalizer/finalizer_isolates_run_gc_test.dart @@ -0,0 +1,104 @@ +// 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. + +// VMOptions= +// VMOptions=--use_compactor +// VMOptions=--use_compactor --force_evacuation + +// @dart = 2.9 + +import 'dart:async'; +import 'dart:isolate'; + +import 'package:expect/expect.dart'; + +import 'helpers.dart'; + +void main() async { + await testNormalExit(); + await testSendAndExit(); + await testSendAndExitFinalizer(); + print('End of test, shutting down.'); +} + +final finalizerTokens = {}; + +void callback(Nonce token) { + print('Running finalizer: token: $token'); + finalizerTokens.add(token); +} + +void runIsolateAttachFinalizer(Object message) { + final finalizer = Finalizer(callback); + final value = Nonce(1001); + final token = Nonce(1002); + finalizer.attach(value, token); + final token9 = Nonce(9002); + makeObjectWithFinalizer(finalizer, token9); + if (message == null) { + print('Isolate done.'); + return; + } + final list = message as List; + assert(list.length == 2); + final sendPort = list[0] as SendPort; + final tryToSendFinalizer = list[1] as bool; + if (tryToSendFinalizer) { + Expect.throws(() { + // TODO(http://dartbug.com/47777): Send and exit support. + print('Trying to send and exit finalizer.'); + Isolate.exit(sendPort, [value, finalizer]); + }); + } + print('Isolate sending and exit.'); + Isolate.exit(sendPort, [value]); +} + +Future testNormalExit() async { + final portExitMessage = ReceivePort(); + await Isolate.spawn( + runIsolateAttachFinalizer, + null, + onExit: portExitMessage.sendPort, + ); + await portExitMessage.first; + + doGC(); + await yieldToMessageLoop(); + + Expect.equals(0, finalizerTokens.length); +} + +@pragma('vm:never-inline') +Future testSendAndExitHelper({bool trySendFinalizer = false}) async { + final port = ReceivePort(); + await Isolate.spawn( + runIsolateAttachFinalizer, + [port.sendPort, trySendFinalizer], + ); + final message = await port.first as List; + print('Received message ($message).'); + final value = message[0] as Nonce; + print('Received value ($value), but now forgetting about it.'); + + Expect.equals(1, message.length); + // TODO(http://dartbug.com/47777): Send and exit support. + return null; +} + +Future testSendAndExit() async { + await testSendAndExitHelper(trySendFinalizer: false); + + doGC(); + await yieldToMessageLoop(); + + Expect.equals(0, finalizerTokens.length); +} + +Future testSendAndExitFinalizer() async { + final finalizer = await testSendAndExitHelper(trySendFinalizer: true); + + // TODO(http://dartbug.com/47777): Send and exit support. + Expect.isNull(finalizer); +} diff --git a/runtime/tests/vm/dart_2/finalizer/finalizer_nullable_run_gc_test.dart b/runtime/tests/vm/dart_2/finalizer/finalizer_nullable_run_gc_test.dart new file mode 100644 index 00000000000..b033c1b3f55 --- /dev/null +++ b/runtime/tests/vm/dart_2/finalizer/finalizer_nullable_run_gc_test.dart @@ -0,0 +1,45 @@ +// 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. + +// @dart = 2.9 + +import 'package:expect/expect.dart'; + +import 'helpers.dart'; + +void main() { + testFinalizer(); +} + +void testFinalizer() async { + final finalizerTokens = {}; + void callback(Nonce token) { + print('Running finalizer: token: $token'); + finalizerTokens.add(token); + } + + final finalizer = Finalizer(callback); + + { + final detach = Nonce(2022); + final token = null; + + makeObjectWithFinalizer(finalizer, token, detach: detach); + + doGC(); + + // We haven't stopped running synchronous dart code yet. + Expect.isFalse(finalizerTokens.contains(token)); + + await Future.delayed(Duration(milliseconds: 1)); + + // Now we have. + Expect.isTrue(finalizerTokens.contains(token)); + + // Try detaching after finalizer ran. + finalizer.detach(detach); + } + + print('End of test, shutting down.'); +} diff --git a/runtime/tests/vm/dart_2/finalizer/finalizer_run_gc_test.dart b/runtime/tests/vm/dart_2/finalizer/finalizer_run_gc_test.dart new file mode 100644 index 00000000000..9c174612242 --- /dev/null +++ b/runtime/tests/vm/dart_2/finalizer/finalizer_run_gc_test.dart @@ -0,0 +1,92 @@ +// 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. + +// VMOptions= +// VMOptions=--use_compactor +// VMOptions=--use_compactor --force_evacuation + +// @dart = 2.9 + +import 'package:expect/expect.dart'; + +import 'helpers.dart'; + +void main() { + testWrongArguments(); + testFinalizer(); +} + +void testWrongArguments() { + void callback(Object token) { + throw 'This should never happen!'; + } + + final finalizer = Finalizer(callback); + final myFinalizable = Nonce(1000); + final token = Nonce(2000); + final detach = Nonce(3000); + + Expect.throws(() { + finalizer.attach(myFinalizable, token, detach: 123); + }); + Expect.throws(() { + finalizer.attach(123, token, detach: detach); + }); +} + +void testFinalizer() async { + final finalizerTokens = {}; + void callback(Object token) { + print('Running finalizer: token: $token'); + finalizerTokens.add(token); + } + + final finalizer = Finalizer(callback); + + { + final detach = Nonce(2022); + final token = Nonce(42); + + makeObjectWithFinalizer(finalizer, token, detach: detach); + + doGC(); + + // We haven't stopped running synchronous dart code yet. + Expect.isFalse(finalizerTokens.contains(token)); + + await Future.delayed(Duration(milliseconds: 1)); + + // Now we have. + Expect.isTrue(finalizerTokens.contains(token)); + + // Try detaching after finalizer ran. + finalizer.detach(detach); + } + + { + final token = Nonce(1337); + final token2 = Nonce(1338); + final detachkey = Nonce(1984); + { + final value = Nonce(2); + final value2 = Nonce(2000000); + finalizer.attach(value, token, detach: detachkey); + finalizer.attach(value2, token2, detach: detachkey); + // Should detach 2 finalizers. + finalizer.detach(detachkey); + // Try detaching again, should do nothing. + finalizer.detach(detachkey); + } + doGC(); + await yieldToMessageLoop(); + Expect.isFalse(finalizerTokens.contains(token)); + Expect.isFalse(finalizerTokens.contains(token2)); + } + + // Not running finalizer on shutdown. + final value = Nonce(3); + final token = Nonce(1337); + finalizer.attach(value, token); + print('End of test, shutting down.'); +} diff --git a/runtime/tests/vm/dart_2/finalizer/finalizer_zone_run_gc_test.dart b/runtime/tests/vm/dart_2/finalizer/finalizer_zone_run_gc_test.dart new file mode 100644 index 00000000000..17646d1ec0d --- /dev/null +++ b/runtime/tests/vm/dart_2/finalizer/finalizer_zone_run_gc_test.dart @@ -0,0 +1,75 @@ +// 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. + +// VMOptions= +// VMOptions=--use_compactor +// VMOptions=--use_compactor --force_evacuation + +// @dart = 2.9 + +import 'dart:async'; + +import 'package:expect/expect.dart'; + +import 'helpers.dart'; + +void main() async { + await testFinalizerZone(); + await testFinalizerException(); +} + +Future testFinalizerZone() async { + Zone expectedZone; + Zone actualZone; + + final finalizer = runZoned(() { + expectedZone = Zone.current; + + void callback(Object token) { + actualZone = Zone.current; + } + + return Finalizer(callback); + }); + + final detach = Nonce(2022); + final token = Nonce(42); + + makeObjectWithFinalizer(finalizer, token, detach: detach); + + doGC(); + + // We haven't stopped running synchronous dart code yet. + Expect.isNull(actualZone); + + await yieldToMessageLoop(); + + // Now we have. + Expect.equals(expectedZone, actualZone); +} + +Future testFinalizerException() async { + Object caughtError; + + final finalizer = runZonedGuarded(() { + void callback(Object token) { + throw 'uncaught!'; + } + + return Finalizer(callback); + }, (Object error, StackTrace stack) { + caughtError = error; + }); + + final detach = Nonce(2022); + final token = Nonce(42); + + makeObjectWithFinalizer(finalizer, token, detach: detach); + + doGC(); + + Expect.isNull(caughtError); + await yieldToMessageLoop(); + Expect.isNotNull(caughtError); +} diff --git a/runtime/tests/vm/dart_2/finalizer/helpers.dart b/runtime/tests/vm/dart_2/finalizer/helpers.dart new file mode 100644 index 00000000000..a82646ce344 --- /dev/null +++ b/runtime/tests/vm/dart_2/finalizer/helpers.dart @@ -0,0 +1,57 @@ +// 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. + +// @dart = 2.9 + +// ignore: import_internal_library, unused_import +import 'dart:_internal'; +import 'dart:async'; + +/// A user-defined class of which objects can be identified with a field value. +class Nonce { + final int value; + + Nonce(this.value); + + String toString() => 'Nonce($value)'; +} + +/// Never inline to ensure `value` becomes unreachable. +@pragma('vm:never-inline') +void makeObjectWithFinalizer(Finalizer finalizer, T token, + {Object detach}) { + final value = Nonce(1); + finalizer.attach(value, token, detach: detach); +} + +/// Triggers garbage collection. +// Defined in `dart:_internal`. +// ignore: undefined_identifier +void triggerGc() => VMInternalsForTesting.collectAllGarbage(); + +void Function(String) _namedPrint(String name) { + if (name != null) { + return (String value) => print('$name: $value'); + } + return (String value) => print(value); +} + +/// Does a GC and if [doAwait] awaits a future to enable running finalizers. +/// +/// Also prints for debug purposes. +/// +/// If provided, [name] prefixes the debug prints. +void doGC({String name}) { + final _print = _namedPrint(name); + + _print('Do GC.'); + triggerGc(); + _print('GC done'); +} + +Future yieldToMessageLoop({String name}) async { + await Future.delayed(Duration(milliseconds: 1)); + _namedPrint(name)('Await done.'); + return null; +} diff --git a/runtime/tests/vm/dart_2/finalizer/weak_reference_run_gc_test.dart b/runtime/tests/vm/dart_2/finalizer/weak_reference_run_gc_test.dart index 8c7583d9462..708d5403274 100644 --- a/runtime/tests/vm/dart_2/finalizer/weak_reference_run_gc_test.dart +++ b/runtime/tests/vm/dart_2/finalizer/weak_reference_run_gc_test.dart @@ -4,25 +4,16 @@ // @dart = 2.9 -// ignore: import_internal_library, unused_import -import 'dart:_internal'; - import 'package:expect/expect.dart'; +import 'helpers.dart'; + void main() { testWeakReferenceNonExpandoKey(); testWeakReferenceTypeArgument(); testWeakReference(); } -class Nonce { - final int value; - - Nonce(this.value); - - String toString() => 'Nonce($value)'; -} - void testWeakReferenceNonExpandoKey() { Expect.throwsArgumentError(() { WeakReference("Hello world!"); @@ -57,7 +48,3 @@ void testWeakReference() { print('End of test, shutting down.'); } - -// Defined in `dart:_internal`. -// ignore: undefined_identifier -void triggerGc() => VMInternalsForTesting.collectAllGarbage(); diff --git a/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart b/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart index 1843f0c7f96..91fd27d2ed3 100644 --- a/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart +++ b/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart @@ -247,6 +247,7 @@ class SendReceiveTest extends SendReceiveTestBase { await testWeakProperty(); await testWeakReference(); + await testFinalizer(); await testForbiddenClosures(); } @@ -758,6 +759,14 @@ class SendReceiveTest extends SendReceiveTestBase { } } + Future testFinalizer() async { + print('testFinalizer'); + + void callback(Object token) {} + final finalizer = Finalizer(callback); + Expect.throwsArgumentError(() => sendPort.send(finalizer)); + } + Future testForbiddenClosures() async { print('testForbiddenClosures'); for (final closure in nonCopyableClosures) { diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status index 1f5066c31fb..8feee006d68 100644 --- a/runtime/tests/vm/vm.status +++ b/runtime/tests/vm/vm.status @@ -108,6 +108,7 @@ dart_2/isolates/reload_*: SkipByDesign # These tests only run on normal JIT. [ $compiler == dartkp ] dart/causal_stacks/async_throws_stack_no_causal_non_symbolic_test: SkipByDesign # --no-lazy... does nothing on precompiler. dart/causal_stacks/async_throws_stack_no_causal_test: SkipByDesign # --no-lazy... does nothing on precompiler. +dart/finalizer/finalizer_isolate_groups_run_gc_test: SkipByDesign # Isolate.spawnUri is not supported in AOT. dart/redirection_type_shuffling_test: SkipByDesign # Uses dart:mirrors. dart/scavenger_abort_test: SkipSlow dart/v8_snapshot_profile_writer_test: Pass, Slow # Can be slow due to re-invoking the precompiler. @@ -442,9 +443,11 @@ dart_2/*: SkipByDesign # Legacy tests are not supposed to run on NNBD bots. # These Isolate tests that use spawnURI are hence skipped on purpose. [ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ] dart/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri +dart/finalizer/finalizer_isolate_groups_run_gc_test: SkipByDesign # uses spawnUri. dart/isolates/send_object_to_spawn_uri_isolate_test: SkipByDesign # uses spawnUri dart/issue32950_test: SkipByDesign # uses spawnUri. dart_2/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri +dart_2/finalizer/finalizer_isolate_groups_run_gc_test: SkipByDesign # uses spawnUri. dart_2/isolates/send_object_to_spawn_uri_isolate_test: SkipByDesign # uses spawnUri dart_2/issue32950_test: SkipByDesign # uses spawnUri. diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc index dc432e37da0..e91180e0030 100644 --- a/runtime/vm/class_finalizer.cc +++ b/runtime/vm/class_finalizer.cc @@ -267,6 +267,10 @@ void ClassFinalizer::VerifyBootstrapClasses() { ASSERT_EQUAL(WeakProperty::InstanceSize(), cls.host_instance_size()); cls = object_store->weak_reference_class(); ASSERT_EQUAL(WeakReference::InstanceSize(), cls.host_instance_size()); + cls = object_store->finalizer_class(); + ASSERT_EQUAL(Finalizer::InstanceSize(), cls.host_instance_size()); + cls = object_store->finalizer_entry_class(); + ASSERT_EQUAL(FinalizerEntry::InstanceSize(), cls.host_instance_size()); cls = object_store->linked_hash_map_class(); ASSERT_EQUAL(LinkedHashMap::InstanceSize(), cls.host_instance_size()); cls = object_store->immutable_linked_hash_map_class(); diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h index 93e1979eaff..501c3a827c5 100644 --- a/runtime/vm/class_id.h +++ b/runtime/vm/class_id.h @@ -68,6 +68,9 @@ typedef uint16_t ClassIdTagType; V(TypeArguments) \ V(AbstractType) \ V(Type) \ + V(FinalizerBase) \ + V(Finalizer) \ + V(FinalizerEntry) \ V(FunctionType) \ V(TypeRef) \ V(TypeParameter) \ diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc index 4d28937959b..8d01fc7901d 100644 --- a/runtime/vm/compiler/backend/range_analysis.cc +++ b/runtime/vm/compiler/backend/range_analysis.cc @@ -2797,6 +2797,16 @@ void LoadFieldInstr::InferRange(RangeAnalysis* analysis, Range* range) { case Slot::Kind::kClosure_function: case Slot::Kind::kClosure_function_type_arguments: case Slot::Kind::kClosure_instantiator_type_arguments: + case Slot::Kind::kFinalizer_callback: + case Slot::Kind::kFinalizer_type_arguments: + case Slot::Kind::kFinalizerBase_all_entries: + case Slot::Kind::kFinalizerBase_detachments: + case Slot::Kind::kFinalizerBase_entries_collected: + case Slot::Kind::kFinalizerEntry_detach: + case Slot::Kind::kFinalizerEntry_finalizer: + case Slot::Kind::kFinalizerEntry_next: + case Slot::Kind::kFinalizerEntry_token: + case Slot::Kind::kFinalizerEntry_value: case Slot::Kind::kFunction_data: case Slot::Kind::kFunction_signature: case Slot::Kind::kFunctionType_named_parameter_names: diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc index 4a512f82325..dfd04aca34f 100644 --- a/runtime/vm/compiler/backend/slot.cc +++ b/runtime/vm/compiler/backend/slot.cc @@ -227,6 +227,16 @@ bool Slot::IsImmutableLengthSlot() const { case Slot::Kind::kClosure_hash: case Slot::Kind::kCapturedVariable: case Slot::Kind::kDartField: + case Slot::Kind::kFinalizer_callback: + case Slot::Kind::kFinalizer_type_arguments: + case Slot::Kind::kFinalizerBase_all_entries: + case Slot::Kind::kFinalizerBase_detachments: + case Slot::Kind::kFinalizerBase_entries_collected: + case Slot::Kind::kFinalizerEntry_detach: + case Slot::Kind::kFinalizerEntry_finalizer: + case Slot::Kind::kFinalizerEntry_next: + case Slot::Kind::kFinalizerEntry_token: + case Slot::Kind::kFinalizerEntry_value: case Slot::Kind::kFunction_data: case Slot::Kind::kFunction_signature: case Slot::Kind::kFunctionType_named_parameter_names: diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h index ab82fe27180..995ce8cf66b 100644 --- a/runtime/vm/compiler/backend/slot.h +++ b/runtime/vm/compiler/backend/slot.h @@ -53,6 +53,15 @@ class ParsedFunction; // that) or like a non-final field. #define NULLABLE_BOXED_NATIVE_SLOTS_LIST(V) \ V(Array, UntaggedArray, type_arguments, TypeArguments, FINAL) \ + V(Finalizer, UntaggedFinalizer, type_arguments, TypeArguments, FINAL) \ + V(FinalizerBase, UntaggedFinalizerBase, all_entries, LinkedHashSet, VAR) \ + V(FinalizerBase, UntaggedFinalizerBase, detachments, Dynamic, VAR) \ + V(FinalizerBase, UntaggedFinalizer, entries_collected, FinalizerEntry, VAR) \ + V(FinalizerEntry, UntaggedFinalizerEntry, value, Dynamic, VAR) \ + V(FinalizerEntry, UntaggedFinalizerEntry, detach, Dynamic, VAR) \ + V(FinalizerEntry, UntaggedFinalizerEntry, token, Dynamic, VAR) \ + V(FinalizerEntry, UntaggedFinalizerEntry, finalizer, FinalizerBase, VAR) \ + V(FinalizerEntry, UntaggedFinalizerEntry, next, FinalizerEntry, VAR) \ V(Function, UntaggedFunction, signature, FunctionType, FINAL) \ V(Context, UntaggedContext, parent, Context, FINAL) \ V(Closure, UntaggedClosure, instantiator_type_arguments, TypeArguments, \ @@ -91,6 +100,7 @@ class ParsedFunction; V(Closure, UntaggedClosure, function, Function, FINAL) \ V(Closure, UntaggedClosure, context, Context, FINAL) \ V(Closure, UntaggedClosure, hash, Context, VAR) \ + V(Finalizer, UntaggedFinalizer, callback, Closure, FINAL) \ V(Function, UntaggedFunction, data, Dynamic, FINAL) \ V(FunctionType, UntaggedFunctionType, named_parameter_names, Array, FINAL) \ V(FunctionType, UntaggedFunctionType, parameter_types, Array, FINAL) \ @@ -159,6 +169,7 @@ NONNULLABLE_BOXED_NATIVE_SLOTS_LIST(FOR_EACH_NATIVE_SLOT) AOT_ONLY_UNBOXED_NATIVE_SLOTS_LIST(V) \ V(ClosureData, UntaggedClosureData, default_type_arguments_kind, Uint8, \ FINAL) \ + V(FinalizerBase, UntaggedFinalizerBase, isolate, IntPtr, VAR) \ V(Function, UntaggedFunction, entry_point, Uword, FINAL) \ V(Function, UntaggedFunction, kind_tag, Uint32, FINAL) \ V(Function, UntaggedFunction, packed_fields, Uint32, FINAL) \ diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 006ea70edc2..9abd1fd95a7 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -818,6 +818,13 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function, V(ByteDataViewLength, TypedDataBase_length) \ V(ByteDataViewOffsetInBytes, TypedDataView_offset_in_bytes) \ V(ByteDataViewTypedData, TypedDataView_typed_data) \ + V(Finalizer_getCallback, Finalizer_callback) \ + V(FinalizerBase_getAllEntries, FinalizerBase_all_entries) \ + V(FinalizerBase_getDetachments, FinalizerBase_detachments) \ + V(FinalizerEntry_getDetach, FinalizerEntry_detach) \ + V(FinalizerEntry_getNext, FinalizerEntry_next) \ + V(FinalizerEntry_getToken, FinalizerEntry_token) \ + V(FinalizerEntry_getValue, FinalizerEntry_value) \ V(GrowableArrayLength, GrowableObjectArray_length) \ V(ImmutableLinkedHashBase_getData, ImmutableLinkedHashBase_data) \ V(ImmutableLinkedHashBase_getIndex, ImmutableLinkedHashBase_index) \ @@ -835,6 +842,14 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function, V(WeakReference_getTarget, WeakReference_target) #define STORE_NATIVE_FIELD(V) \ + V(Finalizer_setCallback, Finalizer_callback) \ + V(FinalizerBase_setAllEntries, FinalizerBase_all_entries) \ + V(FinalizerBase_setDetachments, FinalizerBase_detachments) \ + V(FinalizerEntry_setDetach, FinalizerEntry_detach) \ + V(FinalizerEntry_setFinalizer, FinalizerEntry_finalizer) \ + V(FinalizerEntry_setNext, FinalizerEntry_next) \ + V(FinalizerEntry_setToken, FinalizerEntry_token) \ + V(FinalizerEntry_setValue, FinalizerEntry_value) \ V(LinkedHashBase_setData, LinkedHashBase_data) \ V(LinkedHashBase_setIndex, LinkedHashBase_index) \ V(WeakProperty_setKey, WeakProperty_key) \ @@ -919,6 +934,10 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph( case MethodRecognizer::kFfiAsExternalTypedDataFloat: case MethodRecognizer::kFfiAsExternalTypedDataDouble: case MethodRecognizer::kGetNativeField: + case MethodRecognizer::kFinalizerBase_exchangeEntriesCollectedWithNull: + case MethodRecognizer::kFinalizerBase_getIsolateFinalizers: + case MethodRecognizer::kFinalizerBase_setIsolate: + case MethodRecognizer::kFinalizerBase_setIsolateFinalizers: case MethodRecognizer::kObjectEquals: case MethodRecognizer::kStringBaseLength: case MethodRecognizer::kStringBaseIsEmpty: @@ -1567,6 +1586,41 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod( body += LoadLocal(parsed_function_->RawParameterVariable(0)); body += MathUnary(MathUnaryInstr::kSqrt); } break; + case MethodRecognizer::kFinalizerBase_setIsolate: + ASSERT_EQUAL(function.NumParameters(), 1); + body += LoadLocal(parsed_function_->RawParameterVariable(0)); + body += LoadIsolate(); + body += ConvertUntaggedToUnboxed(kUnboxedIntPtr); + body += StoreNativeField(Slot::FinalizerBase_isolate()); + body += NullConstant(); + break; + case MethodRecognizer::kFinalizerBase_getIsolateFinalizers: + ASSERT_EQUAL(function.NumParameters(), 0); + body += LoadIsolate(); + body += RawLoadField(compiler::target::Isolate::finalizers_offset()); + break; + case MethodRecognizer::kFinalizerBase_setIsolateFinalizers: + ASSERT_EQUAL(function.NumParameters(), 1); + body += LoadIsolate(); + body += LoadLocal(parsed_function_->RawParameterVariable(0)); + body += RawStoreField(compiler::target::Isolate::finalizers_offset()); + body += NullConstant(); + break; + case MethodRecognizer::kFinalizerBase_exchangeEntriesCollectedWithNull: + ASSERT_EQUAL(function.NumParameters(), 1); + ASSERT(this->optimizing_); + // This relies on being force-optimized to do an 'atomic' exchange w.r.t. + // the GC. + // As an alternative design we could introduce an ExchangeNativeFieldInstr + // that uses the same machine code as std::atomic::exchange. Or we could + // use an FfiNative to do that in C. + body += LoadLocal(parsed_function_->RawParameterVariable(0)); + // No GC from here til StoreNativeField. + body += LoadNativeField(Slot::FinalizerBase_entries_collected()); + body += LoadLocal(parsed_function_->RawParameterVariable(0)); + body += NullConstant(); + body += StoreNativeField(Slot::FinalizerBase_entries_collected()); + break; #define IL_BODY(method, slot) \ case MethodRecognizer::k##method: \ ASSERT_EQUAL(function.NumParameters(), 1); \ @@ -3974,6 +4028,19 @@ Fragment FlowGraphBuilder::UnboxTruncate(Representation to) { return Fragment(unbox); } +Fragment FlowGraphBuilder::LoadThread() { + LoadThreadInstr* instr = new (Z) LoadThreadInstr(); + Push(instr); + return Fragment(instr); +} + +Fragment FlowGraphBuilder::LoadIsolate() { + Fragment body; + body += LoadThread(); + body += LoadUntagged(compiler::target::Thread::isolate_offset()); + return body; +} + // TODO(http://dartbug.com/47487): Support unboxed output value. Fragment FlowGraphBuilder::BoolToInt() { // TODO(http://dartbug.com/36855) Build IfThenElseInstr, instead of letting diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h index 03a18f68d44..2a92d6ae212 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.h +++ b/runtime/vm/compiler/frontend/kernel_to_il.h @@ -276,6 +276,12 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder { // target representation. Fragment UnboxTruncate(Representation to); + // Loads the (untagged) thread address. + Fragment LoadThread(); + + // Loads the (untagged) isolate address. + Fragment LoadIsolate(); + // Converts a true to 1 and false to 0. Fragment BoolToInt(); diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h index e8a7016ccae..1676f7c6468 100644 --- a/runtime/vm/compiler/recognized_methods_list.h +++ b/runtime/vm/compiler/recognized_methods_list.h @@ -110,6 +110,28 @@ namespace dart { V(::, _sqrt, MathSqrt, 0x03183390) \ V(::, _exp, MathExp, 0x00f4ffd0) \ V(::, _log, MathLog, 0x09ae8462) \ + V(FinalizerBase, get:_allEntries, FinalizerBase_getAllEntries, 0xf03ff26b) \ + V(FinalizerBase, set:_allEntries, FinalizerBase_setAllEntries, 0x8f0920e8) \ + V(FinalizerBase, get:_detachments, FinalizerBase_getDetachments, 0x2f650f36) \ + V(FinalizerBase, set:_detachments, FinalizerBase_setDetachments, 0x788f1df3) \ + V(FinalizerBase, _exchangeEntriesCollectedWithNull, \ + FinalizerBase_exchangeEntriesCollectedWithNull, 0x6c9124fb) \ + V(FinalizerBase, _setIsolate, FinalizerBase_setIsolate, 0xbcf7db91) \ + V(FinalizerBase, get:_isolateFinalizers, FinalizerBase_getIsolateFinalizers, \ + 0x70f53b2b) \ + V(FinalizerBase, set:_isolateFinalizers, FinalizerBase_setIsolateFinalizers, \ + 0xb3e66928) \ + V(_FinalizerImpl, get:_callback, Finalizer_getCallback, 0x6f3d56bc) \ + V(_FinalizerImpl, set:_callback, Finalizer_setCallback, 0xc6aa96f9) \ + V(FinalizerEntry, get:value, FinalizerEntry_getValue, 0xf5c9b9d7) \ + V(FinalizerEntry, set:value, FinalizerEntry_setValue, 0x5501cc54) \ + V(FinalizerEntry, get:detach, FinalizerEntry_getDetach, 0x171cd968) \ + V(FinalizerEntry, set:detach, FinalizerEntry_setDetach, 0x7654ebe5) \ + V(FinalizerEntry, set:finalizer, FinalizerEntry_setFinalizer, 0x15cfefe9) \ + V(FinalizerEntry, get:token, FinalizerEntry_getToken, 0x04915a72) \ + V(FinalizerEntry, set:token, FinalizerEntry_setToken, 0x63c96cef) \ + V(FinalizerEntry, get:next, FinalizerEntry_getNext, 0x7102d7a4) \ + V(FinalizerEntry, set:next, FinalizerEntry_setNext, 0xd0b2ee61) \ V(Float32x4, _Float32x4FromDoubles, Float32x4FromDoubles, 0x1845792b) \ V(Float32x4, Float32x4.zero, Float32x4Zero, 0xd3b64002) \ V(Float32x4, _Float32x4Splat, Float32x4Splat, 0x13a552c3) \ diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc index 7d7866b5544..2973168647d 100644 --- a/runtime/vm/compiler/runtime_api.cc +++ b/runtime/vm/compiler/runtime_api.cc @@ -443,6 +443,10 @@ static uword GetInstanceSizeImpl(const dart::Class& handle) { return WeakProperty::InstanceSize(); case kWeakReferenceCid: return WeakReference::InstanceSize(); + case kFinalizerCid: + return Finalizer::InstanceSize(); + case kFinalizerEntryCid: + return FinalizerEntry::InstanceSize(); case kByteBufferCid: case kByteDataViewCid: case kPointerCid: diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h index 529583662ec..2b2a7d319fb 100644 --- a/runtime/vm/compiler/runtime_api.h +++ b/runtime/vm/compiler/runtime_api.h @@ -1015,6 +1015,34 @@ class WeakReference : public AllStatic { FINAL_CLASS(); }; +class FinalizerBase : public AllStatic { + public: + static word all_entries_offset(); + static word detachments_offset(); + static word entries_collected_offset(); + static word isolate_offset(); + FINAL_CLASS(); +}; + +class Finalizer : public AllStatic { + public: + static word type_arguments_offset(); + static word callback_offset(); + static word InstanceSize(); + FINAL_CLASS(); +}; + +class FinalizerEntry : public AllStatic { + public: + static word value_offset(); + static word detach_offset(); + static word token_offset(); + static word next_offset(); + static word finalizer_offset(); + static word InstanceSize(); + FINAL_CLASS(); +}; + class MirrorReference : public AllStatic { public: static word InstanceSize(); @@ -1212,6 +1240,7 @@ class Isolate : public AllStatic { static word current_tag_offset(); static word user_tag_offset(); static word ic_miss_code_offset(); + static word finalizers_offset(); #if !defined(PRODUCT) static word single_step_offset(); #endif // !defined(PRODUCT) diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h index 06ff2b0c450..e2c52c5fe8a 100644 --- a/runtime/vm/compiler/runtime_offsets_extracted.h +++ b/runtime/vm/compiler/runtime_offsets_extracted.h @@ -183,6 +183,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 28; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 24; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 28; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 40; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 32; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 20; @@ -190,7 +191,7 @@ static constexpr dart::compiler::target::word IsolateGroup_shared_class_table_offset = 8; static constexpr dart::compiler::target::word IsolateGroup_cached_class_table_table_offset = 16; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 40; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 44; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 20; static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 12; static constexpr dart::compiler::target::word @@ -219,12 +220,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 12; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 160; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116; + 164; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 180; + 184; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 104; + 108; static constexpr dart::compiler::target::word OneByteString_data_offset = 12; static constexpr dart::compiler::target::word PointerBase_data_offset = 4; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8; @@ -432,6 +433,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 16; static constexpr dart::compiler::target::word Type_type_class_id_offset = 20; static constexpr dart::compiler::target::word Type_type_state_offset = 22; static constexpr dart::compiler::target::word Type_nullability_offset = 23; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 24; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 20; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 12; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 8; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 16; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 16; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20; static constexpr dart::compiler::target::word FunctionType_hash_offset = 28; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 24; @@ -514,6 +531,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 28; static constexpr dart::compiler::target::word Field_InstanceSize = 60; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 88; @@ -750,6 +769,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 40; @@ -757,7 +777,7 @@ static constexpr dart::compiler::target::word IsolateGroup_shared_class_table_offset = 16; static constexpr dart::compiler::target::word IsolateGroup_cached_class_table_table_offset = 32; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 80; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 88; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40; static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 24; static constexpr dart::compiler::target::word @@ -786,12 +806,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 24; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 320; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232; + 328; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 360; + 368; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word OneByteString_data_offset = 16; static constexpr dart::compiler::target::word PointerBase_data_offset = 8; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = @@ -1005,6 +1025,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 32; static constexpr dart::compiler::target::word Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word Type_type_state_offset = 42; static constexpr dart::compiler::target::word Type_nullability_offset = 43; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 48; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 40; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 24; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 16; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 32; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40; static constexpr dart::compiler::target::word FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 48; @@ -1088,6 +1124,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word Field_InstanceSize = 96; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 128; @@ -1322,6 +1360,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 28; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 24; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 28; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 40; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 32; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 20; @@ -1329,7 +1368,7 @@ static constexpr dart::compiler::target::word IsolateGroup_shared_class_table_offset = 8; static constexpr dart::compiler::target::word IsolateGroup_cached_class_table_table_offset = 16; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 40; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 44; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 20; static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 12; static constexpr dart::compiler::target::word @@ -1358,12 +1397,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 12; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 160; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116; + 164; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 180; + 184; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 104; + 108; static constexpr dart::compiler::target::word OneByteString_data_offset = 12; static constexpr dart::compiler::target::word PointerBase_data_offset = 4; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8; @@ -1571,6 +1610,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 16; static constexpr dart::compiler::target::word Type_type_class_id_offset = 20; static constexpr dart::compiler::target::word Type_type_state_offset = 22; static constexpr dart::compiler::target::word Type_nullability_offset = 23; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 24; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 20; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 12; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 8; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 16; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 16; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20; static constexpr dart::compiler::target::word FunctionType_hash_offset = 28; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 24; @@ -1650,6 +1705,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 28; static constexpr dart::compiler::target::word Field_InstanceSize = 60; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 88; @@ -1886,6 +1943,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 40; @@ -1893,7 +1951,7 @@ static constexpr dart::compiler::target::word IsolateGroup_shared_class_table_offset = 16; static constexpr dart::compiler::target::word IsolateGroup_cached_class_table_table_offset = 32; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 80; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 88; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40; static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 24; static constexpr dart::compiler::target::word @@ -1922,12 +1980,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 24; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 320; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232; + 328; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 360; + 368; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word OneByteString_data_offset = 16; static constexpr dart::compiler::target::word PointerBase_data_offset = 8; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = @@ -2141,6 +2199,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 32; static constexpr dart::compiler::target::word Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word Type_type_state_offset = 42; static constexpr dart::compiler::target::word Type_nullability_offset = 43; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 48; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 40; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 24; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 16; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 32; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40; static constexpr dart::compiler::target::word FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 48; @@ -2225,6 +2299,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word Field_InstanceSize = 96; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 128; @@ -2459,6 +2535,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 40; @@ -2466,7 +2543,7 @@ static constexpr dart::compiler::target::word IsolateGroup_shared_class_table_offset = 16; static constexpr dart::compiler::target::word IsolateGroup_cached_class_table_table_offset = 32; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 80; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 88; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40; static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 16; static constexpr dart::compiler::target::word @@ -2495,12 +2572,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 24; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 320; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232; + 328; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 360; + 368; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word OneByteString_data_offset = 16; static constexpr dart::compiler::target::word PointerBase_data_offset = 8; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = @@ -2714,6 +2791,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 28; static constexpr dart::compiler::target::word Type_type_class_id_offset = 32; static constexpr dart::compiler::target::word Type_type_state_offset = 34; static constexpr dart::compiler::target::word Type_nullability_offset = 35; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 36; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 32; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 20; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 16; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 24; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 12; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 16; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 20; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 24; static constexpr dart::compiler::target::word FunctionType_hash_offset = 40; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 36; @@ -2797,6 +2890,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 32; static constexpr dart::compiler::target::word Field_InstanceSize = 64; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 40; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 32; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 96; @@ -3031,6 +3126,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 40; @@ -3038,7 +3134,7 @@ static constexpr dart::compiler::target::word IsolateGroup_shared_class_table_offset = 16; static constexpr dart::compiler::target::word IsolateGroup_cached_class_table_table_offset = 32; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 80; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 88; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40; static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 16; static constexpr dart::compiler::target::word @@ -3067,12 +3163,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 24; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 320; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232; + 328; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 360; + 368; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word OneByteString_data_offset = 16; static constexpr dart::compiler::target::word PointerBase_data_offset = 8; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = @@ -3286,6 +3382,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 28; static constexpr dart::compiler::target::word Type_type_class_id_offset = 32; static constexpr dart::compiler::target::word Type_type_state_offset = 34; static constexpr dart::compiler::target::word Type_nullability_offset = 35; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 36; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 32; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 20; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 16; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 24; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 12; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 16; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 20; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 24; static constexpr dart::compiler::target::word FunctionType_hash_offset = 40; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 36; @@ -3370,6 +3482,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 32; static constexpr dart::compiler::target::word Field_InstanceSize = 64; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 40; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 32; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 96; @@ -3604,6 +3718,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 28; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 24; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 28; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 40; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 32; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 20; @@ -3611,7 +3726,7 @@ static constexpr dart::compiler::target::word IsolateGroup_shared_class_table_offset = 8; static constexpr dart::compiler::target::word IsolateGroup_cached_class_table_table_offset = 16; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 40; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 44; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 20; static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 12; static constexpr dart::compiler::target::word @@ -3640,12 +3755,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 12; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 160; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116; + 164; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 180; + 184; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 104; + 108; static constexpr dart::compiler::target::word OneByteString_data_offset = 12; static constexpr dart::compiler::target::word PointerBase_data_offset = 4; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8; @@ -3853,6 +3968,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 16; static constexpr dart::compiler::target::word Type_type_class_id_offset = 20; static constexpr dart::compiler::target::word Type_type_state_offset = 22; static constexpr dart::compiler::target::word Type_nullability_offset = 23; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 24; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 20; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 12; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 8; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 16; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 16; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20; static constexpr dart::compiler::target::word FunctionType_hash_offset = 28; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 24; @@ -3937,6 +4068,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 28; static constexpr dart::compiler::target::word Field_InstanceSize = 60; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 88; @@ -4173,6 +4306,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 40; @@ -4180,7 +4314,7 @@ static constexpr dart::compiler::target::word IsolateGroup_shared_class_table_offset = 16; static constexpr dart::compiler::target::word IsolateGroup_cached_class_table_table_offset = 32; -static constexpr dart::compiler::target::word Isolate_single_step_offset = 80; +static constexpr dart::compiler::target::word Isolate_single_step_offset = 88; static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40; static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 24; static constexpr dart::compiler::target::word @@ -4209,12 +4343,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 24; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 320; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232; + 328; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 360; + 368; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word OneByteString_data_offset = 16; static constexpr dart::compiler::target::word PointerBase_data_offset = 8; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = @@ -4428,6 +4562,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 32; static constexpr dart::compiler::target::word Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word Type_type_state_offset = 42; static constexpr dart::compiler::target::word Type_nullability_offset = 43; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 48; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 40; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 24; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 16; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 32; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40; static constexpr dart::compiler::target::word FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 48; @@ -4512,6 +4662,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word Field_InstanceSize = 96; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 128; @@ -4743,6 +4895,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 28; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 36; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 20; @@ -4778,12 +4931,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 12; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 160; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116; + 164; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 180; + 184; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 104; + 108; static constexpr dart::compiler::target::word OneByteString_data_offset = 12; static constexpr dart::compiler::target::word PointerBase_data_offset = 4; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8; @@ -4991,6 +5144,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 16; static constexpr dart::compiler::target::word Type_type_class_id_offset = 20; static constexpr dart::compiler::target::word Type_type_state_offset = 22; static constexpr dart::compiler::target::word Type_nullability_offset = 23; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 24; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 20; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 12; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 8; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 16; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 16; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20; static constexpr dart::compiler::target::word FunctionType_hash_offset = 28; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 24; @@ -5073,6 +5242,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 28; static constexpr dart::compiler::target::word Field_InstanceSize = 60; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 88; @@ -5304,6 +5475,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 40; @@ -5339,12 +5511,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 24; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 320; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232; + 328; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 360; + 368; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word OneByteString_data_offset = 16; static constexpr dart::compiler::target::word PointerBase_data_offset = 8; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = @@ -5558,6 +5730,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 32; static constexpr dart::compiler::target::word Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word Type_type_state_offset = 42; static constexpr dart::compiler::target::word Type_nullability_offset = 43; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 48; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 40; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 24; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 16; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 32; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40; static constexpr dart::compiler::target::word FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 48; @@ -5641,6 +5829,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word Field_InstanceSize = 96; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 128; @@ -5870,6 +6060,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 28; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 36; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 20; @@ -5905,12 +6096,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 12; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 160; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116; + 164; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 180; + 184; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 104; + 108; static constexpr dart::compiler::target::word OneByteString_data_offset = 12; static constexpr dart::compiler::target::word PointerBase_data_offset = 4; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8; @@ -6118,6 +6309,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 16; static constexpr dart::compiler::target::word Type_type_class_id_offset = 20; static constexpr dart::compiler::target::word Type_type_state_offset = 22; static constexpr dart::compiler::target::word Type_nullability_offset = 23; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 24; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 20; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 12; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 8; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 16; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 16; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20; static constexpr dart::compiler::target::word FunctionType_hash_offset = 28; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 24; @@ -6197,6 +6404,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 28; static constexpr dart::compiler::target::word Field_InstanceSize = 60; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 88; @@ -6428,6 +6637,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 40; @@ -6463,12 +6673,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 24; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 320; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232; + 328; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 360; + 368; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word OneByteString_data_offset = 16; static constexpr dart::compiler::target::word PointerBase_data_offset = 8; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = @@ -6682,6 +6892,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 32; static constexpr dart::compiler::target::word Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word Type_type_state_offset = 42; static constexpr dart::compiler::target::word Type_nullability_offset = 43; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 48; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 40; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 24; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 16; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 32; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40; static constexpr dart::compiler::target::word FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 48; @@ -6766,6 +6992,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word Field_InstanceSize = 96; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 128; @@ -6995,6 +7223,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 40; @@ -7030,12 +7259,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 24; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 320; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232; + 328; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 360; + 368; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word OneByteString_data_offset = 16; static constexpr dart::compiler::target::word PointerBase_data_offset = 8; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = @@ -7249,6 +7478,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 28; static constexpr dart::compiler::target::word Type_type_class_id_offset = 32; static constexpr dart::compiler::target::word Type_type_state_offset = 34; static constexpr dart::compiler::target::word Type_nullability_offset = 35; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 36; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 32; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 20; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 16; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 24; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 12; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 16; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 20; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 24; static constexpr dart::compiler::target::word FunctionType_hash_offset = 40; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 36; @@ -7332,6 +7577,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 32; static constexpr dart::compiler::target::word Field_InstanceSize = 64; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 40; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 32; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 96; @@ -7561,6 +7808,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 40; @@ -7596,12 +7844,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 24; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 320; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232; + 328; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 360; + 368; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word OneByteString_data_offset = 16; static constexpr dart::compiler::target::word PointerBase_data_offset = 8; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = @@ -7815,6 +8063,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 28; static constexpr dart::compiler::target::word Type_type_class_id_offset = 32; static constexpr dart::compiler::target::word Type_type_state_offset = 34; static constexpr dart::compiler::target::word Type_nullability_offset = 35; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 36; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 32; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 20; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 16; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 24; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 12; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 16; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 20; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 24; static constexpr dart::compiler::target::word FunctionType_hash_offset = 40; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 36; @@ -7899,6 +8163,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 32; static constexpr dart::compiler::target::word Field_InstanceSize = 64; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 40; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 32; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 96; @@ -8128,6 +8394,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 28; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 36; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 20; @@ -8163,12 +8430,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 12; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 160; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116; + 164; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 180; + 184; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 104; + 108; static constexpr dart::compiler::target::word OneByteString_data_offset = 12; static constexpr dart::compiler::target::word PointerBase_data_offset = 4; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8; @@ -8376,6 +8643,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 16; static constexpr dart::compiler::target::word Type_type_class_id_offset = 20; static constexpr dart::compiler::target::word Type_type_state_offset = 22; static constexpr dart::compiler::target::word Type_nullability_offset = 23; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 24; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 20; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 12; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 8; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 16; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 16; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20; static constexpr dart::compiler::target::word FunctionType_hash_offset = 28; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 24; @@ -8460,6 +8743,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 28; static constexpr dart::compiler::target::word Field_InstanceSize = 60; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 88; @@ -8691,6 +8976,7 @@ static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48; +static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72; static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word IsolateGroup_object_store_offset = 40; @@ -8726,12 +9012,12 @@ static constexpr dart::compiler::target::word NativeArguments_retval_offset = 24; static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word ObjectStore_double_type_offset = - 320; -static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232; + 328; +static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240; static constexpr dart::compiler::target::word ObjectStore_string_type_offset = - 360; + 368; static constexpr dart::compiler::target::word ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word OneByteString_data_offset = 16; static constexpr dart::compiler::target::word PointerBase_data_offset = 8; static constexpr dart::compiler::target::word Pointer_type_arguments_offset = @@ -8945,6 +9231,22 @@ static constexpr dart::compiler::target::word Type_hash_offset = 32; static constexpr dart::compiler::target::word Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word Type_type_state_offset = 42; static constexpr dart::compiler::target::word Type_nullability_offset = 43; +static constexpr dart::compiler::target::word Finalizer_type_arguments_offset = + 48; +static constexpr dart::compiler::target::word Finalizer_callback_offset = 40; +static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset = + 24; +static constexpr dart::compiler::target::word FinalizerBase_detachments_offset = + 16; +static constexpr dart::compiler::target::word + FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8; +static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16; +static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24; +static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset = + 32; +static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40; static constexpr dart::compiler::target::word FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word FunctionType_named_parameter_names_offset = 48; @@ -9029,6 +9331,8 @@ static constexpr dart::compiler::target::word ExternalTypedData_InstanceSize = static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word Field_InstanceSize = 96; +static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56; static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word Function_InstanceSize = 128; @@ -9281,6 +9585,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 24; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 28; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 40; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 32; static constexpr dart::compiler::target::word @@ -9290,7 +9596,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_IsolateGroup_cached_class_table_table_offset = 16; static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset = - 40; + 44; static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 20; static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset = 12; @@ -9325,13 +9631,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 160; + AOT_ObjectStore_double_type_offset = 164; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 116; + 120; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 180; + AOT_ObjectStore_string_type_offset = 184; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 104; + 108; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 12; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 4; @@ -9558,6 +9864,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 20; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 22; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 23; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 24; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 20; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 12; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 8; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 16; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 4; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 4; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 12; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 16; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 20; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 24; @@ -9652,6 +9980,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 28; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 28; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 28; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44; @@ -9914,6 +10245,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 48; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 56; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 80; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 64; static constexpr dart::compiler::target::word @@ -9923,7 +10256,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_IsolateGroup_cached_class_table_table_offset = 32; static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset = - 80; + 88; static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40; static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset = 24; @@ -9958,13 +10291,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 320; + AOT_ObjectStore_double_type_offset = 328; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 232; + 240; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 360; + AOT_ObjectStore_string_type_offset = 368; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 16; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8; @@ -10192,6 +10525,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 48; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 40; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 24; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 16; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 16; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 24; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 40; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 48; @@ -10288,6 +10643,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 56; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80; @@ -10553,6 +10911,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 48; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 56; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 80; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 64; static constexpr dart::compiler::target::word @@ -10562,7 +10922,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_IsolateGroup_cached_class_table_table_offset = 32; static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset = - 80; + 88; static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40; static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset = 24; @@ -10597,13 +10957,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 320; + AOT_ObjectStore_double_type_offset = 328; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 232; + 240; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 360; + AOT_ObjectStore_string_type_offset = 368; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 16; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8; @@ -10831,6 +11191,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 48; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 40; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 24; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 16; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 16; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 24; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 40; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 48; @@ -10928,6 +11310,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 56; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80; @@ -11189,6 +11574,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 48; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 56; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 80; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 64; static constexpr dart::compiler::target::word @@ -11198,7 +11585,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_IsolateGroup_cached_class_table_table_offset = 32; static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset = - 80; + 88; static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40; static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset = 16; @@ -11233,13 +11620,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 320; + AOT_ObjectStore_double_type_offset = 328; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 232; + 240; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 360; + AOT_ObjectStore_string_type_offset = 368; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 16; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8; @@ -11467,6 +11854,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 32; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 34; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 35; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 36; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 32; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 20; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 16; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 24; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 12; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 16; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 20; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 24; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 40; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 36; @@ -11563,6 +11972,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 40; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 32; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56; @@ -11824,6 +12236,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 48; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 56; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 80; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 64; static constexpr dart::compiler::target::word @@ -11833,7 +12247,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_IsolateGroup_cached_class_table_table_offset = 32; static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset = - 80; + 88; static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40; static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset = 16; @@ -11868,13 +12282,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 320; + AOT_ObjectStore_double_type_offset = 328; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 232; + 240; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 360; + AOT_ObjectStore_string_type_offset = 368; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 16; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8; @@ -12102,6 +12516,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 32; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 34; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 35; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 36; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 32; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 20; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 16; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 24; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 12; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 16; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 20; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 24; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 40; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 36; @@ -12199,6 +12635,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 40; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 32; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56; @@ -12460,6 +12899,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 24; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 28; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 40; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 32; static constexpr dart::compiler::target::word @@ -12469,7 +12910,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_IsolateGroup_cached_class_table_table_offset = 16; static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset = - 40; + 44; static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 20; static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset = 12; @@ -12504,13 +12945,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 160; + AOT_ObjectStore_double_type_offset = 164; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 116; + 120; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 180; + AOT_ObjectStore_string_type_offset = 184; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 104; + 108; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 12; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 4; @@ -12737,6 +13178,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 20; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 22; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 23; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 24; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 20; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 12; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 8; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 16; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 4; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 4; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 12; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 16; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 20; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 24; @@ -12833,6 +13296,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 28; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 28; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 28; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44; @@ -13095,6 +13561,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 48; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 56; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 80; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 64; static constexpr dart::compiler::target::word @@ -13104,7 +13572,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_IsolateGroup_cached_class_table_table_offset = 32; static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset = - 80; + 88; static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40; static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset = 24; @@ -13139,13 +13607,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 320; + AOT_ObjectStore_double_type_offset = 328; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 232; + 240; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 360; + AOT_ObjectStore_string_type_offset = 368; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 16; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8; @@ -13373,6 +13841,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 48; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 40; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 24; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 16; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 16; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 24; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 40; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 48; @@ -13470,6 +13960,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 56; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80; @@ -13728,6 +14221,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 20; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 24; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 36; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 28; static constexpr dart::compiler::target::word @@ -13770,13 +14265,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 160; + AOT_ObjectStore_double_type_offset = 164; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 116; + 120; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 180; + AOT_ObjectStore_string_type_offset = 184; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 104; + 108; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 12; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 4; @@ -14003,6 +14498,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 20; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 22; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 23; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 24; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 20; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 12; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 8; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 16; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 4; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 4; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 12; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 16; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 20; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 24; @@ -14097,6 +14614,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 28; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 28; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 28; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44; @@ -14354,6 +14874,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 48; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 72; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word @@ -14396,13 +14918,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 320; + AOT_ObjectStore_double_type_offset = 328; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 232; + 240; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 360; + AOT_ObjectStore_string_type_offset = 368; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 16; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8; @@ -14630,6 +15152,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 48; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 40; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 24; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 16; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 16; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 24; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 40; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 48; @@ -14726,6 +15270,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 56; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80; @@ -14986,6 +15533,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 48; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 72; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word @@ -15028,13 +15577,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 320; + AOT_ObjectStore_double_type_offset = 328; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 232; + 240; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 360; + AOT_ObjectStore_string_type_offset = 368; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 16; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8; @@ -15262,6 +15811,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 48; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 40; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 24; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 16; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 16; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 24; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 40; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 48; @@ -15359,6 +15930,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 56; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80; @@ -15615,6 +16189,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 48; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 72; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word @@ -15657,13 +16233,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 320; + AOT_ObjectStore_double_type_offset = 328; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 232; + 240; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 360; + AOT_ObjectStore_string_type_offset = 368; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 16; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8; @@ -15891,6 +16467,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 32; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 34; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 35; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 36; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 32; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 20; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 16; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 24; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 12; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 16; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 20; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 24; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 40; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 36; @@ -15987,6 +16585,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 40; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 32; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56; @@ -16243,6 +16844,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 48; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 72; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word @@ -16285,13 +16888,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 320; + AOT_ObjectStore_double_type_offset = 328; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 232; + 240; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 360; + AOT_ObjectStore_string_type_offset = 368; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 16; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8; @@ -16519,6 +17122,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 32; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 34; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 35; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 36; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 32; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 20; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 16; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 24; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 12; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 16; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 20; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 24; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 40; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 36; @@ -16616,6 +17241,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 40; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 32; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56; @@ -16872,6 +17500,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 20; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 24; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 36; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 28; static constexpr dart::compiler::target::word @@ -16914,13 +17544,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 160; + AOT_ObjectStore_double_type_offset = 164; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 116; + 120; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 180; + AOT_ObjectStore_string_type_offset = 184; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 104; + 108; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 12; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 4; @@ -17147,6 +17777,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 20; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 22; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 23; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 24; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 20; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 12; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 8; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 16; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 4; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 4; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 12; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 16; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 20; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 24; @@ -17243,6 +17895,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 28; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 28; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 28; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44; @@ -17500,6 +18155,8 @@ static constexpr dart::compiler::target::word AOT_Isolate_current_tag_offset = 40; static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset = 48; +static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset = + 72; static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset = 56; static constexpr dart::compiler::target::word @@ -17542,13 +18199,13 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_NativeArguments_thread_offset = 0; static constexpr dart::compiler::target::word - AOT_ObjectStore_double_type_offset = 320; + AOT_ObjectStore_double_type_offset = 328; static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset = - 232; + 240; static constexpr dart::compiler::target::word - AOT_ObjectStore_string_type_offset = 360; + AOT_ObjectStore_string_type_offset = 368; static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset = - 208; + 216; static constexpr dart::compiler::target::word AOT_OneByteString_data_offset = 16; static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8; @@ -17776,6 +18433,28 @@ static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset = 40; static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42; static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43; +static constexpr dart::compiler::target::word + AOT_Finalizer_type_arguments_offset = 48; +static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset = + 40; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_all_entries_offset = 24; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_detachments_offset = 16; +static constexpr dart::compiler::target::word + AOT_FinalizerBase_entries_collected_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset = + 8; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset = + 16; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset = + 24; +static constexpr dart::compiler::target::word + AOT_FinalizerEntry_finalizer_offset = 32; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset = + 40; static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56; static constexpr dart::compiler::target::word AOT_FunctionType_named_parameter_names_offset = 48; @@ -17873,6 +18552,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_FfiTrampolineData_InstanceSize = 48; static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80; +static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56; +static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize = + 56; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80; diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h index 09f12cf6648..a2da8368fa5 100644 --- a/runtime/vm/compiler/runtime_offsets_list.h +++ b/runtime/vm/compiler/runtime_offsets_list.h @@ -149,6 +149,7 @@ FIELD(Int32x4, value_offset) \ FIELD(Isolate, current_tag_offset) \ FIELD(Isolate, default_tag_offset) \ + FIELD(Isolate, finalizers_offset) \ FIELD(Isolate, ic_miss_code_offset) \ FIELD(IsolateGroup, object_store_offset) \ FIELD(IsolateGroup, shared_class_table_offset) \ @@ -298,6 +299,17 @@ FIELD(Type, type_class_id_offset) \ FIELD(Type, type_state_offset) \ FIELD(Type, nullability_offset) \ + FIELD(Finalizer, type_arguments_offset) \ + FIELD(Finalizer, callback_offset) \ + FIELD(FinalizerBase, all_entries_offset) \ + FIELD(FinalizerBase, detachments_offset) \ + FIELD(FinalizerBase, entries_collected_offset) \ + FIELD(FinalizerBase, isolate_offset) \ + FIELD(FinalizerEntry, value_offset) \ + FIELD(FinalizerEntry, detach_offset) \ + FIELD(FinalizerEntry, token_offset) \ + FIELD(FinalizerEntry, finalizer_offset) \ + FIELD(FinalizerEntry, next_offset) \ FIELD(FunctionType, hash_offset) \ FIELD(FunctionType, named_parameter_names_offset) \ FIELD(FunctionType, nullability_offset) \ @@ -360,6 +372,8 @@ SIZEOF(ExternalTypedData, InstanceSize, UntaggedExternalTypedData) \ SIZEOF(FfiTrampolineData, InstanceSize, UntaggedFfiTrampolineData) \ SIZEOF(Field, InstanceSize, UntaggedField) \ + SIZEOF(Finalizer, InstanceSize, UntaggedFinalizer) \ + SIZEOF(FinalizerEntry, InstanceSize, UntaggedFinalizerEntry) \ SIZEOF(Float32x4, InstanceSize, UntaggedFloat32x4) \ SIZEOF(Float64x2, InstanceSize, UntaggedFloat64x2) \ SIZEOF(Function, InstanceSize, UntaggedFunction) \ diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc index b2fd4b316e8..9042281fc2a 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -370,6 +370,7 @@ char* Dart::DartInit(const Dart_InitializeParams* params) { Object::InitNullAndBool(vm_isolate_->group()); vm_isolate_->isolate_group_->set_object_store(new ObjectStore()); vm_isolate_->isolate_object_store()->Init(); + vm_isolate_->finalizers_ = GrowableObjectArray::null(); Object::Init(vm_isolate_->group()); OffsetsTable::Init(); ArgumentsDescriptor::Init(); diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc index 46df59fa622..501568e0661 100644 --- a/runtime/vm/dart_entry.cc +++ b/runtime/vm/dart_entry.cc @@ -677,18 +677,14 @@ ObjectPtr DartLibraryCalls::Equals(const Instance& left, } ObjectPtr DartLibraryCalls::LookupHandler(Dart_Port port_id) { - Thread* thread = Thread::Current(); - Zone* zone = thread->zone(); + Thread* const thread = Thread::Current(); + Zone* const zone = thread->zone(); const auto& function = Function::Handle( zone, thread->isolate_group()->object_store()->lookup_port_handler()); - const int kNumArguments = 1; ASSERT(!function.IsNull()); Array& args = Array::Handle( zone, thread->isolate()->isolate_object_store()->dart_args_1()); - if (args.IsNull()) { - args = Array::New(kNumArguments); - thread->isolate()->isolate_object_store()->set_dart_args_1(args); - } + ASSERT(!args.IsNull()); args.SetAt(0, Integer::Handle(zone, Integer::New(port_id))); const Object& result = Object::Handle(zone, DartEntry::InvokeFunction(function, args)); @@ -706,24 +702,7 @@ ObjectPtr DartLibraryCalls::LookupOpenPorts() { return result.ptr(); } -ObjectPtr DartLibraryCalls::HandleMessage(Dart_Port port_id, - const Instance& message) { - auto thread = Thread::Current(); - auto zone = thread->zone(); - auto isolate = thread->isolate(); - auto object_store = thread->isolate_group()->object_store(); - const auto& function = - Function::Handle(zone, object_store->handle_message_function()); - const int kNumArguments = 2; - ASSERT(!function.IsNull()); - Array& args = - Array::Handle(zone, isolate->isolate_object_store()->dart_args_2()); - if (args.IsNull()) { - args = Array::New(kNumArguments); - isolate->isolate_object_store()->set_dart_args_2(args); - } - args.SetAt(0, Integer::Handle(zone, Integer::New(port_id))); - args.SetAt(1, message); +static void DebuggerSetResumeIfStepping(Isolate* isolate) { #if !defined(PRODUCT) if (isolate->debugger()->IsStepping()) { // If the isolate is being debugged and the debugger was stepping @@ -732,6 +711,47 @@ ObjectPtr DartLibraryCalls::HandleMessage(Dart_Port port_id, isolate->debugger()->SetResumeAction(Debugger::kStepInto); } #endif +} + +ObjectPtr DartLibraryCalls::HandleMessage(Dart_Port port_id, + const Instance& message) { + auto* const thread = Thread::Current(); + auto* const zone = thread->zone(); + auto* const isolate = thread->isolate(); + auto* const object_store = thread->isolate_group()->object_store(); + const auto& function = + Function::Handle(zone, object_store->handle_message_function()); + ASSERT(!function.IsNull()); + Array& args = + Array::Handle(zone, isolate->isolate_object_store()->dart_args_2()); + ASSERT(!args.IsNull()); + args.SetAt(0, Integer::Handle(zone, Integer::New(port_id))); + args.SetAt(1, message); + DebuggerSetResumeIfStepping(isolate); + const Object& handler = + Object::Handle(zone, DartEntry::InvokeFunction(function, args)); + return handler.ptr(); +} + +ObjectPtr DartLibraryCalls::HandleFinalizerMessage( + const FinalizerBase& finalizer) { + if (FLAG_trace_finalizers) { + THR_Print("Running finalizer %p callback on isolate %p\n", + finalizer.ptr()->untag(), finalizer.isolate()); + } + + auto* const thread = Thread::Current(); + auto* const zone = thread->zone(); + auto* const isolate = thread->isolate(); + auto* const object_store = thread->isolate_group()->object_store(); + const auto& function = + Function::Handle(zone, object_store->handle_finalizer_message_function()); + ASSERT(!function.IsNull()); + Array& args = + Array::Handle(zone, isolate->isolate_object_store()->dart_args_1()); + ASSERT(!args.IsNull()); + args.SetAt(0, finalizer); + DebuggerSetResumeIfStepping(isolate); const Object& handler = Object::Handle(zone, DartEntry::InvokeFunction(function, args)); return handler.ptr(); diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h index 4f650a87eed..c5cc2be5bb7 100644 --- a/runtime/vm/dart_entry.h +++ b/runtime/vm/dart_entry.h @@ -36,8 +36,8 @@ class ArgumentsDescriptor : public ValueObject { intptr_t TypeArgsLen() const; // 0 if no type argument vector is passed. intptr_t FirstArgIndex() const { return TypeArgsLen() > 0 ? 1 : 0; } intptr_t CountWithTypeArgs() const { return FirstArgIndex() + Count(); } - intptr_t Count() const; // Excluding type arguments vector. - intptr_t Size() const; // Excluding type arguments vector. + intptr_t Count() const; // Excluding type arguments vector. + intptr_t Size() const; // Excluding type arguments vector. intptr_t SizeWithTypeArgs() const { return FirstArgIndex() + Size(); } intptr_t PositionalCount() const; // Excluding type arguments vector. intptr_t NamedCount() const { return Count() - PositionalCount(); } @@ -292,10 +292,12 @@ class DartLibraryCalls : public AllStatic { // handler for this port id. static ObjectPtr HandleMessage(Dart_Port port_id, const Instance& message); + // Invokes the finalizer to run its callbacks. + static ObjectPtr HandleFinalizerMessage(const FinalizerBase& finalizer); + // Returns a list of open ReceivePorts. static ObjectPtr LookupOpenPorts(); - // Returns null on success, an ErrorPtr on failure. static ObjectPtr DrainMicrotaskQueue(); diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h index 1e77f74952a..68b49e4320a 100644 --- a/runtime/vm/flag_list.h +++ b/runtime/vm/flag_list.h @@ -202,6 +202,7 @@ constexpr bool FLAG_support_il_printer = false; "Generate code for a generic CPU, unknown at compile time") \ D(trace_cha, bool, false, "Trace CHA operations") \ R(trace_field_guards, false, bool, false, "Trace changes in field's cids.") \ + D(trace_finalizers, bool, false, "Traces finalizers.") \ D(trace_ic, bool, false, "Trace IC handling") \ D(trace_ic_miss_in_optimized, bool, false, \ "Trace IC miss in optimized code") \ diff --git a/runtime/vm/heap/gc_shared.h b/runtime/vm/heap/gc_shared.h index 1d2bf6473d7..7e0cb2dd9c8 100644 --- a/runtime/vm/heap/gc_shared.h +++ b/runtime/vm/heap/gc_shared.h @@ -30,7 +30,8 @@ namespace dart { // - variable name #define GC_LINKED_LIST(V) \ V(WeakProperty, weak_properties) \ - V(WeakReference, weak_references) + V(WeakReference, weak_references) \ + V(FinalizerEntry, finalizer_entries) template class GCLinkedList { @@ -81,6 +82,115 @@ struct GCLinkedLists { #undef FOREACH }; +#ifdef DEBUG +#define TRACE_FINALIZER(format, ...) \ + if (FLAG_trace_finalizers) { \ + THR_Print("%s %p " format "\n", GCVisitorType::kName, visitor, \ + __VA_ARGS__); \ + } +#else +#define TRACE_FINALIZER(format, ...) +#endif + +// This function processes all finalizer entries discovered by a scavenger or +// marker. If an entry is referencing an object that is going to die, such entry +// is cleared and enqueued in the respective finalizer. +// +// Finalizer entries belonging to unreachable finalizer entries do not get +// processed, so the callback will not be called for these finalizers. +// +// For more documentation see runtime/docs/gc.md. +// +// |GCVisitorType| is a concrete type implementing either marker or scavenger. +// It is expected to provide |SetNullIfCollected| method for clearing fields +// referring to dead objects and |kName| field which contains visitor name for +// tracing output. +template +void MournFinalized(GCVisitorType* visitor) { + FinalizerEntryPtr current_entry = + visitor->delayed_.finalizer_entries.Release(); + while (current_entry != FinalizerEntry::null()) { + TRACE_FINALIZER("Processing Entry %p", current_entry->untag()); + FinalizerEntryPtr next_entry = + current_entry->untag()->next_seen_by_gc_.Decompress( + current_entry->heap_base()); + current_entry->untag()->next_seen_by_gc_ = FinalizerEntry::null(); + + uword heap_base = current_entry->heap_base(); + const bool value_collected_this_gc = GCVisitorType::SetNullIfCollected( + heap_base, ¤t_entry->untag()->value_); + GCVisitorType::SetNullIfCollected(heap_base, + ¤t_entry->untag()->detach_); + GCVisitorType::SetNullIfCollected(heap_base, + ¤t_entry->untag()->finalizer_); + + ObjectPtr token_object = current_entry->untag()->token(); + // See sdk/lib/_internal/vm/lib/internal_patch.dart FinalizerBase.detach. + const bool is_detached = token_object == current_entry; + + if (value_collected_this_gc && !is_detached) { + FinalizerBasePtr finalizer = current_entry->untag()->finalizer(); + + if (finalizer.IsRawNull()) { + TRACE_FINALIZER("Value collected entry %p finalizer null", + current_entry->untag()); + + // Do nothing, the finalizer has been GCed. + } else if (finalizer.IsFinalizer()) { + TRACE_FINALIZER("Value collected entry %p finalizer %p", + current_entry->untag(), finalizer->untag()); + + FinalizerPtr finalizer_dart = static_cast(finalizer); + // Move entry to entries collected and current head of that list as + // the next element. Using a atomic exchange satisfies concurrency + // between the parallel GC tasks. + // We rely on the fact that the mutator thread is not running to avoid + // races between GC and mutator modifying Finalizer.entries_collected. + // + // We only run in serial marker or in the finalize step in the marker, + // both are in safepoint. + // The main scavenger worker is at safepoint, the other scavenger + // workers are are not, but they bypass safepoint because the main + // worker is at a safepoint already. + ASSERT(Thread::Current()->IsAtSafepoint() || + Thread::Current()->BypassSafepoints()); + + FinalizerEntryPtr previous_head = + finalizer_dart->untag()->exchange_entries_collected(current_entry); + current_entry->untag()->set_next(previous_head); + const bool first_entry = previous_head.IsRawNull(); + // Schedule calling Dart finalizer. + if (first_entry) { + Isolate* isolate = finalizer->untag()->isolate_; + if (isolate == nullptr) { + TRACE_FINALIZER( + "Not scheduling finalizer %p callback on isolate null", + finalizer->untag()); + } else { + TRACE_FINALIZER("Scheduling finalizer %p callback on isolate %p", + finalizer->untag(), isolate); + + PersistentHandle* handle = + isolate->group()->api_state()->AllocatePersistentHandle(); + handle->set_ptr(finalizer); + MessageHandler* message_handler = isolate->message_handler(); + message_handler->PostMessage( + Message::New(handle, Message::kNormalPriority), + /*before_events*/ false); + } + } + } else { + // TODO(http://dartbug.com/47777): Implement NativeFinalizer. + UNREACHABLE(); + } + } + + current_entry = next_entry; + } +} + +#undef TRACE_FINALIZER + } // namespace dart #endif // RUNTIME_VM_HEAP_GC_SHARED_H_ diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc index a797c39c490..63a150b7f6c 100644 --- a/runtime/vm/heap/marker.cc +++ b/runtime/vm/heap/marker.cc @@ -47,6 +47,10 @@ class MarkingVisitorBase : public ObjectPointerVisitor { int64_t marked_micros() const { return marked_micros_; } void AddMicros(int64_t micros) { marked_micros_ += micros; } +#ifdef DEBUG + constexpr static const char* const kName = "Marker"; +#endif + static bool IsMarked(ObjectPtr raw) { ASSERT(raw->IsHeapObject()); ASSERT(raw->IsOldObject()); @@ -126,6 +130,9 @@ class MarkingVisitorBase : public ObjectPointerVisitor { } else if (class_id == kWeakReferenceCid) { WeakReferencePtr raw_weak = static_cast(raw_obj); size = ProcessWeakReference(raw_weak); + } else if (class_id == kFinalizerEntryCid) { + FinalizerEntryPtr raw_weak = static_cast(raw_obj); + size = ProcessFinalizerEntry(raw_weak); } else { size = raw_obj->untag()->VisitPointersNonvirtual(this); } @@ -220,6 +227,17 @@ class MarkingVisitorBase : public ObjectPointerVisitor { return raw_weak->untag()->HeapSize(); } + intptr_t ProcessFinalizerEntry(FinalizerEntryPtr raw_entry) { + ASSERT(IsMarked(raw_entry)); + delayed_.finalizer_entries.Enqueue(raw_entry); + // Only visit token and next. + MarkObject(LoadCompressedPointerIgnoreRace(&raw_entry->untag()->token_) + .Decompress(raw_entry->heap_base())); + MarkObject(LoadCompressedPointerIgnoreRace(&raw_entry->untag()->next_) + .Decompress(raw_entry->heap_base())); + return raw_entry->untag()->HeapSize(); + } + void ProcessDeferredMarking() { ObjectPtr raw_obj; while ((raw_obj = deferred_work_list_.Pop()) != nullptr) { @@ -254,6 +272,7 @@ class MarkingVisitorBase : public ObjectPointerVisitor { void FinalizeMarking() { work_list_.Finalize(); deferred_work_list_.Finalize(); + MournFinalized(this); } void MournWeakProperties() { @@ -394,6 +413,9 @@ class MarkingVisitorBase : public ObjectPointerVisitor { uintptr_t marked_bytes_; int64_t marked_micros_; + template + friend void MournFinalized(GCVisitorType* visitor); + DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitorBase); }; @@ -703,6 +725,8 @@ class ParallelMarkTask : public ThreadPool::Task { // Phase 3: Weak processing and statistics. visitor_->MournWeakProperties(); visitor_->MournWeakReferences(); + // Don't MournFinalized here, do it on main thread, so that we don't have + // to coordinate workers. marker_->IterateWeakRoots(thread); int64_t stop = OS::GetCurrentMonotonicMicros(); @@ -942,6 +966,7 @@ void GCMarker::MarkObjects(PageSpace* page_space) { visitor.FinalizeMarking(); visitor.MournWeakProperties(); visitor.MournWeakReferences(); + MournFinalized(&visitor); IterateWeakRoots(thread); // All marking done; detach code, etc. int64_t stop = OS::GetCurrentMonotonicMicros(); diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc index 75b2519dd16..194529657e9 100644 --- a/runtime/vm/heap/scavenger.cc +++ b/runtime/vm/heap/scavenger.cc @@ -138,6 +138,10 @@ class ScavengerVisitorBase : public ObjectPointerVisitor { promoted_list_(promotion_stack) {} ~ScavengerVisitorBase() { ASSERT(delayed_.IsEmpty()); } +#ifdef DEBUG + constexpr static const char* const kName = "Scavenger"; +#endif + virtual void VisitTypedDataViewPointers(TypedDataViewPtr view, CompressedObjectPtr* first, CompressedObjectPtr* last) { @@ -298,6 +302,7 @@ class ScavengerVisitorBase : public ObjectPointerVisitor { MournWeakProperties(); MournOrUpdateWeakReferences(); + MournFinalized(this); } page_space_->ReleaseLock(freelist_); thread_ = nullptr; @@ -536,6 +541,9 @@ class ScavengerVisitorBase : public ObjectPointerVisitor { NewPage* tail_ = nullptr; // Allocating from here. NewPage* scan_ = nullptr; // Resolving from here. + template + friend void MournFinalized(GCVisitorType* visitor); + DISALLOW_COPY_AND_ASSIGN(ScavengerVisitorBase); }; @@ -1418,6 +1426,21 @@ intptr_t ScavengerVisitorBase::ProcessCopied(ObjectPtr raw_obj) { return raw_weak->untag()->HeapSize(); } } + } else if (UNLIKELY(class_id == kFinalizerEntryCid)) { + FinalizerEntryPtr raw_entry = static_cast(raw_obj); + ASSERT(IsNotForwarding(raw_entry)); + delayed_.finalizer_entries.Enqueue(raw_entry); + // Only visit token and next. +#if !defined(DART_COMPRESSED_POINTERS) + ScavengePointer(&raw_entry->untag()->token_); + ScavengePointer(&raw_entry->untag()->next_); +#else + ScavengeCompressedPointer(raw_entry->heap_base(), + &raw_entry->untag()->token_); + ScavengeCompressedPointer(raw_entry->heap_base(), + &raw_entry->untag()->next_); +#endif + return raw_entry->untag()->HeapSize(); } return raw_obj->untag()->VisitPointersNonvirtual(this); } diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc index 59450e8b9c0..287aa91e86e 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc @@ -1388,6 +1388,15 @@ MessageHandler::MessageStatus IsolateMessageHandler::HandleMessage( } } } + } else if (message->IsFinalizerInvocationRequest()) { + const Object& msg_handler = Object::Handle( + zone, + DartLibraryCalls::HandleFinalizerMessage(FinalizerBase::Cast(msg))); + if (msg_handler.IsError()) { + status = ProcessUnhandledException(Error::Cast(msg_handler)); + } else { + // The handler closure which was used to successfully handle the message. + } } else if (message->dest_port() == Message::kIllegalPort) { // Check whether this is a delayed OOB message which needed handling as // part of the regular message dispatch. All other messages are dropped on @@ -1686,6 +1695,7 @@ Isolate::Isolate(IsolateGroup* isolate_group, default_tag_(UserTag::null()), ic_miss_code_(Code::null()), field_table_(new FieldTable(/*isolate=*/this)), + finalizers_(GrowableObjectArray::null()), isolate_group_(isolate_group), isolate_object_store_(new IsolateObjectStore()), #if !defined(DART_PRECOMPILED_RUNTIME) @@ -2465,6 +2475,34 @@ void Isolate::LowLevelShutdown() { } } + // Set live finalizers isolate to null, before deleting the message handler. + // TODO(http://dartbug.com/47777): How to detect if the isolate field was ever + // initialized beyond RAW_NULL? + const auto& finalizers = + GrowableObjectArray::Handle(stack_zone.GetZone(), finalizers_); + if (!finalizers.IsNull()) { + const intptr_t num_finalizers = finalizers.Length(); + auto& weak_reference = WeakReference::Handle(stack_zone.GetZone()); + auto& finalizer = FinalizerBase::Handle(stack_zone.GetZone()); + for (int i = 0; i < num_finalizers; i++) { + weak_reference ^= finalizers.At(i); + finalizer ^= weak_reference.target(); + if (!finalizer.IsNull()) { + if (finalizer.isolate() == this) { + if (FLAG_trace_finalizers) { + THR_Print("Isolate %p Setting finalizer %p isolate to null\n", this, + finalizer.ptr()->untag()); + } + // Finalizer was not sent to another isolate with send and exit. + finalizer.set_isolate(nullptr); + } else { + // TODO(http://dartbug.com/47777): Send and exit support. + UNREACHABLE(); + } + } + } + } + // Close all the ports owned by this isolate. PortMap::ClosePorts(message_handler()); @@ -2571,7 +2609,6 @@ void Isolate::Shutdown() { "--check-reloaded is enabled.\n"); } } - #endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) // Then, proceed with low-level teardown. @@ -2721,6 +2758,7 @@ void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor, visitor->VisitPointer(reinterpret_cast(&ic_miss_code_)); visitor->VisitPointer(reinterpret_cast(&tag_table_)); visitor->VisitPointer(reinterpret_cast(&sticky_error_)); + visitor->VisitPointer(reinterpret_cast(&finalizers_)); #if !defined(PRODUCT) visitor->VisitPointer( reinterpret_cast(&pending_service_extension_calls_)); diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h index e714838538f..bd1e9fb72eb 100644 --- a/runtime/vm/isolate.h +++ b/runtime/vm/isolate.h @@ -1065,6 +1065,10 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry { void set_init_callback_data(void* value) { init_callback_data_ = value; } void* init_callback_data() const { return init_callback_data_; } + static intptr_t finalizers_offset() { + return OFFSET_OF(Isolate, finalizers_); + } + #if !defined(DART_PRECOMPILED_RUNTIME) NativeCallbackTrampolines* native_callback_trampolines() { return &native_callback_trampolines_; @@ -1540,6 +1544,9 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry { UserTagPtr default_tag_; CodePtr ic_miss_code_; FieldTable* field_table_ = nullptr; + // Used to clear out `UntaggedFinalizerBase::isolate_` pointers on isolate + // shutdown to prevent usage of dangling pointers. + GrowableObjectArrayPtr finalizers_; bool single_step_ = false; bool is_system_isolate_ = false; // End accessed from generated code. @@ -1651,7 +1658,7 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry { Dart_EnvironmentCallback environment_callback_ = nullptr; Random random_; Simulator* simulator_ = nullptr; - Mutex mutex_; // Protects compiler stats. + Mutex mutex_; // Protects compiler stats. MessageHandler* message_handler_ = nullptr; intptr_t defer_finalization_count_ = 0; DeoptContext* deopt_context_ = nullptr; @@ -1727,7 +1734,7 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry { friend class ServiceIsolate; friend class Thread; friend class Timeline; - friend class IsolateGroup; // reload_context_ + friend class IsolateGroup; // reload_context_ DISALLOW_COPY_AND_ASSIGN(Isolate); }; diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc index 0b1eb106be5..f5e8986347e 100644 --- a/runtime/vm/kernel_loader.cc +++ b/runtime/vm/kernel_loader.cc @@ -1300,7 +1300,8 @@ void KernelLoader::LoadLibraryImportsAndExports(Library* library, } if (!Api::IsFfiEnabled() && target_library.url() == Symbols::DartFfi().ptr() && - library->url() != Symbols::DartCore().ptr()) { + library->url() != Symbols::DartCore().ptr() && + library->url() != Symbols::DartInternal().ptr()) { H.ReportError( "import of dart:ffi is not supported in the current Dart runtime"); } diff --git a/runtime/vm/message.cc b/runtime/vm/message.cc index 0f2d2e4c232..d9d06801af9 100644 --- a/runtime/vm/message.cc +++ b/runtime/vm/message.cc @@ -45,12 +45,20 @@ Message::Message(Dart_Port dest_port, ASSERT(IsPersistentHandle()); } +Message::Message(PersistentHandle* handle, Priority priority) + : dest_port_(ILLEGAL_PORT), + payload_(handle), + snapshot_length_(kFinalizerSnapshotLen), + priority_(priority) { + ASSERT(IsFinalizerInvocationRequest()); +} + Message::~Message() { if (IsSnapshot()) { free(payload_.snapshot_); } delete finalizable_data_; - if (IsPersistentHandle()) { + if (IsPersistentHandle() || IsFinalizerInvocationRequest()) { auto isolate_group = IsolateGroup::Current(); isolate_group->api_state()->FreePersistentHandle( payload_.persistent_handle_); diff --git a/runtime/vm/message.h b/runtime/vm/message.h index 4c82bdfaf8e..46064a9484e 100644 --- a/runtime/vm/message.h +++ b/runtime/vm/message.h @@ -62,8 +62,13 @@ class Message { // the VM heap. This is indicated by setting the len_ field to 0. Message(Dart_Port dest_port, ObjectPtr raw_obj, Priority priority); + // A message sent from SendPort.send or SendPort.sendAndExit where sender and + // receiver are in the same isolate group. Message(Dart_Port dest_port, PersistentHandle* handle, Priority priority); + // A message sent from GC to run a finalizer. + Message(PersistentHandle* handle, Priority priority); + ~Message(); template @@ -94,7 +99,7 @@ class Message { return payload_.raw_obj_; } PersistentHandle* persistent_handle() const { - ASSERT(IsPersistentHandle()); + ASSERT(IsPersistentHandle() || IsFinalizerInvocationRequest()); return payload_.persistent_handle_; } Priority priority() const { return priority_; } @@ -103,7 +108,9 @@ class Message { // of at the top of the message loop. Control messages from dart:isolate or // vm-service requests. bool IsOOB() const { return priority_ == Message::kOOBPriority; } - bool IsSnapshot() const { return !IsRaw() && !IsPersistentHandle(); } + bool IsSnapshot() const { + return !IsRaw() && !IsPersistentHandle() && !IsFinalizerInvocationRequest(); + } // A message whose object is an immortal object from the vm-isolate's heap. bool IsRaw() const { return snapshot_length_ == 0; } // A message sent from SendPort.send or SendPort.sendAndExit where sender and @@ -111,6 +118,10 @@ class Message { bool IsPersistentHandle() const { return snapshot_length_ == kPersistentHandleSnapshotLen; } + // A message sent from GC to run a finalizer. + bool IsFinalizerInvocationRequest() const { + return snapshot_length_ == kFinalizerSnapshotLen; + } void DropFinalizers() { if (finalizable_data_ != nullptr) { @@ -124,6 +135,7 @@ class Message { private: static intptr_t const kPersistentHandleSnapshotLen = -1; + static intptr_t const kFinalizerSnapshotLen = -2; friend class MessageQueue; diff --git a/runtime/vm/message_handler.h b/runtime/vm/message_handler.h index 715641be113..228c745a92e 100644 --- a/runtime/vm/message_handler.h +++ b/runtime/vm/message_handler.h @@ -211,6 +211,8 @@ class MessageHandler { Thread* thread() const { return Thread::Current(); } private: + template + friend void MournFinalized(GCVisitorType* visitor); friend class PortMap; friend class MessageHandlerTestPeer; friend class MessageHandlerTask; diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc index cc40ebb956a..b0d52509e0b 100644 --- a/runtime/vm/message_snapshot.cc +++ b/runtime/vm/message_snapshot.cc @@ -26,7 +26,6 @@ namespace dart { - static Dart_CObject cobj_sentinel = {Dart_CObject_kUnsupported, {false}}; static Dart_CObject cobj_transition_sentinel = {Dart_CObject_kUnsupported, {false}}; @@ -46,8 +45,12 @@ class PredefinedCObjects { } static Dart_CObject* cobj_null() { return &getInstance().cobj_null_; } - static Dart_CObject* cobj_empty_array() { return &getInstance().cobj_empty_array_; } - static Dart_CObject* cobj_zero_array() { return &getInstance().cobj_zero_array_; } + static Dart_CObject* cobj_empty_array() { + return &getInstance().cobj_empty_array_; + } + static Dart_CObject* cobj_zero_array() { + return &getInstance().cobj_zero_array_; + } private: PredefinedCObjects() { @@ -3938,6 +3941,11 @@ ObjectPtr ReadObjectGraphCopyMessage(Thread* thread, PersistentHandle* handle) { ObjectPtr ReadMessage(Thread* thread, Message* message) { if (message->IsRaw()) { return message->raw_obj(); + } else if (message->IsFinalizerInvocationRequest()) { + PersistentHandle* handle = message->persistent_handle(); + Object& msg_obj = Object::Handle(thread->zone(), handle->ptr()); + ASSERT(msg_obj.IsFinalizer()); + return msg_obj.ptr(); } else if (message->IsPersistentHandle()) { return ReadObjectGraphCopyMessage(thread, message->persistent_handle()); } else { diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 7b71456cfa9..a81a147effc 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -118,7 +118,7 @@ ArrayPtr SubtypeTestCache::cached_array_; cpp_vtable Object::builtin_vtables_[kNumPredefinedCids] = {}; -// These are initialized to a value that will force a illegal memory access if +// These are initialized to a value that will force an illegal memory access if // they are being used. #if defined(RAW_NULL) #error RAW_NULL should not be defined. @@ -2344,6 +2344,15 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group, pending_classes.Add(cls); RegisterClass(cls, Symbols::FfiDynamicLibrary(), lib); + cls = Class::New(isolate_group); + cls.set_type_arguments_field_offset( + Finalizer::type_arguments_offset(), + RTN::Finalizer::type_arguments_offset()); + cls.set_num_type_arguments_unsafe(1); + object_store->set_finalizer_class(cls); + pending_classes.Add(cls); + RegisterPrivateClass(cls, Symbols::_FinalizerImpl(), core_lib); + // Pre-register the internal library so we can place the vm class // FinalizerEntry there rather than the core library. lib = Library::LookupLibrary(thread, Symbols::DartInternal()); @@ -2356,6 +2365,11 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group, ASSERT(!lib.IsNull()); ASSERT(lib.ptr() == Library::InternalLibrary()); + cls = Class::New(isolate_group); + object_store->set_finalizer_entry_class(cls); + pending_classes.Add(cls); + RegisterClass(cls, Symbols::FinalizerEntry(), lib); + // Finish the initialization by compiling the bootstrap scripts containing // the base interfaces and the implementation of the internal classes. const Error& error = Error::Handle( @@ -2523,6 +2537,10 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group, object_store->set_weak_property_class(cls); cls = Class::New(isolate_group); object_store->set_weak_reference_class(cls); + cls = Class::New(isolate_group); + object_store->set_finalizer_class(cls); + cls = Class::New(isolate_group); + object_store->set_finalizer_entry_class(cls); cls = Class::New(isolate_group); cls = Class::New(isolate_group); @@ -11250,8 +11268,7 @@ class FieldGuardUpdater { FieldGuardUpdater(const Field* field, const Object& value); bool IsUpdateNeeded() { - return does_guarded_cid_need_update_ || - does_is_nullable_need_update_ || + return does_guarded_cid_need_update_ || does_is_nullable_need_update_ || does_list_length_and_offset_need_update_ || does_static_type_exactness_state_need_update_; } @@ -11274,7 +11291,8 @@ class FieldGuardUpdater { } intptr_t guarded_list_length() { return list_length_; } - void set_guarded_list_length_and_offset(intptr_t list_length, + void set_guarded_list_length_and_offset( + intptr_t list_length, intptr_t list_length_in_object_offset) { list_length_ = list_length; list_length_in_object_offset_ = list_length_in_object_offset; @@ -11678,15 +11696,15 @@ void FieldGuardUpdater::ReviewExactnessState() { return; } -FieldGuardUpdater::FieldGuardUpdater(const Field* field, const Object& value): - field_(field), - value_(value), - guarded_cid_(field->guarded_cid()), - is_nullable_(field->is_nullable()), - list_length_(field->guarded_list_length()), - list_length_in_object_offset_( - field->guarded_list_length_in_object_offset()), - static_type_exactness_state_(field->static_type_exactness_state()) { +FieldGuardUpdater::FieldGuardUpdater(const Field* field, const Object& value) + : field_(field), + value_(value), + guarded_cid_(field->guarded_cid()), + is_nullable_(field->is_nullable()), + list_length_(field->guarded_list_length()), + list_length_in_object_offset_( + field->guarded_list_length_in_object_offset()), + static_type_exactness_state_(field->static_type_exactness_state()) { ReviewGuards(); ReviewExactnessState(); } @@ -26012,14 +26030,50 @@ WeakReferencePtr WeakReference::New(Heap::Space space) { space, WeakReference::ContainsCompressedPointers()); return static_cast(raw); } - const char* WeakReference::ToCString() const { TypeArguments& type_args = TypeArguments::Handle(GetTypeArguments()); String& type_args_name = String::Handle(type_args.UserVisibleName()); - return OS::SCreate(Thread::Current()->zone(), "WeakReference%s", + return OS::SCreate(Thread::Current()->zone(), "_WeakReference%s", type_args_name.ToCString()); } +const char* FinalizerBase::ToCString() const { + return "FinalizerBase"; +} + +FinalizerPtr Finalizer::New(Heap::Space space) { + ASSERT(IsolateGroup::Current()->object_store()->finalizer_class() != + Class::null()); + ObjectPtr raw = + Object::Allocate(Finalizer::kClassId, Finalizer::InstanceSize(), space, + Finalizer::ContainsCompressedPointers()); + return static_cast(raw); +} + +const char* Finalizer::ToCString() const { + TypeArguments& type_args = TypeArguments::Handle(GetTypeArguments()); + String& type_args_name = String::Handle(type_args.UserVisibleName()); + return OS::SCreate(Thread::Current()->zone(), "_FinalizerImpl%s", + type_args_name.ToCString()); +} + +FinalizerEntryPtr FinalizerEntry::New(Heap::Space space) { + ASSERT(IsolateGroup::Current()->object_store()->finalizer_entry_class() != + Class::null()); + ObjectPtr raw = + Object::Allocate(FinalizerEntry::kClassId, FinalizerEntry::InstanceSize(), + space, FinalizerEntry::ContainsCompressedPointers()); + return static_cast(raw); +} + +void FinalizerEntry::set_finalizer(const FinalizerBase& value) const { + untag()->set_finalizer(value.ptr()); +} + +const char* FinalizerEntry::ToCString() const { + return "FinalizerEntry"; +} + AbstractTypePtr MirrorReference::GetAbstractTypeReferent() const { ASSERT(Object::Handle(referent()).IsAbstractType()); return AbstractType::Cast(Object::Handle(referent())).ptr(); diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 607d88d9f1d..34b5b78b63c 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -3188,7 +3188,29 @@ class Function : public Object { bool ForceOptimize() const { return IsFfiFromAddress() || IsFfiGetAddress() || IsFfiLoad() || IsFfiStore() || IsFfiTrampoline() || IsFfiAsExternalTypedData() || - IsTypedDataViewFactory() || IsUtf8Scan() || IsGetNativeField(); + IsTypedDataViewFactory() || IsUtf8Scan() || IsGetNativeField() || + IsFinalizerForceOptimized(); + } + + bool IsFinalizerForceOptimized() const { + // Either because of unboxed/untagged data, or because we don't want the GC + // to trigger in between. + switch (recognized_kind()) { + case MethodRecognizer::kFinalizerBase_getIsolateFinalizers: + case MethodRecognizer::kFinalizerBase_setIsolate: + case MethodRecognizer::kFinalizerBase_setIsolateFinalizers: + // Unboxed/untagged representation not supported in unoptimized. + return true; + case MethodRecognizer::kFinalizerBase_exchangeEntriesCollectedWithNull: + // Prevent the GC from running so that the operation is atomic from + // a GC point of view. Always double check implementation in + // kernel_to_il.cc that no GC can happen in between the relevant IL + // instructions. + // TODO(https://dartbug.com/48527): Support inlining. + return true; + default: + return false; + } } bool CanBeInlined() const; @@ -12021,15 +12043,109 @@ class WeakReference : public Instance { return RoundedAllocationSize(sizeof(UntaggedWeakReference)); } - static void Clear(WeakReferencePtr raw_weak) { - ASSERT(raw_weak->untag()->next_seen_by_gc_ == - CompressedWeakReferencePtr(WeakReference::null())); - // This action is performed by the GC. No barrier. - raw_weak->untag()->target_ = Object::null(); + private: + FINAL_HEAP_OBJECT_IMPLEMENTATION(WeakReference, Instance); + friend class Class; +}; + +class FinalizerEntry : public Instance { + public: + ObjectPtr value() const { return untag()->value(); } + void set_value(const Object& value) const { untag()->set_value(value.ptr()); } + static intptr_t value_offset() { + return OFFSET_OF(UntaggedFinalizerEntry, value_); + } + + ObjectPtr detach() const { return untag()->detach(); } + void set_detach(const Object& value) const { + untag()->set_detach(value.ptr()); + } + static intptr_t detach_offset() { + return OFFSET_OF(UntaggedFinalizerEntry, detach_); + } + + ObjectPtr token() const { return untag()->token(); } + void set_token(const Object& value) const { untag()->set_token(value.ptr()); } + static intptr_t token_offset() { + return OFFSET_OF(UntaggedFinalizerEntry, token_); + } + + FinalizerBasePtr finalizer() const { return untag()->finalizer(); } + void set_finalizer(const FinalizerBase& value) const; + static intptr_t finalizer_offset() { + return OFFSET_OF(UntaggedFinalizerEntry, finalizer_); + } + + FinalizerEntryPtr next() const { return untag()->next(); } + void set_next(const FinalizerEntry& value) const { + untag()->set_next(value.ptr()); + } + static intptr_t next_offset() { + return OFFSET_OF(UntaggedFinalizerEntry, next_); + } + + static intptr_t InstanceSize() { + return RoundedAllocationSize(sizeof(UntaggedFinalizerEntry)); + } + + static FinalizerEntryPtr New(Heap::Space space = Heap::kNew); + + private: + FINAL_HEAP_OBJECT_IMPLEMENTATION(FinalizerEntry, Instance); + friend class Class; +}; + +class FinalizerBase : public Instance { + public: + static intptr_t isolate_offset() { + return OFFSET_OF(UntaggedFinalizerBase, isolate_); + } + Isolate* isolate() const { return untag()->isolate_; } + void set_isolate(Isolate* value) const { untag()->isolate_ = value; } + + static intptr_t detachments_offset() { + return OFFSET_OF(UntaggedFinalizerBase, detachments_); + } + + LinkedHashSetPtr all_entries() const { return untag()->all_entries(); } + static intptr_t all_entries_offset() { + return OFFSET_OF(UntaggedFinalizerBase, all_entries_); + } + + FinalizerEntryPtr entries_collected() const { + return untag()->entries_collected(); + } + void set_entries_collected(const FinalizerEntry& value) const { + untag()->set_entries_collected(value.ptr()); + } + static intptr_t entries_collected_offset() { + return OFFSET_OF(UntaggedFinalizer, entries_collected_); } private: - FINAL_HEAP_OBJECT_IMPLEMENTATION(WeakReference, Instance); + HEAP_OBJECT_IMPLEMENTATION(FinalizerBase, Instance); + friend class Class; +}; + +class Finalizer : public FinalizerBase { + public: + static intptr_t type_arguments_offset() { + return OFFSET_OF(UntaggedFinalizer, type_arguments_); + } + + ObjectPtr callback() const { return untag()->callback(); } + static intptr_t callback_offset() { + return OFFSET_OF(UntaggedFinalizer, callback_); + } + + static intptr_t InstanceSize() { + return RoundedAllocationSize(sizeof(UntaggedFinalizer)); + } + + static FinalizerPtr New(Heap::Space space = Heap::kNew); + + private: + FINAL_HEAP_OBJECT_IMPLEMENTATION(Finalizer, FinalizerBase); friend class Class; }; diff --git a/runtime/vm/object_graph_copy.cc b/runtime/vm/object_graph_copy.cc index 0998320db32..ede344dac69 100644 --- a/runtime/vm/object_graph_copy.cc +++ b/runtime/vm/object_graph_copy.cc @@ -35,6 +35,9 @@ V(ExceptionHandlers) \ V(FfiTrampolineData) \ V(Field) \ + V(Finalizer) \ + V(FinalizerBase) \ + V(FinalizerEntry) \ V(Function) \ V(FunctionType) \ V(FutureOr) \ @@ -600,6 +603,7 @@ class ObjectCopyBase { // those are the only non-abstract classes (so we avoid checking more cids // here that cannot happen in reality) HANDLE_ILLEGAL_CASE(DynamicLibrary) + HANDLE_ILLEGAL_CASE(Finalizer) HANDLE_ILLEGAL_CASE(MirrorReference) HANDLE_ILLEGAL_CASE(Pointer) HANDLE_ILLEGAL_CASE(ReceivePort) @@ -1815,7 +1819,7 @@ class ObjectGraphCopier { // We force the GC to compact, which is more likely to discover // untracked pointers (and other issues, like incorrect class table). thread_->heap()->CollectAllGarbage(GCReason::kDebugging, - /*compact=*/ true); + /*compact=*/true); } // Fast copy failed due to diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc index 210f508899f..59245d6d023 100644 --- a/runtime/vm/object_service.cc +++ b/runtime/vm/object_service.cc @@ -1700,6 +1700,29 @@ void WeakReference::PrintJSONImpl(JSONStream* stream, bool ref) const { jsobj.AddProperty("target", target_handle); } +void FinalizerBase::PrintJSONImpl(JSONStream* stream, bool ref) const { + UNREACHABLE(); +} + +void Finalizer::PrintJSONImpl(JSONStream* stream, bool ref) const { + JSONObject jsobj(stream); + PrintSharedInstanceJSON(&jsobj, ref); + jsobj.AddProperty("kind", "Finalizer"); + jsobj.AddServiceId(*this); + if (ref) { + return; + } + + const Object& finalizer_callback = Object::Handle(callback()); + jsobj.AddProperty("callback", finalizer_callback); + + // Not exposing entries. +} + +void FinalizerEntry::PrintJSONImpl(JSONStream* stream, bool ref) const { + UNREACHABLE(); +} + void MirrorReference::PrintJSONImpl(JSONStream* stream, bool ref) const { JSONObject jsobj(stream); PrintSharedInstanceJSON(&jsobj, ref); diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc index 23f9b4dd4e3..bdbc4a1a9ff 100644 --- a/runtime/vm/object_store.cc +++ b/runtime/vm/object_store.cc @@ -78,6 +78,8 @@ ErrorPtr IsolateObjectStore::PreallocateObjects(const Object& out_of_memory) { resume_capabilities_ = GrowableObjectArray::New(); exit_listeners_ = GrowableObjectArray::New(); error_listeners_ = GrowableObjectArray::New(); + dart_args_1_ = Array::New(1); + dart_args_2_ = Array::New(2); // Allocate pre-allocated unhandled exception object initialized with the // pre-allocated OutOfMemoryError. @@ -467,7 +469,24 @@ void ObjectStore::LazyInitFfiMembers() { auto* const thread = Thread::Current(); SafepointWriteRwLocker locker(thread, thread->isolate_group()->program_lock()); - // TODO(http://dartbug.com/47777): Implement finalizers. + if (handle_finalizer_message_function_.load() == Function::null()) { + auto* const zone = thread->zone(); + auto& cls = Class::Handle(zone); + auto& function = Function::Handle(zone); + auto& error = Error::Handle(zone); + + const auto& ffi_lib = Library::Handle(zone, Library::FfiLibrary()); + ASSERT(!ffi_lib.IsNull()); + + cls = finalizer_class(); + ASSERT(!cls.IsNull()); + error = cls.EnsureIsFinalized(thread); + ASSERT(error.IsNull()); + function = + cls.LookupFunctionAllowPrivate(Symbols::_handleFinalizerMessage()); + ASSERT(!function.IsNull()); + handle_finalizer_message_function_.store(function.ptr()); + } } void ObjectStore::LazyInitIsolateMembers() { @@ -512,13 +531,14 @@ void ObjectStore::LazyInitInternalMembers() { auto* const zone = thread->zone(); auto& cls = Class::Handle(zone); auto& field = Field::Handle(zone); + auto& error = Error::Handle(zone); const auto& internal_lib = Library::Handle(zone, Library::InternalLibrary()); cls = internal_lib.LookupClass(Symbols::Symbol()); ASSERT(!cls.IsNull()); - const auto& error = cls.EnsureIsFinalized(thread); - ASSERT(error == Error::null()); + error = cls.EnsureIsFinalized(thread); + ASSERT(error.IsNull()); symbol_class_.store(cls.ptr()); field = cls.LookupInstanceFieldAllowPrivate(Symbols::_name()); diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h index f86b8c5b6db..26bce631497 100644 --- a/runtime/vm/object_store.h +++ b/runtime/vm/object_store.h @@ -55,6 +55,7 @@ class ObjectPointerVisitor; LAZY_CORE(Function, _object_to_string_function) \ LAZY_INTERNAL(Class, symbol_class) \ LAZY_INTERNAL(Field, symbol_name_field) \ + LAZY_FFI(Function, handle_finalizer_message_function) \ LAZY_ASYNC(Type, non_nullable_future_rare_type) \ LAZY_ASYNC(Type, non_nullable_future_never_type) \ LAZY_ASYNC(Type, nullable_future_null_type) \ @@ -126,6 +127,9 @@ class ObjectPointerVisitor; RW(Class, expando_class) \ RW(Class, weak_property_class) \ RW(Class, weak_reference_class) \ + RW(Class, finalizer_class) \ + RW(Class, finalizer_entry_class) \ + RW(Class, finalizer_native_class) \ ARW_AR(Array, symbol_table) \ RW(Array, canonical_types) \ RW(Array, canonical_function_types) \ @@ -315,8 +319,8 @@ class ObjectPointerVisitor; RW(UnhandledException, preallocated_unhandled_exception) \ RW(StackTrace, preallocated_stack_trace) \ RW(UnwindError, preallocated_unwind_error) \ - RW(Array, dart_args_1) \ - RW(Array, dart_args_2) \ + R_(Array, dart_args_1) \ + R_(Array, dart_args_2) \ R_(GrowableObjectArray, resume_capabilities) \ R_(GrowableObjectArray, exit_listeners) \ R_(GrowableObjectArray, error_listeners) diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc index 237ffb05f8c..8a647cbe1af 100644 --- a/runtime/vm/object_test.cc +++ b/runtime/vm/object_test.cc @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. #include +#include #include "include/dart_api.h" @@ -16,12 +17,15 @@ #include "vm/code_descriptors.h" #include "vm/compiler/assembler/assembler.h" #include "vm/compiler/compiler_state.h" +#include "vm/compiler/runtime_api.h" #include "vm/dart_api_impl.h" #include "vm/dart_entry.h" #include "vm/debugger.h" #include "vm/debugger_api_impl_test.h" +#include "vm/flags.h" #include "vm/isolate.h" #include "vm/malloc_hooks.h" +#include "vm/message_handler.h" #include "vm/object.h" #include "vm/object_store.h" #include "vm/resolver.h" @@ -4005,6 +4009,1037 @@ ISOLATE_UNIT_TEST_CASE( WeakReference_Preserve_ReachableThroughWeakProperty(thread, Heap::kOld); } +static int NumEntries(const FinalizerEntry& entry, intptr_t acc = 0) { + if (entry.IsNull()) { + return acc; + } + return NumEntries(FinalizerEntry::Handle(entry.next()), acc + 1); +} + +static void Finalizer_PreserveOne(Thread* thread, + Heap::Space space, + bool with_detach) { +#ifdef DEBUG + SetFlagScope sfs(&FLAG_trace_finalizers, true); +#endif + + MessageHandler* handler = thread->isolate()->message_handler(); + { + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(0, aq.queue()->Length()); + } + + const auto& finalizer = Finalizer::Handle(Finalizer::New(space)); + finalizer.set_isolate(thread->isolate()); + const auto& entry = FinalizerEntry::Handle(FinalizerEntry::New(space)); + entry.set_finalizer(finalizer); + const auto& value = String::Handle(OneByteString::New("value", space)); + entry.set_value(value); + auto& detach = Object::Handle(); + if (with_detach) { + detach = OneByteString::New("detach", space); + } else { + detach = Object::null(); + } + entry.set_detach(detach); + const auto& token = String::Handle(OneByteString::New("token", space)); + entry.set_token(token); + + if (space == Heap::kNew) { + GCTestHelper::CollectNewSpace(); + } else { + GCTestHelper::CollectAllGarbage(); + } + + // Nothing in the entry should have been collected. + EXPECT_NE(Object::null(), entry.value()); + EXPECT((entry.detach() == Object::null()) ^ with_detach); + EXPECT_NE(Object::null(), entry.token()); + + // The entry should not have moved to the collected list. + EXPECT_EQ(0, + NumEntries(FinalizerEntry::Handle(finalizer.entries_collected()))); + + // We should have no messages. + { + // Acquire ownership of message handler queues. + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(0, aq.queue()->Length()); + } +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveNoDetachOne_NewSpace) { + Finalizer_PreserveOne(thread, Heap::kNew, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveNoDetachOne_OldSpace) { + Finalizer_PreserveOne(thread, Heap::kOld, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveWithDetachOne_NewSpace) { + Finalizer_PreserveOne(thread, Heap::kNew, true); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveWithDetachOne_OldSpace) { + Finalizer_PreserveOne(thread, Heap::kOld, true); +} + +static void Finalizer_ClearDetachOne(Thread* thread, Heap::Space space) { +#ifdef DEBUG + SetFlagScope sfs(&FLAG_trace_finalizers, true); +#endif + + MessageHandler* handler = thread->isolate()->message_handler(); + { + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(0, aq.queue()->Length()); + } + + const auto& finalizer = Finalizer::Handle(Finalizer::New(space)); + finalizer.set_isolate(thread->isolate()); + const auto& entry = FinalizerEntry::Handle(FinalizerEntry::New(space)); + entry.set_finalizer(finalizer); + const auto& value = String::Handle(OneByteString::New("value", space)); + entry.set_value(value); + const auto& token = String::Handle(OneByteString::New("token", space)); + entry.set_token(token); + + { + HANDLESCOPE(thread); + const auto& detach = String::Handle(OneByteString::New("detach", space)); + entry.set_detach(detach); + } + + if (space == Heap::kNew) { + GCTestHelper::CollectNewSpace(); + } else { + GCTestHelper::CollectAllGarbage(); + } + + // Detach should have been collected. + EXPECT_NE(Object::null(), entry.value()); + EXPECT_EQ(Object::null(), entry.detach()); + EXPECT_NE(Object::null(), entry.token()); + + // The entry should not have moved to the collected list. + EXPECT_EQ(0, + NumEntries(FinalizerEntry::Handle(finalizer.entries_collected()))); + + // We should have no messages. + { + // Acquire ownership of message handler queues. + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(0, aq.queue()->Length()); + } +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearDetachOne_NewSpace) { + Finalizer_ClearDetachOne(thread, Heap::kNew); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearDetachOne_OldSpace) { + Finalizer_ClearDetachOne(thread, Heap::kOld); +} + +static void Finalizer_ClearValueOne(Thread* thread, + Heap::Space space, + bool null_token) { +#ifdef DEBUG + SetFlagScope sfs(&FLAG_trace_finalizers, true); +#endif + + MessageHandler* handler = thread->isolate()->message_handler(); + { + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(0, aq.queue()->Length()); + } + + const auto& finalizer = Finalizer::Handle(Finalizer::New(space)); + finalizer.set_isolate(thread->isolate()); + const auto& entry = FinalizerEntry::Handle(FinalizerEntry::New(space)); + entry.set_finalizer(finalizer); + const auto& detach = String::Handle(OneByteString::New("detach", space)); + auto& token = Object::Handle(); + if (null_token) { + // Null is a valid token in Dart finalizers. + token = Object::null(); + } else { + token = OneByteString::New("token", space); + } + entry.set_token(token); + entry.set_detach(detach); + + { + HANDLESCOPE(thread); + const auto& value = String::Handle(OneByteString::New("value", space)); + entry.set_value(value); + } + + if (space == Heap::kNew) { + GCTestHelper::CollectNewSpace(); + } else { + GCTestHelper::CollectAllGarbage(); + } + + // Value should have been collected. + EXPECT_EQ(Object::null(), entry.value()); + EXPECT_NE(Object::null(), entry.detach()); + + // The entry should have moved to the collected list. + EXPECT_EQ(1, + NumEntries(FinalizerEntry::Handle(finalizer.entries_collected()))); + + // We should have 1 message. + { + // Acquire ownership of message handler queues. + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(1, aq.queue()->Length()); + } +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueOne_NewSpace) { + Finalizer_ClearValueOne(thread, Heap::kNew, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueOne_OldSpace) { + Finalizer_ClearValueOne(thread, Heap::kOld, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueNullTokenOne_NewSpace) { + Finalizer_ClearValueOne(thread, Heap::kNew, true); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueNullTokenOne_OldSpace) { + Finalizer_ClearValueOne(thread, Heap::kOld, true); +} + +static void Finalizer_DetachOne(Thread* thread, + Heap::Space space, + bool clear_value) { +#ifdef DEBUG + SetFlagScope sfs(&FLAG_trace_finalizers, true); +#endif + + MessageHandler* handler = thread->isolate()->message_handler(); + { + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(0, aq.queue()->Length()); + } + + const auto& finalizer = Finalizer::Handle(Finalizer::New(space)); + finalizer.set_isolate(thread->isolate()); + const auto& entry = FinalizerEntry::Handle(FinalizerEntry::New(space)); + entry.set_finalizer(finalizer); + const auto& detach = String::Handle(OneByteString::New("detach", space)); + entry.set_detach(detach); + + // Simulate calling detach, setting the token of the entry to the entry. + entry.set_token(entry); + + auto& value = String::Handle(); + { + HANDLESCOPE(thread); + + const auto& object = String::Handle(OneByteString::New("value", space)); + entry.set_value(object); + if (!clear_value) { + value = object.ptr(); + } + } + + if (space == Heap::kNew) { + GCTestHelper::CollectNewSpace(); + } else { + GCTestHelper::CollectAllGarbage(); + } + + EXPECT((entry.value() == Object::null()) ^ !clear_value); + EXPECT_NE(Object::null(), entry.detach()); + EXPECT_EQ(entry.ptr(), entry.token()); + + // The entry should have been removed entirely + EXPECT_EQ(0, + NumEntries(FinalizerEntry::Handle(finalizer.entries_collected()))); + + // We should have no message. + { + // Acquire ownership of message handler queues. + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(0, aq.queue()->Length()); + } +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_DetachOne_NewSpace) { + Finalizer_DetachOne(thread, Heap::kNew, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_DetachOne_OldSpace) { + Finalizer_DetachOne(thread, Heap::kOld, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_DetachAndClearValueOne_NewSpace) { + Finalizer_DetachOne(thread, Heap::kNew, true); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_DetachAndClearValueOne_OldSpace) { + Finalizer_DetachOne(thread, Heap::kOld, true); +} + +static void Finalizer_GcFinalizer(Thread* thread, Heap::Space space) { +#ifdef DEBUG + SetFlagScope sfs(&FLAG_trace_finalizers, true); +#endif + + MessageHandler* handler = thread->isolate()->message_handler(); + { + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(0, aq.queue()->Length()); + } + + const auto& detach = String::Handle(OneByteString::New("detach", space)); + const auto& token = String::Handle(OneByteString::New("token", space)); + + { + HANDLESCOPE(thread); + const auto& finalizer = Finalizer::Handle(Finalizer::New(space)); + finalizer.set_isolate(thread->isolate()); + const auto& entry = FinalizerEntry::Handle(FinalizerEntry::New(space)); + entry.set_finalizer(finalizer); + entry.set_detach(detach); + entry.set_token(token); + const auto& value = String::Handle(OneByteString::New("value", space)); + entry.set_value(value); + } + + if (space == Heap::kNew) { + GCTestHelper::CollectNewSpace(); + } else { + GCTestHelper::CollectAllGarbage(); + } + + // We should have no message, the Finalizer itself has been GCed. + { + // Acquire ownership of message handler queues. + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(0, aq.queue()->Length()); + } +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_GcFinalizer_NewSpace) { + Finalizer_GcFinalizer(thread, Heap::kNew); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_GcFinalizer_OldSpace) { + Finalizer_GcFinalizer(thread, Heap::kOld); +} + +static void Finalizer_TwoEntriesCrossGen( + Thread* thread, + Heap::Space* spaces, + bool collect_old_space, + bool collect_new_space, + bool evacuate_new_space_and_collect_old_space, + bool clear_value_1, + bool clear_value_2, + bool clear_detach_1, + bool clear_detach_2) { +#ifdef DEBUG + SetFlagScope sfs(&FLAG_trace_finalizers, true); +#endif + + MessageHandler* handler = thread->isolate()->message_handler(); + // We're reusing the isolate in a loop, so there are messages from previous + // runs of this test. + intptr_t queue_length_start = 0; + { + MessageHandler::AcquiredQueues aq(handler); + queue_length_start = aq.queue()->Length(); + } + + const auto& finalizer = Finalizer::Handle(Finalizer::New(spaces[0])); + finalizer.set_isolate(thread->isolate()); + const auto& entry1 = FinalizerEntry::Handle(FinalizerEntry::New(spaces[1])); + entry1.set_finalizer(finalizer); + const auto& entry2 = FinalizerEntry::Handle(FinalizerEntry::New(spaces[2])); + entry2.set_finalizer(finalizer); + + auto& value1 = String::Handle(); + auto& detach1 = String::Handle(); + const auto& token1 = String::Handle(OneByteString::New("token1", spaces[3])); + entry1.set_token(token1); + + auto& value2 = String::Handle(); + auto& detach2 = String::Handle(); + const auto& token2 = String::Handle(OneByteString::New("token2", spaces[4])); + entry2.set_token(token2); + entry2.set_detach(detach2); + + { + HANDLESCOPE(thread); + auto& object = String::Handle(); + + object ^= OneByteString::New("value1", spaces[5]); + entry1.set_value(object); + if (!clear_value_1) { + value1 = object.ptr(); + } + + object ^= OneByteString::New("detach", spaces[6]); + entry1.set_detach(object); + if (!clear_detach_1) { + detach1 = object.ptr(); + } + + object ^= OneByteString::New("value2", spaces[7]); + entry2.set_value(object); + if (!clear_value_2) { + value2 = object.ptr(); + } + + object ^= OneByteString::New("detach", spaces[8]); + entry2.set_detach(object); + if (!clear_detach_2) { + detach2 = object.ptr(); + } + } + + if (collect_old_space) { + GCTestHelper::CollectOldSpace(); + } + if (collect_new_space) { + GCTestHelper::CollectNewSpace(); + } + if (evacuate_new_space_and_collect_old_space) { + GCTestHelper::CollectAllGarbage(); + } + + EXPECT((entry1.value() == Object::null()) ^ !clear_value_1); + EXPECT((entry2.value() == Object::null()) ^ !clear_value_2); + EXPECT((entry1.detach() == Object::null()) ^ !clear_detach_1); + EXPECT((entry2.detach() == Object::null()) ^ !clear_detach_2); + EXPECT_NE(Object::null(), entry1.token()); + EXPECT_NE(Object::null(), entry2.token()); + + const intptr_t expect_num_cleared = + (clear_value_1 ? 1 : 0) + (clear_value_2 ? 1 : 0); + EXPECT_EQ(expect_num_cleared, + NumEntries(FinalizerEntry::Handle(finalizer.entries_collected()))); + + const intptr_t expect_num_messages = expect_num_cleared == 0 ? 0 : 1; + { + // Acquire ownership of message handler queues. + MessageHandler::AcquiredQueues aq(handler); + EXPECT_EQ(expect_num_messages + queue_length_start, aq.queue()->Length()); + } +} + +const intptr_t kFinalizerTwoEntriesNumObjects = 9; + +static void Finalizer_TwoEntries(Thread* thread, + Heap::Space space, + bool clear_value_1, + bool clear_value_2, + bool clear_detach_1, + bool clear_detach_2) { + const bool collect_old_space = true; + const bool collect_new_space = space == Heap::kNew; + const bool evacuate_new_space_and_collect_old_space = !collect_new_space; + + Heap::Space spaces[kFinalizerTwoEntriesNumObjects]; + for (intptr_t i = 0; i < kFinalizerTwoEntriesNumObjects; i++) { + spaces[i] = space; + } + Finalizer_TwoEntriesCrossGen( + thread, spaces, collect_old_space, collect_new_space, + evacuate_new_space_and_collect_old_space, clear_value_1, clear_value_2, + clear_detach_1, clear_detach_2); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueTwo_NewSpace) { + Finalizer_TwoEntries(thread, Heap::kNew, true, true, false, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueTwo_OldSpace) { + Finalizer_TwoEntries(thread, Heap::kOld, true, true, false, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearFirstValue_NewSpace) { + Finalizer_TwoEntries(thread, Heap::kNew, true, false, false, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearFirstValue_OldSpace) { + Finalizer_TwoEntries(thread, Heap::kOld, true, false, false, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearSecondValue_NewSpace) { + Finalizer_TwoEntries(thread, Heap::kNew, false, true, false, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearSecondValue_OldSpace) { + Finalizer_TwoEntries(thread, Heap::kOld, false, true, false, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveTwo_NewSpace) { + Finalizer_TwoEntries(thread, Heap::kNew, false, false, false, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveTwo_OldSpace) { + Finalizer_TwoEntries(thread, Heap::kOld, false, false, false, false); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearDetachTwo_NewSpace) { + Finalizer_TwoEntries(thread, Heap::kNew, false, false, true, true); +} + +ISOLATE_UNIT_TEST_CASE(Finalizer_ClearDetachTwo_OldSpace) { + Finalizer_TwoEntries(thread, Heap::kOld, false, false, true, true); +} + +static void Finalizer_TwoEntriesCrossGen(Thread* thread, intptr_t test_i) { + ASSERT(test_i < (1 << kFinalizerTwoEntriesNumObjects)); + Heap::Space spaces[kFinalizerTwoEntriesNumObjects]; + for (intptr_t i = 0; i < kFinalizerTwoEntriesNumObjects; i++) { + spaces[i] = ((test_i >> i) & 0x1) == 0x1 ? Heap::kOld : Heap::kNew; + } + // Either collect or evacuate new space. + for (const bool collect_new_space : {false, true}) { + // Always run old space collection first. + const bool collect_old_space = true; + // Always run old space collection after new space. + const bool evacuate_new_space_and_collect_old_space = true; + for (intptr_t test_j = 0; test_j < 16; test_j++) { + const bool clear_value_1 = (test_j >> 0 & 0x1) == 0x1; + const bool clear_value_2 = (test_j >> 1 & 0x1) == 0x1; + const bool clear_detach_1 = (test_j >> 2 & 0x1) == 0x1; + const bool clear_detach_2 = (test_j >> 3 & 0x1) == 0x1; + Finalizer_TwoEntriesCrossGen( + thread, spaces, collect_old_space, collect_new_space, + evacuate_new_space_and_collect_old_space, clear_value_1, + clear_value_2, clear_detach_1, clear_detach_2); + } + } +} +#define FINALIZER_CROSS_GEN_TEST_CASE(n) \ + ISOLATE_UNIT_TEST_CASE(Finalizer_CrossGen_##n) { \ + Finalizer_TwoEntriesCrossGen(thread, n); \ + } + +#define REPEAT_512(V) \ + V(0) \ + V(1) \ + V(2) \ + V(3) \ + V(4) \ + V(5) \ + V(6) \ + V(7) \ + V(8) \ + V(9) \ + V(10) \ + V(11) \ + V(12) \ + V(13) \ + V(14) \ + V(15) \ + V(16) \ + V(17) \ + V(18) \ + V(19) \ + V(20) \ + V(21) \ + V(22) \ + V(23) \ + V(24) \ + V(25) \ + V(26) \ + V(27) \ + V(28) \ + V(29) \ + V(30) \ + V(31) \ + V(32) \ + V(33) \ + V(34) \ + V(35) \ + V(36) \ + V(37) \ + V(38) \ + V(39) \ + V(40) \ + V(41) \ + V(42) \ + V(43) \ + V(44) \ + V(45) \ + V(46) \ + V(47) \ + V(48) \ + V(49) \ + V(50) \ + V(51) \ + V(52) \ + V(53) \ + V(54) \ + V(55) \ + V(56) \ + V(57) \ + V(58) \ + V(59) \ + V(60) \ + V(61) \ + V(62) \ + V(63) \ + V(64) \ + V(65) \ + V(66) \ + V(67) \ + V(68) \ + V(69) \ + V(70) \ + V(71) \ + V(72) \ + V(73) \ + V(74) \ + V(75) \ + V(76) \ + V(77) \ + V(78) \ + V(79) \ + V(80) \ + V(81) \ + V(82) \ + V(83) \ + V(84) \ + V(85) \ + V(86) \ + V(87) \ + V(88) \ + V(89) \ + V(90) \ + V(91) \ + V(92) \ + V(93) \ + V(94) \ + V(95) \ + V(96) \ + V(97) \ + V(98) \ + V(99) \ + V(100) \ + V(101) \ + V(102) \ + V(103) \ + V(104) \ + V(105) \ + V(106) \ + V(107) \ + V(108) \ + V(109) \ + V(110) \ + V(111) \ + V(112) \ + V(113) \ + V(114) \ + V(115) \ + V(116) \ + V(117) \ + V(118) \ + V(119) \ + V(120) \ + V(121) \ + V(122) \ + V(123) \ + V(124) \ + V(125) \ + V(126) \ + V(127) \ + V(128) \ + V(129) \ + V(130) \ + V(131) \ + V(132) \ + V(133) \ + V(134) \ + V(135) \ + V(136) \ + V(137) \ + V(138) \ + V(139) \ + V(140) \ + V(141) \ + V(142) \ + V(143) \ + V(144) \ + V(145) \ + V(146) \ + V(147) \ + V(148) \ + V(149) \ + V(150) \ + V(151) \ + V(152) \ + V(153) \ + V(154) \ + V(155) \ + V(156) \ + V(157) \ + V(158) \ + V(159) \ + V(160) \ + V(161) \ + V(162) \ + V(163) \ + V(164) \ + V(165) \ + V(166) \ + V(167) \ + V(168) \ + V(169) \ + V(170) \ + V(171) \ + V(172) \ + V(173) \ + V(174) \ + V(175) \ + V(176) \ + V(177) \ + V(178) \ + V(179) \ + V(180) \ + V(181) \ + V(182) \ + V(183) \ + V(184) \ + V(185) \ + V(186) \ + V(187) \ + V(188) \ + V(189) \ + V(190) \ + V(191) \ + V(192) \ + V(193) \ + V(194) \ + V(195) \ + V(196) \ + V(197) \ + V(198) \ + V(199) \ + V(200) \ + V(201) \ + V(202) \ + V(203) \ + V(204) \ + V(205) \ + V(206) \ + V(207) \ + V(208) \ + V(209) \ + V(210) \ + V(211) \ + V(212) \ + V(213) \ + V(214) \ + V(215) \ + V(216) \ + V(217) \ + V(218) \ + V(219) \ + V(220) \ + V(221) \ + V(222) \ + V(223) \ + V(224) \ + V(225) \ + V(226) \ + V(227) \ + V(228) \ + V(229) \ + V(230) \ + V(231) \ + V(232) \ + V(233) \ + V(234) \ + V(235) \ + V(236) \ + V(237) \ + V(238) \ + V(239) \ + V(240) \ + V(241) \ + V(242) \ + V(243) \ + V(244) \ + V(245) \ + V(246) \ + V(247) \ + V(248) \ + V(249) \ + V(250) \ + V(251) \ + V(252) \ + V(253) \ + V(254) \ + V(255) \ + V(256) \ + V(257) \ + V(258) \ + V(259) \ + V(260) \ + V(261) \ + V(262) \ + V(263) \ + V(264) \ + V(265) \ + V(266) \ + V(267) \ + V(268) \ + V(269) \ + V(270) \ + V(271) \ + V(272) \ + V(273) \ + V(274) \ + V(275) \ + V(276) \ + V(277) \ + V(278) \ + V(279) \ + V(280) \ + V(281) \ + V(282) \ + V(283) \ + V(284) \ + V(285) \ + V(286) \ + V(287) \ + V(288) \ + V(289) \ + V(290) \ + V(291) \ + V(292) \ + V(293) \ + V(294) \ + V(295) \ + V(296) \ + V(297) \ + V(298) \ + V(299) \ + V(300) \ + V(301) \ + V(302) \ + V(303) \ + V(304) \ + V(305) \ + V(306) \ + V(307) \ + V(308) \ + V(309) \ + V(310) \ + V(311) \ + V(312) \ + V(313) \ + V(314) \ + V(315) \ + V(316) \ + V(317) \ + V(318) \ + V(319) \ + V(320) \ + V(321) \ + V(322) \ + V(323) \ + V(324) \ + V(325) \ + V(326) \ + V(327) \ + V(328) \ + V(329) \ + V(330) \ + V(331) \ + V(332) \ + V(333) \ + V(334) \ + V(335) \ + V(336) \ + V(337) \ + V(338) \ + V(339) \ + V(340) \ + V(341) \ + V(342) \ + V(343) \ + V(344) \ + V(345) \ + V(346) \ + V(347) \ + V(348) \ + V(349) \ + V(350) \ + V(351) \ + V(352) \ + V(353) \ + V(354) \ + V(355) \ + V(356) \ + V(357) \ + V(358) \ + V(359) \ + V(360) \ + V(361) \ + V(362) \ + V(363) \ + V(364) \ + V(365) \ + V(366) \ + V(367) \ + V(368) \ + V(369) \ + V(370) \ + V(371) \ + V(372) \ + V(373) \ + V(374) \ + V(375) \ + V(376) \ + V(377) \ + V(378) \ + V(379) \ + V(380) \ + V(381) \ + V(382) \ + V(383) \ + V(384) \ + V(385) \ + V(386) \ + V(387) \ + V(388) \ + V(389) \ + V(390) \ + V(391) \ + V(392) \ + V(393) \ + V(394) \ + V(395) \ + V(396) \ + V(397) \ + V(398) \ + V(399) \ + V(400) \ + V(401) \ + V(402) \ + V(403) \ + V(404) \ + V(405) \ + V(406) \ + V(407) \ + V(408) \ + V(409) \ + V(410) \ + V(411) \ + V(412) \ + V(413) \ + V(414) \ + V(415) \ + V(416) \ + V(417) \ + V(418) \ + V(419) \ + V(420) \ + V(421) \ + V(422) \ + V(423) \ + V(424) \ + V(425) \ + V(426) \ + V(427) \ + V(428) \ + V(429) \ + V(430) \ + V(431) \ + V(432) \ + V(433) \ + V(434) \ + V(435) \ + V(436) \ + V(437) \ + V(438) \ + V(439) \ + V(440) \ + V(441) \ + V(442) \ + V(443) \ + V(444) \ + V(445) \ + V(446) \ + V(447) \ + V(448) \ + V(449) \ + V(450) \ + V(451) \ + V(452) \ + V(453) \ + V(454) \ + V(455) \ + V(456) \ + V(457) \ + V(458) \ + V(459) \ + V(460) \ + V(461) \ + V(462) \ + V(463) \ + V(464) \ + V(465) \ + V(466) \ + V(467) \ + V(468) \ + V(469) \ + V(470) \ + V(471) \ + V(472) \ + V(473) \ + V(474) \ + V(475) \ + V(476) \ + V(477) \ + V(478) \ + V(479) \ + V(480) \ + V(481) \ + V(482) \ + V(483) \ + V(484) \ + V(485) \ + V(486) \ + V(487) \ + V(488) \ + V(489) \ + V(490) \ + V(491) \ + V(492) \ + V(493) \ + V(494) \ + V(495) \ + V(496) \ + V(497) \ + V(498) \ + V(499) \ + V(500) \ + V(501) \ + V(502) \ + V(503) \ + V(504) \ + V(505) \ + V(506) \ + V(507) \ + V(508) \ + V(509) \ + V(510) \ + V(511) + +REPEAT_512(FINALIZER_CROSS_GEN_TEST_CASE) + ISOLATE_UNIT_TEST_CASE(MirrorReference) { const MirrorReference& reference = MirrorReference::Handle(MirrorReference::New(Object::Handle())); diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc index eb83d684815..82e1bf8892a 100644 --- a/runtime/vm/raw_object.cc +++ b/runtime/vm/raw_object.cc @@ -552,6 +552,8 @@ COMPRESSED_VISITOR(StackTrace) COMPRESSED_VISITOR(RegExp) COMPRESSED_VISITOR(WeakProperty) COMPRESSED_VISITOR(WeakReference) +COMPRESSED_VISITOR(Finalizer) +COMPRESSED_VISITOR(FinalizerEntry) COMPRESSED_VISITOR(MirrorReference) COMPRESSED_VISITOR(UserTag) REGULAR_VISITOR(SubtypeTestCache) @@ -594,6 +596,7 @@ UNREACHABLE_VISITOR(AbstractType) UNREACHABLE_VISITOR(CallSiteData) UNREACHABLE_VISITOR(TypedDataBase) UNREACHABLE_VISITOR(Error) +UNREACHABLE_VISITOR(FinalizerBase) UNREACHABLE_VISITOR(Number) UNREACHABLE_VISITOR(Integer) UNREACHABLE_VISITOR(String) diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 1ba2094a9c1..c21d64a6852 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -623,6 +623,20 @@ class UntaggedObject { } } + template + type ExchangeCompressedPointer(compressed_type const* addr, type value) { + compressed_type previous_value = + reinterpret_cast*>( + const_cast(addr)) + ->exchange(static_cast(value), order); + if (value.IsHeapObject()) { + CheckHeapPointerStore(value, Thread::Current()); + } + return static_cast(previous_value.Decompress(heap_base())); + } + template SmiPtr LoadSmi(SmiPtr const* addr) const { return reinterpret_cast*>(const_cast(addr)) @@ -3321,6 +3335,92 @@ class UntaggedWeakReference : public UntaggedInstance { friend class SlowObjectCopy; // For OFFSET_OF }; +class UntaggedFinalizerBase : public UntaggedInstance { + RAW_HEAP_OBJECT_IMPLEMENTATION(FinalizerBase); + + // The isolate this finalizer belongs to. Updated on sent and exit and set + // to null on isolate shutdown. See Isolate::finalizers_. + Isolate* isolate_; + + COMPRESSED_POINTER_FIELD(ObjectPtr, detachments) + VISIT_FROM(detachments) + COMPRESSED_POINTER_FIELD(LinkedHashSetPtr, all_entries) + COMPRESSED_POINTER_FIELD(FinalizerEntryPtr, entries_collected) + +// With compressed pointers, the first field in a subclass is at offset 28. +// If the fields would be public, the first field in a subclass is at offset 32. +// On Windows, it is always at offset 32, no matter public/private. +// This makes it 32 for all OSes. +// We can't use ALIGN8 on the first fields of the subclasses because they use +// the COMPRESSED_POINTER_FIELD macro to define it. +#ifdef DART_COMPRESSED_POINTERS + uint32_t align_next_field; +#endif + + template + friend void MournFinalized(GCVisitorType* visitor); + friend class GCMarker; + template + friend class MarkingVisitorBase; + friend class Scavenger; + template + friend class ScavengerVisitorBase; +}; + +class UntaggedFinalizer : public UntaggedFinalizerBase { + RAW_HEAP_OBJECT_IMPLEMENTATION(Finalizer); + + COMPRESSED_POINTER_FIELD(ClosurePtr, callback) + COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, type_arguments) + VISIT_TO(type_arguments) + + template + FinalizerEntryPtr exchange_entries_collected(FinalizerEntryPtr value) { + return ExchangeCompressedPointer( + &entries_collected_, value); + } + + template + friend void MournFinalized(GCVisitorType* visitor); + friend class GCMarker; + template + friend class MarkingVisitorBase; + friend class Scavenger; + template + friend class ScavengerVisitorBase; +}; + +class UntaggedFinalizerEntry : public UntaggedInstance { + RAW_HEAP_OBJECT_IMPLEMENTATION(FinalizerEntry); + + COMPRESSED_POINTER_FIELD(ObjectPtr, value) // Weak reference. + VISIT_FROM(value) + COMPRESSED_POINTER_FIELD(ObjectPtr, detach) // Weak reference. + COMPRESSED_POINTER_FIELD(ObjectPtr, token) + COMPRESSED_POINTER_FIELD(FinalizerBasePtr, finalizer) // Weak reference. + // Used for the linked list in Finalizer::entries_collected_. That cannot be + // an ordinary list because we need to add elements during a GC so we cannot + // modify the heap. + COMPRESSED_POINTER_FIELD(FinalizerEntryPtr, next) + VISIT_TO(next) + + // Linked list is chaining all pending. Not visited by pointer visitors. + // Only populated during the GC, otherwise null. + COMPRESSED_POINTER_FIELD(FinalizerEntryPtr, next_seen_by_gc) + + template + friend class GCLinkedList; + template + friend void MournFinalized(GCVisitorType* visitor); + friend class GCMarker; + template + friend class MarkingVisitorBase; + friend class Scavenger; + template + friend class ScavengerVisitorBase; +}; + // MirrorReferences are used by mirrors to hold reflectees that are VM // internal objects, such as libraries, classes, functions or types. class UntaggedMirrorReference : public UntaggedInstance { diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index 77840416ffb..7953a1fc47b 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -137,6 +137,8 @@ class ObjectPointerVisitor; V(FfiVoid, "Void") \ V(FfiHandle, "Handle") \ V(Field, "Field") \ + V(FinalizerBase, "FinalizerBase") \ + V(FinalizerEntry, "FinalizerEntry") \ V(FinallyRetVal, ":finally_ret_val") \ V(FirstArg, "x") \ V(Float32List, "Float32List") \ @@ -308,6 +310,7 @@ class ObjectPointerVisitor; V(_ExternalUint64Array, "_ExternalUint64Array") \ V(_ExternalUint8Array, "_ExternalUint8Array") \ V(_ExternalUint8ClampedArray, "_ExternalUint8ClampedArray") \ + V(_FinalizerImpl, "_FinalizerImpl") \ V(_Float32ArrayFactory, "Float32List.") \ V(_Float32ArrayView, "_Float32ArrayView") \ V(_Float32List, "_Float32List") \ @@ -407,6 +410,7 @@ class ObjectPointerVisitor; V(_ensureScheduleImmediate, "_ensureScheduleImmediate") \ V(_future, "_future") \ V(_handleMessage, "_handleMessage") \ + V(_handleFinalizerMessage, "_handleFinalizerMessage") \ V(_instanceOf, "_instanceOf") \ V(_listGetAt, "_listGetAt") \ V(_listLength, "_listLength") \ diff --git a/runtime/vm/tagged_pointer.h b/runtime/vm/tagged_pointer.h index 0f53fe793c7..5a0b99f20e8 100644 --- a/runtime/vm/tagged_pointer.h +++ b/runtime/vm/tagged_pointer.h @@ -413,6 +413,9 @@ DEFINE_TAGGED_POINTER(StackTrace, Instance) DEFINE_TAGGED_POINTER(RegExp, Instance) DEFINE_TAGGED_POINTER(WeakProperty, Instance) DEFINE_TAGGED_POINTER(WeakReference, Instance) +DEFINE_TAGGED_POINTER(FinalizerBase, Instance) +DEFINE_TAGGED_POINTER(Finalizer, Instance) +DEFINE_TAGGED_POINTER(FinalizerEntry, Instance) DEFINE_TAGGED_POINTER(MirrorReference, Instance) DEFINE_TAGGED_POINTER(UserTag, Instance) DEFINE_TAGGED_POINTER(FutureOr, Instance) diff --git a/sdk/lib/_internal/vm/lib/core_patch.dart b/sdk/lib/_internal/vm/lib/core_patch.dart index 78b3bab372f..79ff4aa14d4 100644 --- a/sdk/lib/_internal/vm/lib/core_patch.dart +++ b/sdk/lib/_internal/vm/lib/core_patch.dart @@ -13,10 +13,14 @@ import "dart:_internal" show allocateOneByteString, allocateTwoByteString, + checkValidWeakTarget, ClassID, CodeUnits, copyRangeFromUint8ListToOneByteString, EfficientLengthIterable, + FinalizerBase, + FinalizerBaseMembers, + FinalizerEntry, FixedLengthListBase, IterableElementError, ListIterator, @@ -28,11 +32,12 @@ import "dart:_internal" makeFixedListUnmodifiable, makeListFixedLength, patch, + reachabilityFence, unsafeCast, writeIntoOneByteString, writeIntoTwoByteString; -import "dart:async" show Completer, DeferredLoadException, Future, Timer; +import "dart:async" show Completer, DeferredLoadException, Future, Timer, Zone; import "dart:collection" show @@ -49,9 +54,9 @@ import "dart:collection" import "dart:convert" show ascii, Encoding, json, latin1, utf8; -import "dart:ffi" show Pointer, Struct, Union; +import "dart:ffi" show Pointer, Struct, Union, NativePort; -import "dart:isolate" show Isolate; +import "dart:isolate" show Isolate, RawReceivePort; import "dart:typed_data" show Endian, Uint8List, Int64List, Uint16List, Uint32List; diff --git a/sdk/lib/_internal/vm/lib/expando_patch.dart b/sdk/lib/_internal/vm/lib/expando_patch.dart index cf34b7fb244..fd5bd93ae83 100644 --- a/sdk/lib/_internal/vm/lib/expando_patch.dart +++ b/sdk/lib/_internal/vm/lib/expando_patch.dart @@ -28,7 +28,8 @@ class Expando { @patch T? operator [](Object object) { - _checkType(object); + // TODO(http://dartbug.com/48634): Rename to `key`. + checkValidWeakTarget(object, 'object'); var mask = _size - 1; var idx = object._identityHashCode & mask; @@ -50,7 +51,8 @@ class Expando { @patch void operator []=(Object object, T? value) { - _checkType(object); + // TODO(http://dartbug.com/48634): Rename to `key`. + checkValidWeakTarget(object, 'object'); var mask = _size - 1; var idx = object._identityHashCode & mask; @@ -147,19 +149,6 @@ class Expando { } } - static _checkType(object) { - if ((object == null) || - (object is bool) || - (object is num) || - (object is String) || - (object is Pointer) || - (object is Struct) || - (object is Union)) { - throw new ArgumentError.value(object, - "Expandos are not allowed on strings, numbers, booleans, null, Pointers, Structs or Unions."); - } - } - int get _size => _data.length; int get _limit => (3 * (_size ~/ 4)); @@ -170,14 +159,14 @@ class Expando { @patch class WeakReference { @patch - factory WeakReference(T object) = _WeakReferenceImpl; + factory WeakReference(T target) = _WeakReferenceImpl; } @pragma("vm:entry-point") class _WeakReferenceImpl implements WeakReference { - _WeakReferenceImpl(T object) { - Expando._checkType(object); - _target = object; + _WeakReferenceImpl(T target) { + checkValidWeakTarget(target, 'target'); + _target = target; } @pragma("vm:recognized", "other") @@ -190,11 +179,3 @@ class _WeakReferenceImpl implements WeakReference { @pragma("vm:external-name", "WeakReference_setTarget") external set _target(T? value); } - -@patch -class Finalizer { - @patch - factory Finalizer(void Function(T) object) { - throw UnimplementedError("Finalizer"); - } -} diff --git a/sdk/lib/_internal/vm/lib/finalizer_patch.dart b/sdk/lib/_internal/vm/lib/finalizer_patch.dart index aec537bf694..a9db8536c6a 100644 --- a/sdk/lib/_internal/vm/lib/finalizer_patch.dart +++ b/sdk/lib/_internal/vm/lib/finalizer_patch.dart @@ -4,5 +4,83 @@ // part of "core_patch.dart"; -// This is a placeholder file which will shortly contain a Finalizer -// implementation. +@patch +@pragma("vm:entry-point") +abstract class Finalizer { + @patch + factory Finalizer(void Function(T) callback) = _FinalizerImpl; +} + +@pragma("vm:entry-point") +class _FinalizerImpl extends FinalizerBase implements Finalizer { + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external void Function(T) get _callback; + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external set _callback(void Function(T) value); + + /// Constructs a finalizer. + /// + /// This is fine as a non-atomic operation, because the GC only looks at + /// finalizer instances when it process their entries. By preventing inlining + /// we ensure the the finalizer to have been fully initialized by the time + /// any [attach] on it is called. + /// + /// Alternatively, we could make it a recognized method and add a reachability + /// fence on the relevant members. + @pragma('vm:never-inline') + _FinalizerImpl(void Function(T) callback) { + allEntries = {}; + _callback = Zone.current.bindUnaryCallbackGuarded(callback); + setIsolate(); + isolateRegisterFinalizer(); + } + + void attach(Object value, T token, {Object? detach}) { + checkValidWeakTarget(value, 'value'); + if (detach != null) { + checkValidWeakTarget(detach, 'detach'); + } + + // Initializing the entry in a non-atomic way should be fine. + // The only interesting step in the GC is when value is collected. + // If the entry gets processed before initializing value, it will be null, + // and this is fine. We will not consider it as being collected that GC. + final entry = FinalizerEntry() + ..value = value + ..token = token + ..detach = detach + ..finalizer = this; + allEntries.add(entry); + // Ensure value stays reachable until after having initialized the entry. + // This ensures the token and finalizer are set. + reachabilityFence(value); + + if (detach != null) { + (detachments[detach] ??= {}).add(entry); + } + } + + void _runFinalizers() { + FinalizerEntry? entry = exchangeEntriesCollectedWithNull(); + while (entry != null) { + final token = entry.token; + // Check token for identical, detach might have been called. + if (!identical(token, entry)) { + _callback(unsafeCast(token)); + } + allEntries.remove(entry); + final detach = entry.detach; + if (detach != null) { + detachments[detach]?.remove(entry); + } + entry = entry.next; + } + } + + @pragma("vm:entry-point", "call") + static _handleFinalizerMessage(_FinalizerImpl finalizer) { + finalizer._runFinalizers(); + } +} diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart index 4c0fa92eb6e..547835cf5cd 100644 --- a/sdk/lib/_internal/vm/lib/internal_patch.dart +++ b/sdk/lib/_internal/vm/lib/internal_patch.dart @@ -9,7 +9,7 @@ import "dart:async" show Timer; import "dart:core" hide Symbol; - +import "dart:ffi" show Pointer, Struct, Union; import "dart:isolate" show SendPort; import "dart:typed_data" show Int32List, Uint8List; @@ -209,3 +209,225 @@ class LateError { throw new LateError.localADI(localName); } } + +void checkValidWeakTarget(object, name) { + if ((object == null) || + (object is bool) || + (object is num) || + (object is String) || + (object is Pointer) || + (object is Struct) || + (object is Union)) { + throw new ArgumentError.value(object, name, + "Cannot be a string, number, boolean, null, Pointer, Struct or Union"); + } +} + +@pragma("vm:entry-point") +class FinalizerBase { + /// The list of finalizers of this isolate. + /// + /// Reuses [WeakReference] so that we don't have to implement yet another + /// mechanism to hold on weakly to things. + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external static List>? get _isolateFinalizers; + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external static set _isolateFinalizers( + List>? value); + + static int _isolateFinalizersPurgeCollectedAt = 1; + + /// Amortizes the cost for purging nulled out entries. + /// + /// Similar to how Expandos purge their nulled out entries on a rehash when + /// resizing. + static void _isolateFinalizersEnsureCapacity() { + _isolateFinalizers ??= >[]; + if (_isolateFinalizers!.length < _isolateFinalizersPurgeCollectedAt) { + return; + } + // retainWhere does a single traversal. + _isolateFinalizers!.retainWhere((weak) => weak.target != null); + // We might have dropped most finalizers, trigger next resize at 2x. + _isolateFinalizersPurgeCollectedAt = _isolateFinalizers!.length * 2; + } + + /// Registers this [FinalizerBase] to the isolate. + /// + /// This is used to prevent sending messages from the GC to the isolate after + /// isolate shutdown. + void _isolateRegisterFinalizer() { + _isolateFinalizersEnsureCapacity(); + _isolateFinalizers!.add(WeakReference(this)); + } + + /// The isolate this [FinalizerBase] belongs to. + /// + /// This is used to send finalizer messages to `_handleFinalizerMessage` + /// without a Dart_Port. + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external _setIsolate(); + + /// All active attachments. + /// + /// This keeps the [FinalizerEntry]s belonging to this finalizer alive. If an + /// entry gets collected, the finalizer is not run when the + /// [FinalizerEntry.value] is collected. + /// + /// TODO(http://dartbug.com/47777): For native finalizers, what data structure + /// can we use that we can modify in the VM. So that we don't have to send a + /// message to Dart to clean up entries for which the GC has run. + /// + /// Requirements for data structure: + /// 1. Keeps entries reachable. Entries that are collected will never run + /// the GC. + /// 2. Atomic insert in Dart on `attach`. GC should not run in between. + /// 3. Atomic remove in Dart on `detach`. multiple GC tasks run in parallel. + /// 4. Atomic remove in C++ on value being collected. Multiple GC tasks run in + /// parallel. + /// + /// For Dart finalizers we execute the remove in Dart, much simpler. + @pragma("vm:recognized", "other") + @pragma('vm:prefer-inline') + external Set get _allEntries; + @pragma("vm:recognized", "other") + @pragma('vm:prefer-inline') + external set _allEntries(Set entries); + + /// Entries of which the value has been collected. + /// + /// This is a linked list, with [FinalizerEntry.next]. + /// + /// Atomic exchange: The GC cannot run between reading the value and storing + /// `null`. Atomicity guaranteed by force optimizing the function. + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external FinalizerEntry? _exchangeEntriesCollectedWithNull(); + + /// A weak map from `detach` keys to [FinalizerEntry]s. + /// + /// Using the [FinalizerEntry.detach] keys as keys in an [Expando] ensures + /// they can be GCed. + /// + /// [FinalizerEntry]s do not get GCed themselves when their + /// [FinalizerEntry.detach] is unreachable, in contrast to `WeakProperty`s + /// which are GCed themselves when their `key` is no longer reachable. + /// To prevent [FinalizerEntry]s staying around in [_detachments] forever, + /// we reuse `WeakProperty`s. + /// To avoid code duplication, we do not inline the code but use an [Expando] + /// here instead. + /// + /// We cannot eagerly purge entries from the map (in the Expando) when GCed. + /// The map is indexed on detach, and doesn't enable finding the entries + /// based on their identity. + /// Instead we rely on the WeakProperty being nulled out (assuming the + /// `detach` key gets GCed) and then reused. + @pragma("vm:recognized", "other") + @pragma('vm:prefer-inline') + external Expando>? get _detachments; + @pragma("vm:recognized", "other") + @pragma('vm:prefer-inline') + external set _detachments(Expando>? value); + + void detach(Object detach) { + final entries = detachments[detach]; + if (entries != null) { + for (final entry in entries) { + entry.token = entry; + _allEntries.remove(entry); + } + detachments[detach] = null; + } + } +} + +// Extension so that the members can be accessed from other libs. +extension FinalizerBaseMembers on FinalizerBase { + /// See documentation on [_allEntries]. + @pragma('vm:prefer-inline') + Set get allEntries => _allEntries; + @pragma('vm:prefer-inline') + set allEntries(Set value) => _allEntries = value; + + /// See documentation on [_exchangeEntriesCollectedWithNull]. + FinalizerEntry? exchangeEntriesCollectedWithNull() => + _exchangeEntriesCollectedWithNull(); + + /// See documentation on [_detachments]. + @pragma('vm:prefer-inline') + Expando> get detachments { + _detachments ??= Expando>(); + return unsafeCast>>(_detachments); + } + + /// See documentation on [_isolateRegisterFinalizer]. + isolateRegisterFinalizer() => _isolateRegisterFinalizer(); + + /// See documentation on [_setIsolate]. + setIsolate() => _setIsolate(); +} + +/// Contains the informatation of an active [Finalizer.attach]. +/// +/// It holds on to the [value], optional [detach], and [token]. In addition, it +/// also keeps a reference the [finalizer] it belings to and a [next] field for +/// when being used in a linked list. +/// +/// This is being kept alive by [FinalizerBase._allEntries] until either (1) +/// [Finalizer.detach] detaches it, or (2) [value] is collected and the +/// `callback` has been invoked. +/// +/// Note that the GC itself uses an extra hidden field `next_seen_by_gc` to keep a +/// linked list of pending entries while running the GC. +@pragma("vm:entry-point") +class FinalizerEntry { + /// The [value] the [FinalizerBase] is attached to. + /// + /// Set to `null` by GC when unreachable. + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external Object? get value; + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external set value(Object? value); + + /// The [detach] object can be passed to [FinalizerBase] to detach + /// the finalizer. + /// + /// Set to `null` by GC when unreachable. + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external Object? get detach; + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external set detach(Object? value); + + /// The [token] is passed to [FinalizerBase] when the finalizer is run. + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external Object? get token; + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external set token(Object? value); + + /// The [finalizer] this [FinalizerEntry] belongs to. + /// + /// Set to `null` by GC when unreachable. + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external set finalizer(FinalizerBase? finalizer); + + /// The [next] entry in a linked list. + /// + /// Used in for the linked list starting from + /// [FinalizerBase._exchangeEntriesCollectedWithNull]. + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external FinalizerEntry? get next; + @pragma("vm:recognized", "other") + @pragma("vm:prefer-inline") + external set next(FinalizerEntry? value); +} diff --git a/sdk/lib/core/weak.dart b/sdk/lib/core/weak.dart index 01ef31c1eab..3c8f96888c5 100644 --- a/sdk/lib/core/weak.dart +++ b/sdk/lib/core/weak.dart @@ -207,15 +207,15 @@ abstract class Finalizer { /// with different, or the same, finalization token. void attach(Object value, T finalizationToken, {Object? detach}); - /// Detaches the finalizer from values attached with [detachToken]. + /// Detaches this finalizer from values attached with [detach]. /// /// Each attachment between this finalizer and a value, - /// which was created by calling [attach] with the [detachToken] object as + /// which was created by calling [attach] with the [detach] object as /// `detach` argument, is removed. /// /// If the finalizer was attached multiple times to the same value /// with different detachment keys, - /// only those attachments which used [detachToken] are removed. + /// only those attachments which used [detach] are removed. /// /// After detaching, an attachment won't cause any callbacks to happen /// if the object become inaccessible. @@ -242,5 +242,5 @@ abstract class Finalizer { /// } /// } /// ``` - void detach(Object detachToken); + void detach(Object detach); } diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart index 96ef3e5db71..6b2b940f56b 100644 --- a/sdk/lib/isolate/isolate.dart +++ b/sdk/lib/isolate/isolate.dart @@ -723,6 +723,7 @@ abstract class SendPort implements Capability { /// therefore not be sent. /// - [ReceivePort] /// - [DynamicLibrary] + /// - [Finalizer] /// - [Pointer] /// - [UserTag] /// - `MirrorReference`