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