From 7dca34c23535287593595a3f570a714465556210 Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Tue, 22 Mar 2022 10:30:18 +0000 Subject: [PATCH] [vm] Implement `Finalizer` This CL implements the `Finalizer` in the GC. (This CL does not yet implement `NativeFinalizer`.) 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: I03e6b4a46212316254bf46ba3f2df333abaa686c 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/+/229544 Reviewed-by: Lasse Nielsen Reviewed-by: Slava Egorov 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/app_snapshot.cc | 2 +- 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 | 66 +- runtime/vm/dart_entry.h | 8 +- runtime/vm/flag_list.h | 1 + runtime/vm/heap/gc_shared.cc | 39 + runtime/vm/heap/gc_shared.h | 195 ++++ runtime/vm/heap/heap_sources.gni | 2 + runtime/vm/heap/marker.cc | 191 ++- runtime/vm/heap/scavenger.cc | 157 +-- 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 | 5 + runtime/vm/object.cc | 58 +- runtime/vm/object.h | 136 ++- runtime/vm/object_graph_copy.cc | 14 +- 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 | 112 +- 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 + 67 files changed, 4318 insertions(+), 446 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 create mode 100644 runtime/vm/heap/gc_shared.cc create mode 100644 runtime/vm/heap/gc_shared.h diff --git a/runtime/docs/gc.md b/runtime/docs/gc.md index 7c2fd9aab38e..ac9696d47b2e 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 3d2a0f093f52..e2ef579add21 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 000000000000..c0dfdebfe4f4 --- /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 000000000000..ba5216fd60da --- /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 000000000000..5750bf438ecc --- /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 000000000000..8000a41a8e7d --- /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 000000000000..a278b5db88d8 --- /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 000000000000..bcc6d9e1d047 --- /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 000000000000..d776098aced6 --- /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 15b330d16b71..da365b98f9da 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 cd24fbc51432..d714c560be8b 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 000000000000..58ff5bbcbba2 --- /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 000000000000..afd09bba078a --- /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 000000000000..7c2103d881e3 --- /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 000000000000..b033c1b3f55e --- /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 000000000000..9c1746122429 --- /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 000000000000..17646d1ec0d6 --- /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 000000000000..a82646ce3440 --- /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 8c7583d94625..708d5403274e 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 1843f0c7f966..91fd27d2ed31 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 1f5066c31fb6..8feee006d68a 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/app_snapshot.cc b/runtime/vm/app_snapshot.cc index f694613bca86..e2b8a4098cfe 100644 --- a/runtime/vm/app_snapshot.cc +++ b/runtime/vm/app_snapshot.cc @@ -5140,7 +5140,7 @@ class WeakPropertyDeserializationCluster : public DeserializationCluster { Deserializer::InitializeHeader(property, kWeakPropertyCid, WeakProperty::InstanceSize()); ReadFromTo(property); - property->untag()->next_ = WeakProperty::null(); + property->untag()->next_seen_by_gc_ = WeakProperty::null(); } } }; diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc index dc432e37da00..e91180e00300 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 93e1979eafff..501c3a827c5e 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 4d28937959ba..8d01fc7901d3 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 4a512f823253..dfd04aca34f6 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 ab82fe271809..995ce8cf66b5 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 006ea70edc25..9abd1fd95a74 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 03a18f68d44c..2a92d6ae2124 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 e8a7016ccaea..1676f7c64680 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 9cc619dbbd6f..d9ddcb3d4f7f 100644 --- a/runtime/vm/compiler/runtime_api.cc +++ b/runtime/vm/compiler/runtime_api.cc @@ -439,6 +439,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 f502d997fa1f..11d001306cf4 100644 --- a/runtime/vm/compiler/runtime_api.h +++ b/runtime/vm/compiler/runtime_api.h @@ -1045,6 +1045,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(); @@ -1242,6 +1270,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 6f1d53533ed8..ee0e4c22363c 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; @@ -436,6 +437,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; @@ -518,6 +535,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; @@ -754,6 +773,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; @@ -761,7 +781,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 @@ -790,12 +810,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 = @@ -1013,6 +1033,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; @@ -1096,6 +1132,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; @@ -1330,6 +1368,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; @@ -1337,7 +1376,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 @@ -1366,12 +1405,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; @@ -1583,6 +1622,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; @@ -1662,6 +1717,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; @@ -1898,6 +1955,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; @@ -1905,7 +1963,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 @@ -1934,12 +1992,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 = @@ -2157,6 +2215,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; @@ -2241,6 +2315,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; @@ -2475,6 +2551,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; @@ -2482,7 +2559,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 @@ -2511,12 +2588,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 = @@ -2734,6 +2811,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; @@ -2817,6 +2910,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; @@ -3051,6 +3146,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; @@ -3058,7 +3154,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 @@ -3087,12 +3183,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 = @@ -3310,6 +3406,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; @@ -3394,6 +3506,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; @@ -3628,6 +3742,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; @@ -3635,7 +3750,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 @@ -3664,12 +3779,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; @@ -3881,6 +3996,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; @@ -3965,6 +4096,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; @@ -4201,6 +4334,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; @@ -4208,7 +4342,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 @@ -4237,12 +4371,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 = @@ -4460,6 +4594,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; @@ -4544,6 +4694,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; @@ -4775,6 +4927,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; @@ -4810,12 +4963,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; @@ -5027,6 +5180,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; @@ -5109,6 +5278,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; @@ -5340,6 +5511,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; @@ -5375,12 +5547,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 = @@ -5598,6 +5770,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; @@ -5681,6 +5869,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; @@ -5910,6 +6100,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; @@ -5945,12 +6136,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; @@ -6162,6 +6353,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; @@ -6241,6 +6448,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; @@ -6472,6 +6681,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; @@ -6507,12 +6717,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 = @@ -6730,6 +6940,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; @@ -6814,6 +7040,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; @@ -7043,6 +7271,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; @@ -7078,12 +7307,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 = @@ -7301,6 +7530,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; @@ -7384,6 +7629,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; @@ -7613,6 +7860,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; @@ -7648,12 +7896,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 = @@ -7871,6 +8119,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; @@ -7955,6 +8219,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; @@ -8184,6 +8450,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; @@ -8219,12 +8486,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; @@ -8436,6 +8703,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; @@ -8520,6 +8803,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; @@ -8751,6 +9036,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; @@ -8786,12 +9072,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 = @@ -9009,6 +9295,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; @@ -9093,6 +9395,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; @@ -9345,6 +9649,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 @@ -9354,7 +9660,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; @@ -9389,13 +9695,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; @@ -9626,6 +9932,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; @@ -9720,6 +10048,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; @@ -9982,6 +10313,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 @@ -9991,7 +10324,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; @@ -10026,13 +10359,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; @@ -10264,6 +10597,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; @@ -10360,6 +10715,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; @@ -10625,6 +10983,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 @@ -10634,7 +10994,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; @@ -10669,13 +11029,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; @@ -10907,6 +11267,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; @@ -11004,6 +11386,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; @@ -11265,6 +11650,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 @@ -11274,7 +11661,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; @@ -11309,13 +11696,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; @@ -11547,6 +11934,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; @@ -11643,6 +12052,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; @@ -11904,6 +12316,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 @@ -11913,7 +12327,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; @@ -11948,13 +12362,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; @@ -12186,6 +12600,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; @@ -12283,6 +12719,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; @@ -12544,6 +12983,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 @@ -12553,7 +12994,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; @@ -12588,13 +13029,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; @@ -12825,6 +13266,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; @@ -12921,6 +13384,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; @@ -13183,6 +13649,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 @@ -13192,7 +13660,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; @@ -13227,13 +13695,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; @@ -13465,6 +13933,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; @@ -13562,6 +14052,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; @@ -13820,6 +14313,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 @@ -13862,13 +14357,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; @@ -14099,6 +14594,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; @@ -14193,6 +14710,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; @@ -14450,6 +14970,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 @@ -14492,13 +15014,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; @@ -14730,6 +15252,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; @@ -14826,6 +15370,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; @@ -15086,6 +15633,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 @@ -15128,13 +15677,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; @@ -15366,6 +15915,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; @@ -15463,6 +16034,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; @@ -15719,6 +16293,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 @@ -15761,13 +16337,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; @@ -15999,6 +16575,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; @@ -16095,6 +16693,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; @@ -16351,6 +16952,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 @@ -16393,13 +16996,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; @@ -16631,6 +17234,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; @@ -16728,6 +17353,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; @@ -16984,6 +17612,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 @@ -17026,13 +17656,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; @@ -17263,6 +17893,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; @@ -17359,6 +18011,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; @@ -17616,6 +18271,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 @@ -17658,13 +18315,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; @@ -17896,6 +18553,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; @@ -17993,6 +18672,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 cbd470c3fe6b..7f4c2323649d 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) \ @@ -300,6 +301,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) \ @@ -362,6 +374,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 b2fd4b316e81..9042281fc2ac 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 46df59fa622e..501568e06614 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,32 +702,56 @@ ObjectPtr DartLibraryCalls::LookupOpenPorts() { return result.ptr(); } +static void DebuggerSetResumeIfStepping(Isolate* isolate) { +#if !defined(PRODUCT) + if (isolate->debugger()->IsStepping()) { + // If the isolate is being debugged and the debugger was stepping + // through code, enable single stepping so debugger will stop + // at the first location the user is interested in. + isolate->debugger()->SetResumeAction(Debugger::kStepInto); + } +#endif +} + 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(); + 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()); - 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); - } + ASSERT(!args.IsNull()); args.SetAt(0, Integer::Handle(zone, Integer::New(port_id))); args.SetAt(1, message); -#if !defined(PRODUCT) - if (isolate->debugger()->IsStepping()) { - // If the isolate is being debugged and the debugger was stepping - // through code, enable single stepping so debugger will stop - // at the first location the user is interested in. - isolate->debugger()->SetResumeAction(Debugger::kStepInto); + 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()); } -#endif + + 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 4f650a87eed3..c5cc2be5bb75 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 1e77f74952a5..68b49e4320a2 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.cc b/runtime/vm/heap/gc_shared.cc new file mode 100644 index 000000000000..0941bd61f229 --- /dev/null +++ b/runtime/vm/heap/gc_shared.cc @@ -0,0 +1,39 @@ +// 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. + +// Logic shared between the Scavenger and Marker. + +#include "vm/heap/gc_shared.h" + +#include "vm/dart_api_state.h" +#include "vm/heap/scavenger.h" +#include "vm/log.h" +#include "vm/message_handler.h" +#include "vm/object.h" + +namespace dart { + +void GCLinkedLists::Clear() { +#define FOREACH(type, var) var.Clear(); + GC_LINKED_LIST(FOREACH) +#undef FOREACH +} + +bool GCLinkedLists::IsEmpty() { +#define FOREACH(type, var) \ + if (!var.IsEmpty()) { \ + return false; \ + } + GC_LINKED_LIST(FOREACH) + return true; +#undef FOREACH +} + +void GCLinkedLists::FlushInto(GCLinkedLists* to) { +#define FOREACH(type, var) var.FlushInto(&to->var); + GC_LINKED_LIST(FOREACH) +#undef FOREACH +} + +} // namespace dart diff --git a/runtime/vm/heap/gc_shared.h b/runtime/vm/heap/gc_shared.h new file mode 100644 index 000000000000..3320868a796e --- /dev/null +++ b/runtime/vm/heap/gc_shared.h @@ -0,0 +1,195 @@ +// 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. + +// Logic shared between the Scavenger and Marker. + +#ifndef RUNTIME_VM_HEAP_GC_SHARED_H_ +#define RUNTIME_VM_HEAP_GC_SHARED_H_ + +#include "vm/compiler/runtime_api.h" +#if defined(SHOULD_NOT_INCLUDE_RUNTIME) +#error "Should not include runtime" +#endif + +#include "vm/dart_api_state.h" +#include "vm/heap/scavenger.h" +#include "vm/log.h" +#include "vm/message_handler.h" +#include "vm/object.h" + +namespace dart { + +// These object types have a linked list chaining all pending objects when +// processing these in the GC. +// The field should not be visited by pointer visitors. +// The field should only be set during a GC. +// +// Macro params: +// - type +// - variable name +#define GC_LINKED_LIST(V) \ + V(WeakProperty, weak_properties) \ + V(WeakReference, weak_references) \ + V(FinalizerEntry, finalizer_entries) + +template +struct GCLinkedList { + public: + void Enqueue(PtrType ptr) { + ptr->untag()->next_seen_by_gc_ = head; + if (head == Type::null()) { + tail = ptr; + } + head = ptr; + } + + void FlushInto(GCLinkedList* to) { + if (to->head == Type::null()) { + ASSERT(to->tail == Type::null()); + to->head = head; + to->tail = tail; + } else { + ASSERT(to->tail != Type::null()); + ASSERT(to->tail->untag()->next_seen_by_gc() == Type::null()); + to->tail->untag()->next_seen_by_gc_ = head; + to->tail = tail; + } + Clear(); + } + + PtrType Clear() { + PtrType return_value = head; + head = Type::null(); + tail = Type::null(); + return return_value; + } + + bool IsEmpty() { return head == Type::null() && tail == Type::null(); } + + private: + PtrType head = Type::null(); + PtrType tail = Type::null(); +}; + +struct GCLinkedLists { + public: + void Clear(); + bool IsEmpty(); + void FlushInto(GCLinkedLists* to); + +#define FOREACH(type, var) GCLinkedList var; + GC_LINKED_LIST(FOREACH) +#undef FOREACH +}; + +#ifdef DEBUG +#define TRACE_FINALIZER(format, ...) \ + if (FLAG_trace_finalizers) { \ + THR_Print("%s %p " format "\n", visitor->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.Clear(); + 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/heap_sources.gni b/runtime/vm/heap/heap_sources.gni index de6d25ecfe14..a8e8d995acd6 100644 --- a/runtime/vm/heap/heap_sources.gni +++ b/runtime/vm/heap/heap_sources.gni @@ -11,6 +11,8 @@ heap_sources = [ "compactor.h", "freelist.cc", "freelist.h", + "gc_shared.cc", + "gc_shared.h", "heap.cc", "heap.h", "marker.cc", diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc index 330981502fa1..f760b67cfc89 100644 --- a/runtime/vm/heap/marker.cc +++ b/runtime/vm/heap/marker.cc @@ -4,9 +4,12 @@ #include "vm/heap/marker.h" +#include "platform/assert.h" #include "platform/atomic.h" #include "vm/allocation.h" #include "vm/dart_api_state.h" +#include "vm/flags.h" +#include "vm/heap/gc_shared.h" #include "vm/heap/pages.h" #include "vm/heap/pointer_block.h" #include "vm/isolate.h" @@ -14,10 +17,12 @@ #include "vm/object_id_ring.h" #include "vm/raw_object.h" #include "vm/stack_frame.h" +#include "vm/tagged_pointer.h" #include "vm/thread_barrier.h" #include "vm/thread_pool.h" #include "vm/thread_registry.h" #include "vm/timeline.h" +#include "vm/token.h" #include "vm/visitor.h" namespace dart { @@ -34,34 +39,35 @@ class MarkingVisitorBase : public ObjectPointerVisitor { page_space_(page_space), work_list_(marking_stack), deferred_work_list_(deferred_marking_stack), - delayed_weak_properties_(WeakProperty::null()), - delayed_weak_properties_tail_(WeakProperty::null()), - delayed_weak_references_(WeakReference::null()), - delayed_weak_references_tail_(WeakReference::null()), marked_bytes_(0), marked_micros_(0) { ASSERT(thread_->isolate_group() == isolate_group); } - ~MarkingVisitorBase() { - ASSERT(delayed_weak_properties_ == WeakProperty::null()); - ASSERT(delayed_weak_references_ == WeakReference::null()); - } + ~MarkingVisitorBase() { ASSERT(delayed_.IsEmpty()); } + +#ifdef DEBUG + const char* kName = "Marker"; +#endif uintptr_t marked_bytes() const { return marked_bytes_; } int64_t marked_micros() const { return marked_micros_; } void AddMicros(int64_t micros) { marked_micros_ += micros; } + bool IsMarked(ObjectPtr raw) { + ASSERT(raw->IsHeapObject()); + ASSERT(raw->IsOldObject()); + return raw->untag()->IsMarked(); + } + bool ProcessPendingWeakProperties() { bool more_to_mark = false; - WeakPropertyPtr cur_weak = delayed_weak_properties_; - delayed_weak_properties_tail_ = delayed_weak_properties_ = - WeakProperty::null(); + WeakPropertyPtr cur_weak = delayed_.weak_properties.Clear(); while (cur_weak != WeakProperty::null()) { WeakPropertyPtr next_weak = - cur_weak->untag()->next_.Decompress(cur_weak->heap_base()); + cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base()); ObjectPtr raw_key = cur_weak->untag()->key(); // Reset the next pointer in the weak property. - cur_weak->untag()->next_ = WeakProperty::null(); + cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null(); if (raw_key->IsSmiOrNewObject() || raw_key->untag()->IsMarked()) { ObjectPtr raw_val = cur_weak->untag()->value(); if (!raw_val->IsSmiOrNewObject() && !raw_val->untag()->IsMarked()) { @@ -73,7 +79,8 @@ class MarkingVisitorBase : public ObjectPointerVisitor { cur_weak->untag()->VisitPointersNonvirtual(this); } else { // Requeue this weak property to be handled later. - EnqueueWeakProperty(cur_weak); + ASSERT(IsMarked(cur_weak)); + delayed_.weak_properties.Enqueue(cur_weak); } // Advance to next weak property in the queue. cur_weak = next_weak; @@ -125,6 +132,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); } @@ -182,34 +192,6 @@ class MarkingVisitorBase : public ObjectPointerVisitor { } } - void EnqueueWeakProperty(WeakPropertyPtr raw_weak) { - ASSERT(raw_weak->IsHeapObject()); - ASSERT(raw_weak->IsOldObject()); - ASSERT(raw_weak->IsWeakProperty()); - ASSERT(raw_weak->untag()->IsMarked()); - ASSERT(raw_weak->untag()->next_ == - CompressedWeakPropertyPtr(WeakProperty::null())); - raw_weak->untag()->next_ = delayed_weak_properties_; - if (delayed_weak_properties_ == WeakProperty::null()) { - delayed_weak_properties_tail_ = raw_weak; - } - delayed_weak_properties_ = raw_weak; - } - - void EnqueueWeakReference(WeakReferencePtr raw_weak) { - ASSERT(raw_weak->IsHeapObject()); - ASSERT(raw_weak->IsOldObject()); - ASSERT(raw_weak->IsWeakReference()); - ASSERT(raw_weak->untag()->IsMarked()); - ASSERT(raw_weak->untag()->next_ == - CompressedWeakReferencePtr(WeakReference::null())); - raw_weak->untag()->next_ = delayed_weak_references_; - if (delayed_weak_references_ == WeakReference::null()) { - delayed_weak_references_tail_ = raw_weak; - } - delayed_weak_references_ = raw_weak; - } - intptr_t ProcessWeakProperty(WeakPropertyPtr raw_weak) { // The fate of the weak property is determined by its key. ObjectPtr raw_key = @@ -218,7 +200,8 @@ class MarkingVisitorBase : public ObjectPointerVisitor { if (raw_key->IsHeapObject() && raw_key->IsOldObject() && !raw_key->untag()->IsMarked()) { // Key was white. Enqueue the weak property. - EnqueueWeakProperty(raw_weak); + ASSERT(IsMarked(raw_weak)); + delayed_.weak_properties.Enqueue(raw_weak); return raw_weak->untag()->HeapSize(); } // Key is gray or black. Make the weak property black. @@ -235,7 +218,8 @@ class MarkingVisitorBase : public ObjectPointerVisitor { !raw_target->untag()->IsMarked()) { // Target was white. Enqueue the weak reference. It is potentially dead. // It might still be made alive by weak properties in next rounds. - EnqueueWeakReference(raw_weak); + ASSERT(IsMarked(raw_weak)); + delayed_.weak_references.Enqueue(raw_weak); } // Always visit the type argument. ObjectPtr raw_type_arguments = @@ -245,6 +229,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) { @@ -279,15 +274,15 @@ class MarkingVisitorBase : public ObjectPointerVisitor { void FinalizeMarking() { work_list_.Finalize(); deferred_work_list_.Finalize(); + MournFinalized(this); } void MournWeakProperties() { - WeakPropertyPtr cur_weak = delayed_weak_properties_; - delayed_weak_properties_ = WeakProperty::null(); + WeakPropertyPtr cur_weak = delayed_.weak_properties.Clear(); while (cur_weak != WeakProperty::null()) { WeakPropertyPtr next_weak = - cur_weak->untag()->next_.Decompress(cur_weak->heap_base()); - cur_weak->untag()->next_ = WeakProperty::null(); + cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base()); + cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null(); RELEASE_ASSERT(!cur_weak->untag()->key()->untag()->IsMarked()); WeakProperty::Clear(cur_weak); cur_weak = next_weak; @@ -295,72 +290,58 @@ class MarkingVisitorBase : public ObjectPointerVisitor { } void MournWeakReferences() { - WeakReferencePtr cur_weak = delayed_weak_references_; - delayed_weak_references_ = WeakReference::null(); + WeakReferencePtr cur_weak = delayed_.weak_references.Clear(); while (cur_weak != WeakReference::null()) { WeakReferencePtr next_weak = - cur_weak->untag()->next_.Decompress(cur_weak->heap_base()); - cur_weak->untag()->next_ = WeakReference::null(); + cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base()); + cur_weak->untag()->next_seen_by_gc_ = WeakReference::null(); + // If we did not mark the target through a weak property in a later round, // then the target is dead and we should clear it. - if (!cur_weak->untag()->target()->untag()->IsMarked()) { - WeakReference::Clear(cur_weak); - } + SetNullIfCollected(cur_weak->heap_base(), &cur_weak->untag()->target_); + cur_weak = next_weak; } } + // Returns whether the object referred to in `ptr_address` was GCed this GC. + static bool SetNullIfCollected(uword heap_base, + CompressedObjectPtr* ptr_address) { + ObjectPtr raw = ptr_address->Decompress(heap_base); + if (raw.IsRawNull()) { + // Object already null before this GC. + return false; + } + if (raw.IsNewObject()) { + // Object not touched during this GC. + return false; + } + if (raw->untag()->IsMarked()) { + return false; + } + *ptr_address = Object::null(); + return true; + } + bool WaitForWork(RelaxedAtomic* num_busy) { return work_list_.WaitForWork(num_busy); } - void Flush(WeakPropertyPtr* weak_properties_head, - WeakPropertyPtr* weak_properties_tail, - WeakReferencePtr* weak_references_head, - WeakReferencePtr* weak_references_tail) { + void Flush(GCLinkedLists* global_list) { work_list_.Flush(); deferred_work_list_.Flush(); - - if (*weak_properties_head == WeakProperty::null()) { - *weak_properties_head = delayed_weak_properties_; - *weak_properties_tail = delayed_weak_properties_tail_; - } else { - (*weak_properties_tail)->untag()->next_ = delayed_weak_properties_; - *weak_properties_tail = delayed_weak_properties_tail_; - } - delayed_weak_properties_tail_ = delayed_weak_properties_ = - WeakProperty::null(); - - if (*weak_references_head == WeakReference::null()) { - *weak_references_head = delayed_weak_references_; - *weak_references_tail = delayed_weak_references_tail_; - } else { - (*weak_references_tail)->untag()->next_ = delayed_weak_references_; - *weak_references_tail = delayed_weak_references_tail_; - } - delayed_weak_references_tail_ = delayed_weak_references_ = - WeakReference::null(); + delayed_.FlushInto(global_list); } - void Adopt(WeakPropertyPtr weak_properties_head, - WeakPropertyPtr weak_properties_tail, - WeakReferencePtr weak_references_head, - WeakReferencePtr weak_references_tail) { - ASSERT(delayed_weak_properties_ == WeakProperty::null()); - ASSERT(delayed_weak_properties_tail_ == WeakProperty::null()); - ASSERT(delayed_weak_references_ == WeakReference::null()); - ASSERT(delayed_weak_references_tail_ == WeakReference::null()); - delayed_weak_properties_ = weak_properties_head; - delayed_weak_properties_tail_ = weak_properties_tail; - delayed_weak_references_ = weak_references_head; - delayed_weak_references_tail_ = weak_references_tail; + void Adopt(GCLinkedLists* other) { + ASSERT(delayed_.IsEmpty()); + other->FlushInto(&delayed_); } void AbandonWork() { work_list_.AbandonWork(); deferred_work_list_.AbandonWork(); - delayed_weak_properties_ = WeakProperty::null(); - delayed_weak_references_ = WeakReference::null(); + delayed_.Clear(); } private: @@ -430,13 +411,13 @@ class MarkingVisitorBase : public ObjectPointerVisitor { PageSpace* page_space_; MarkerWorkList work_list_; MarkerWorkList deferred_work_list_; - WeakPropertyPtr delayed_weak_properties_; - WeakPropertyPtr delayed_weak_properties_tail_; - WeakReferencePtr delayed_weak_references_; - WeakReferencePtr delayed_weak_references_tail_; + GCLinkedLists delayed_; uintptr_t marked_bytes_; int64_t marked_micros_; + template + friend void MournFinalized(GCVisitorType* visitor); + DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitorBase); }; @@ -746,6 +727,9 @@ 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(); visitor_->AddMicros(stop - start); @@ -984,6 +968,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(); @@ -998,10 +983,7 @@ void GCMarker::MarkObjects(PageSpace* page_space) { RelaxedAtomic num_busy = 0; // Phase 1: Iterate over roots and drain marking stack in tasks. - WeakPropertyPtr weak_properties_head = WeakProperty::null(); - WeakPropertyPtr weak_properties_tail = WeakProperty::null(); - WeakReferencePtr weak_references_head = WeakReference::null(); - WeakReferencePtr weak_references_tail = WeakReference::null(); + GCLinkedLists global_list; for (intptr_t i = 0; i < num_tasks; ++i) { SyncMarkingVisitor* visitor = visitors_[i]; @@ -1013,12 +995,12 @@ void GCMarker::MarkObjects(PageSpace* page_space) { &marking_stack_, &deferred_marking_stack_); visitors_[i] = visitor; } + // Move all work from local blocks to the global list. Any given // visitor might not get to run if it fails to reach TryEnter soon // enough, and we must fail to visit objects but they're sitting in // such a visitor's local blocks. - visitor->Flush(&weak_properties_head, &weak_properties_tail, - &weak_references_head, &weak_references_tail); + visitor->Flush(&global_list); // Need to move weak property list too. if (i < (num_tasks - 1)) { @@ -1029,8 +1011,7 @@ void GCMarker::MarkObjects(PageSpace* page_space) { ASSERT(result); } else { // Last worker is the main thread. - visitor->Adopt(weak_properties_head, weak_properties_tail, - weak_references_head, weak_references_tail); + visitor->Adopt(&global_list); ParallelMarkTask task(this, isolate_group_, &marking_stack_, barrier, visitor, &num_busy); task.RunEnteredIsolateGroup(); diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc index e8b433a03a0b..e7dcfc14115d 100644 --- a/runtime/vm/heap/scavenger.cc +++ b/runtime/vm/heap/scavenger.cc @@ -4,11 +4,14 @@ #include "vm/heap/scavenger.h" +#include "platform/assert.h" #include "platform/leak_sanitizer.h" +#include "vm/class_id.h" #include "vm/dart.h" #include "vm/dart_api_state.h" #include "vm/flag_list.h" #include "vm/heap/become.h" +#include "vm/heap/gc_shared.h" #include "vm/heap/pages.h" #include "vm/heap/pointer_block.h" #include "vm/heap/safepoint.h" @@ -20,6 +23,7 @@ #include "vm/object.h" #include "vm/object_id_ring.h" #include "vm/object_set.h" +#include "vm/port.h" #include "vm/stack_frame.h" #include "vm/thread_barrier.h" #include "vm/thread_registry.h" @@ -131,13 +135,12 @@ class ScavengerVisitorBase : public ObjectPointerVisitor { freelist_(freelist), bytes_promoted_(0), visiting_old_object_(nullptr), - promoted_list_(promotion_stack), - delayed_weak_properties_(WeakProperty::null()), - delayed_weak_references_(WeakReference::null()) {} - ~ScavengerVisitorBase() { - ASSERT(delayed_weak_properties_ == WeakProperty::null()); - ASSERT(delayed_weak_references_ == WeakReference::null()); - } + promoted_list_(promotion_stack) {} + ~ScavengerVisitorBase() { ASSERT(delayed_.IsEmpty()); } + +#ifdef DEBUG + const char* kName = "Scavenger"; +#endif virtual void VisitTypedDataViewPointers(TypedDataViewPtr view, CompressedObjectPtr* first, @@ -299,6 +302,7 @@ class ScavengerVisitorBase : public ObjectPointerVisitor { MournWeakProperties(); MournOrUpdateWeakReferences(); + MournFinalized(this); } page_space_->ReleaseLock(freelist_); thread_ = nullptr; @@ -308,13 +312,15 @@ class ScavengerVisitorBase : public ObjectPointerVisitor { void AbandonWork() { promoted_list_.AbandonWork(); - delayed_weak_properties_ = WeakProperty::null(); - delayed_weak_references_ = WeakReference::null(); + delayed_.Clear(); } NewPage* head() const { return head_; } NewPage* tail() const { return tail_; } + static bool SetNullIfCollected(uword heap_base, + CompressedObjectPtr* ptr_address); + private: void UpdateStoreBuffer(ObjectPtr obj) { ASSERT(obj->IsHeapObject()); @@ -511,8 +517,13 @@ class ScavengerVisitorBase : public ObjectPointerVisitor { inline void ProcessToSpace(); DART_FORCE_INLINE intptr_t ProcessCopied(ObjectPtr raw_obj); inline void ProcessPromotedList(); - inline void EnqueueWeakProperty(WeakPropertyPtr raw_weak); - inline void EnqueueWeakReference(WeakReferencePtr raw_weak); + + bool IsNotForwarding(ObjectPtr raw) { + ASSERT(raw->IsHeapObject()); + ASSERT(raw->IsNewObject()); + return !IsForwarding(ReadHeaderRelaxed(raw)); + } + inline void MournWeakProperties(); inline void MournOrUpdateWeakReferences(); @@ -523,15 +534,16 @@ class ScavengerVisitorBase : public ObjectPointerVisitor { FreeList* freelist_; intptr_t bytes_promoted_; ObjectPtr visiting_old_object_; - PromotionWorkList promoted_list_; - WeakPropertyPtr delayed_weak_properties_; - WeakReferencePtr delayed_weak_references_; + GCLinkedLists delayed_; NewPage* head_ = nullptr; NewPage* tail_ = nullptr; // Allocating from here. NewPage* scan_ = nullptr; // Resolving from here. + template + friend void MournFinalized(GCVisitorType* visitor); + DISALLOW_COPY_AND_ASSIGN(ScavengerVisitorBase); }; @@ -1323,11 +1335,10 @@ void ScavengerVisitorBase::ProcessWeakProperties() { // Finished this round of scavenging. Process the pending weak properties // for which the keys have become reachable. Potentially this adds more // objects to the to space. - WeakPropertyPtr cur_weak = delayed_weak_properties_; - delayed_weak_properties_ = WeakProperty::null(); + WeakPropertyPtr cur_weak = delayed_.weak_properties.Clear(); while (cur_weak != WeakProperty::null()) { WeakPropertyPtr next_weak = - cur_weak->untag()->next_.Decompress(cur_weak->heap_base()); + cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base()); // Promoted weak properties are not enqueued. So we can guarantee that // we do not need to think about store barriers here. ASSERT(cur_weak->IsNewObject()); @@ -1341,11 +1352,12 @@ void ScavengerVisitorBase::ProcessWeakProperties() { ASSERT(from_->Contains(raw_addr)); uword header = ReadHeaderRelaxed(raw_key); // Reset the next pointer in the weak property. - cur_weak->untag()->next_ = WeakProperty::null(); + cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null(); if (IsForwarding(header)) { cur_weak->untag()->VisitPointersNonvirtual(this); } else { - EnqueueWeakProperty(cur_weak); + ASSERT(IsNotForwarding(cur_weak)); + delayed_.weak_properties.Enqueue(cur_weak); } // Advance to next weak property in the queue. cur_weak = next_weak; @@ -1377,38 +1389,6 @@ void Scavenger::UpdateMaxHeapUsage() { isolate_group->GetHeapNewUsedMaxMetric()->SetValue(UsedInWords() * kWordSize); } -template -void ScavengerVisitorBase::EnqueueWeakProperty( - WeakPropertyPtr raw_weak) { - ASSERT(raw_weak->IsHeapObject()); - ASSERT(raw_weak->IsNewObject()); - ASSERT(raw_weak->IsWeakProperty()); -#if defined(DEBUG) - uword header = ReadHeaderRelaxed(raw_weak); - ASSERT(!IsForwarding(header)); -#endif // defined(DEBUG) - ASSERT(raw_weak->untag()->next_ == - CompressedWeakPropertyPtr(WeakProperty::null())); - raw_weak->untag()->next_ = delayed_weak_properties_; - delayed_weak_properties_ = raw_weak; -} - -template -void ScavengerVisitorBase::EnqueueWeakReference( - WeakReferencePtr raw_weak) { - ASSERT(raw_weak->IsHeapObject()); - ASSERT(raw_weak->IsNewObject()); - ASSERT(raw_weak->IsWeakReference()); -#if defined(DEBUG) - uword header = ReadHeaderRelaxed(raw_weak); - ASSERT(!IsForwarding(header)); -#endif // defined(DEBUG) - ASSERT(raw_weak->untag()->next_ == - CompressedWeakReferencePtr(WeakReference::null())); - raw_weak->untag()->next_ = delayed_weak_references_; - delayed_weak_references_ = raw_weak; -} - template intptr_t ScavengerVisitorBase::ProcessCopied(ObjectPtr raw_obj) { intptr_t class_id = raw_obj->GetClassId(); @@ -1420,7 +1400,8 @@ intptr_t ScavengerVisitorBase::ProcessCopied(ObjectPtr raw_obj) { uword header = ReadHeaderRelaxed(raw_key); if (!IsForwarding(header)) { // Key is white. Enqueue the weak property. - EnqueueWeakProperty(raw_weak); + ASSERT(IsNotForwarding(raw_weak)); + delayed_.weak_properties.Enqueue(raw_weak); return raw_weak->untag()->HeapSize(); } } @@ -1434,7 +1415,8 @@ intptr_t ScavengerVisitorBase::ProcessCopied(ObjectPtr raw_obj) { if (!IsForwarding(header)) { // Target is white. Enqueue the weak reference. Always visit type // arguments. - EnqueueWeakReference(raw_weak); + ASSERT(IsNotForwarding(raw_weak)); + delayed_.weak_references.Enqueue(raw_weak); #if !defined(DART_COMPRESSED_POINTERS) ScavengePointer(&raw_weak->untag()->type_arguments_); #else @@ -1444,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); } @@ -1507,13 +1504,12 @@ void ScavengerVisitorBase::MournWeakProperties() { // The queued weak properties at this point do not refer to reachable keys, // so we clear their key and value fields. - WeakPropertyPtr cur_weak = delayed_weak_properties_; - delayed_weak_properties_ = WeakProperty::null(); + WeakPropertyPtr cur_weak = delayed_.weak_properties.Clear(); while (cur_weak != WeakProperty::null()) { WeakPropertyPtr next_weak = - cur_weak->untag()->next_.Decompress(cur_weak->heap_base()); + cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base()); // Reset the next pointer in the weak property. - cur_weak->untag()->next_ = WeakProperty::null(); + cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null(); #if defined(DEBUG) ObjectPtr raw_key = cur_weak->untag()->key(); @@ -1537,31 +1533,48 @@ void ScavengerVisitorBase::MournOrUpdateWeakReferences() { // The queued weak references at this point either should have their target // updated or should be cleared. - WeakReferencePtr cur_weak = delayed_weak_references_; - delayed_weak_references_ = WeakReference::null(); + WeakReferencePtr cur_weak = delayed_.weak_references.Clear(); while (cur_weak != WeakReference::null()) { WeakReferencePtr next_weak = - cur_weak->untag()->next_.Decompress(cur_weak->heap_base()); + cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base()); // Reset the next pointer in the weak reference. - cur_weak->untag()->next_ = WeakReference::null(); + cur_weak->untag()->next_seen_by_gc_ = WeakReference::null(); - ObjectPtr raw_target = cur_weak->untag()->target(); - uword raw_addr = UntaggedObject::ToAddr(raw_target); - uword header = *reinterpret_cast(raw_addr); - if (IsForwarding(header)) { - // Get the new location of the object. - cur_weak->untag()->target_ = ForwardedObj(header); - } else { - ASSERT(raw_target->IsHeapObject()); - ASSERT(raw_target->IsNewObject()); - WeakReference::Clear(cur_weak); - } + // If we did not mark the target through a weak property in a later round, + // then the target is dead and we should clear it. + SetNullIfCollected(cur_weak->heap_base(), &cur_weak->untag()->target_); // Advance to next weak reference in the queue. cur_weak = next_weak; } } +// Returns whether the object referred to in `ptr_address` was GCed this GC. +template +bool ScavengerVisitorBase::SetNullIfCollected( + uword heap_base, + CompressedObjectPtr* ptr_address) { + ObjectPtr raw = ptr_address->Decompress(heap_base); + if (raw.IsRawNull()) { + // Object already null before this GC. + return false; + } + if (raw.IsOldObject()) { + // Object not touched during this GC. + return false; + } + uword header = *reinterpret_cast(UntaggedObject::ToAddr(raw)); + if (IsForwarding(header)) { + // Get the new location of the object. + *ptr_address = ForwardedObj(header); + return false; + } + ASSERT(raw->IsHeapObject()); + ASSERT(raw->IsNewObject()); + *ptr_address = Object::null(); + return true; +} + void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { ASSERT(Thread::Current()->IsAtSafepoint() || (Thread::Current()->task_kind() == Thread::kMarkerTask) || diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc index 2f8c8cc4ae67..1190825781df 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 e714838538f2..bd1e9fb72eb3 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 0b1eb106be50..f5e8986347eb 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 0f2d2e4c2321..d9d06801af96 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 4c82bdfaf8ee..46064a9484e0 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 715641be1135..228c745a92ee 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 22de126a5194..a5e5d7aebfe7 100644 --- a/runtime/vm/message_snapshot.cc +++ b/runtime/vm/message_snapshot.cc @@ -3916,6 +3916,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 fe3334708755..6a96faf183d5 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. @@ -2341,6 +2341,14 @@ 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); + 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()); @@ -2353,6 +2361,10 @@ 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); + 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( @@ -2520,6 +2532,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); @@ -26005,14 +26021,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 668b2010ff8d..cb4eb7d02ddd 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -3177,7 +3177,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; @@ -5920,9 +5942,7 @@ class CompressedStackMaps : public Object { static intptr_t UnroundedSize(intptr_t length) { return HeaderSize() + length; } - static intptr_t InstanceSize() { - return 0; - } + static intptr_t InstanceSize() { return 0; } static intptr_t InstanceSize(intptr_t length) { return RoundedAllocationSize(UnroundedSize(length)); } @@ -11980,7 +12000,7 @@ class WeakProperty : public Instance { } static void Clear(WeakPropertyPtr raw_weak) { - ASSERT(raw_weak->untag()->next_ == + ASSERT(raw_weak->untag()->next_seen_by_gc_ == CompressedWeakPropertyPtr(WeakProperty::null())); // This action is performed by the GC. No barrier. raw_weak->untag()->key_ = Object::null(); @@ -12012,15 +12032,109 @@ class WeakReference : public Instance { return RoundedAllocationSize(sizeof(UntaggedWeakReference)); } - static void Clear(WeakReferencePtr raw_weak) { - ASSERT(raw_weak->untag()->next_ == - 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(WeakReference, Instance); + 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: + 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 638febe11f52..ede344dac694 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) @@ -1362,8 +1366,8 @@ class ObjectCopy : public Base { Object::null()); // To satisfy some ASSERT()s in GC we'll use Object:null() explicitly here. Base::StoreCompressedPointerNoBarrier( - Types::GetWeakPropertyPtr(to), OFFSET_OF(UntaggedWeakProperty, next_), - Object::null()); + Types::GetWeakPropertyPtr(to), + OFFSET_OF(UntaggedWeakProperty, next_seen_by_gc_), Object::null()); Base::EnqueueWeakProperty(from); } @@ -1380,8 +1384,8 @@ class ObjectCopy : public Base { from, to, OFFSET_OF(UntaggedWeakReference, type_arguments_)); // To satisfy some ASSERT()s in GC we'll use Object:null() explicitly here. Base::StoreCompressedPointerNoBarrier( - Types::GetWeakReferencePtr(to), OFFSET_OF(UntaggedWeakReference, next_), - Object::null()); + Types::GetWeakReferencePtr(to), + OFFSET_OF(UntaggedWeakReference, next_seen_by_gc_), Object::null()); Base::EnqueueWeakReference(from); } @@ -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 210f508899fe..59245d6d023e 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 23f9b4dd4e30..bdbc4a1a9ff4 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 f86b8c5b6db4..26bce6314972 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 237ffb05f8c2..8a647cbe1afe 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 eb83d6848155..82e1bf8892a9 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 5a084c52d50d..2142cd44d5b5 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)) @@ -3265,7 +3279,7 @@ class UntaggedRegExp : public UntaggedInstance { class UntaggedWeakProperty : public UntaggedInstance { RAW_HEAP_OBJECT_IMPLEMENTATION(WeakProperty); - COMPRESSED_POINTER_FIELD(ObjectPtr, key) + COMPRESSED_POINTER_FIELD(ObjectPtr, key) // Weak reference. VISIT_FROM(key) COMPRESSED_POINTER_FIELD(ObjectPtr, value) VISIT_TO(value) @@ -3273,8 +3287,10 @@ class UntaggedWeakProperty : public UntaggedInstance { // Linked list is chaining all pending weak properties. Not visited by // pointer visitors. - CompressedWeakPropertyPtr next_; + COMPRESSED_POINTER_FIELD(WeakPropertyPtr, next_seen_by_gc) + template + friend struct GCLinkedList; friend class GCMarker; template friend class MarkingVisitorBase; @@ -3288,7 +3304,7 @@ class UntaggedWeakProperty : public UntaggedInstance { class UntaggedWeakReference : public UntaggedInstance { RAW_HEAP_OBJECT_IMPLEMENTATION(WeakReference); - COMPRESSED_POINTER_FIELD(ObjectPtr, target) + COMPRESSED_POINTER_FIELD(ObjectPtr, target) // Weak reference. VISIT_FROM(target) COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, type_arguments) VISIT_TO(type_arguments) @@ -3296,8 +3312,10 @@ class UntaggedWeakReference : public UntaggedInstance { // Linked list is chaining all pending weak properties. Not visited by // pointer visitors. - CompressedWeakReferencePtr next_; + COMPRESSED_POINTER_FIELD(WeakReferencePtr, next_seen_by_gc) + template + friend struct GCLinkedList; friend class GCMarker; template friend class MarkingVisitorBase; @@ -3308,6 +3326,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 struct 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 77840416ffb3..7953a1fc47b6 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 0f53fe793c70..5a0b99f20e87 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 78b3bab372f5..79ff4aa14d44 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 cf34b7fb2448..fd5bd93ae83c 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 aec537bf6941..a9db8536c6a0 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 4c0fa92eb6e9..547835cf5cd8 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 01ef31c1eab1..3c8f96888c59 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 96ef3e5db71c..6b2b940f56b6 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`