Version 2.17.0-227.0.dev
Merge commit '7dca34c23535287593595a3f570a714465556210' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9673f81..6f549dd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -116,9 +116,9 @@
Updated the Linter to `1.21.2`, which includes changes that
-- updates `depend_on_referenced_packages` to treat `flutter_gen` as a virtual
- package, not needing an explicit dependency.
-- updates `unnecessary_null_checks` and
+- updates `depend_on_referenced_packages` to treat `flutter_gen` as a virtual
+ package, not needing an explicit dependency.
+- updates `unnecessary_null_checks` and
`null_check_on_nullable_type_parameter` to handle
list/set/map literals, and `yield` and `await` expressions.
- fixes `unnecessary_null_aware_assignments` property-access
@@ -136,6 +136,13 @@
- updates `unnecessary_late` to report on variable names.
- marks `null_check_on_nullable_type_parameter` stable.
+## 2.16.2 - 2022-03-24
+
+This is a patch release that fixes a dart2js crash when building some Flutter
+web apps (issue [#47916][]).
+
+[#47916]: https://github.com/dart-lang/sdk/issues/47916
+
## 2.16.1 - 2022-02-09
This is a patch release that fixes an AOT precompiler crash when building some
diff --git a/runtime/docs/gc.md b/runtime/docs/gc.md
index 7c2fd9a..ac9696d 100644
--- a/runtime/docs/gc.md
+++ b/runtime/docs/gc.md
@@ -13,7 +13,7 @@
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 @@
## 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 @@
<instructions that cannot directly call Dart functions>
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 3d2a0f0..e2ef579 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -242,6 +242,8 @@
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 @@
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 @@
// 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 0000000..c0dfdeb
--- /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<Nonce>(callback);
+
+late String name;
+
+void main(List<String> 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 0000000..ba5216f
--- /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<void> 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<void> 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<void> 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 0000000..5750bf4
--- /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 = <Nonce>{};
+
+void callback(Nonce token) {
+ print('Running finalizer: token: $token');
+ finalizerTokens.add(token);
+}
+
+void runIsolateAttachFinalizer(Object? message) {
+ final finalizer = Finalizer<Nonce>(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<Finalizer?> 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 0000000..8000a41
--- /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 = <Nonce?>{};
+ void callback(Nonce? token) {
+ print('Running finalizer: token: $token');
+ finalizerTokens.add(token);
+ }
+
+ final finalizer = Finalizer<Nonce?>(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 0000000..a278b5d
--- /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<Nonce>(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 = <Object>{};
+ void callback(Object token) {
+ print('Running finalizer: token: $token');
+ finalizerTokens.add(token);
+ }
+
+ final finalizer = Finalizer<Nonce>(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 0000000..bcc6d9e1
--- /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<void> testFinalizerZone() async {
+ Zone? expectedZone;
+ Zone? actualZone;
+
+ final finalizer = runZoned(() {
+ expectedZone = Zone.current;
+
+ void callback(Object token) {
+ actualZone = Zone.current;
+ }
+
+ return Finalizer<Nonce>(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<void> testFinalizerException() async {
+ Object? caughtError;
+
+ final finalizer = runZonedGuarded(() {
+ void callback(Object token) {
+ throw 'uncaught!';
+ }
+
+ return Finalizer<Nonce>(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 0000000..d776098
--- /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<T>(Finalizer<T> 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<void> 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 15b330d..da365b9 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<String>("Hello world!");
@@ -55,7 +46,3 @@
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 cd24fbc..d714c56 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 @@
await testWeakProperty();
await testWeakReference();
+ await testFinalizer();
await testForbiddenClosures();
}
@@ -756,6 +757,14 @@
}
}
+ Future testFinalizer() async {
+ print('testFinalizer');
+
+ void callback(Object token) {}
+ final finalizer = Finalizer<Object>(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 0000000..58ff5bb
--- /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<Nonce>(callback);
+
+String name;
+
+void main(List<String> 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 0000000..afd09bb
--- /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<void> 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<void> 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<void> 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 0000000..7c2103d
--- /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 = <Nonce>{};
+
+void callback(Nonce token) {
+ print('Running finalizer: token: $token');
+ finalizerTokens.add(token);
+}
+
+void runIsolateAttachFinalizer(Object message) {
+ final finalizer = Finalizer<Nonce>(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<Finalizer> 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 0000000..b033c1b
--- /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 = <Nonce>{};
+ void callback(Nonce token) {
+ print('Running finalizer: token: $token');
+ finalizerTokens.add(token);
+ }
+
+ final finalizer = Finalizer<Nonce>(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 0000000..9c17461
--- /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<Nonce>(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 = <Object>{};
+ void callback(Object token) {
+ print('Running finalizer: token: $token');
+ finalizerTokens.add(token);
+ }
+
+ final finalizer = Finalizer<Nonce>(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 0000000..17646d1
--- /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<void> testFinalizerZone() async {
+ Zone expectedZone;
+ Zone actualZone;
+
+ final finalizer = runZoned(() {
+ expectedZone = Zone.current;
+
+ void callback(Object token) {
+ actualZone = Zone.current;
+ }
+
+ return Finalizer<Nonce>(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<void> testFinalizerException() async {
+ Object caughtError;
+
+ final finalizer = runZonedGuarded(() {
+ void callback(Object token) {
+ throw 'uncaught!';
+ }
+
+ return Finalizer<Nonce>(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 0000000..a82646c
--- /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<T>(Finalizer<T> 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<void> 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 8c7583d..708d540 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<String>("Hello world!");
@@ -57,7 +48,3 @@
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 1843f0c..91fd27d 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 @@
await testWeakProperty();
await testWeakReference();
+ await testFinalizer();
await testForbiddenClosures();
}
@@ -758,6 +759,14 @@
}
}
+ Future testFinalizer() async {
+ print('testFinalizer');
+
+ void callback(Object token) {}
+ final finalizer = Finalizer<Object>(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 1f5066c..8feee00 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -108,6 +108,7 @@
[ $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 @@
# These Isolate tests that use spawnURI are hence skipped on purpose.
[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
dart/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri
+dart/finalizer/finalizer_isolate_groups_run_gc_test: SkipByDesign # uses spawnUri.
dart/isolates/send_object_to_spawn_uri_isolate_test: SkipByDesign # uses spawnUri
dart/issue32950_test: SkipByDesign # uses spawnUri.
dart_2/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri
+dart_2/finalizer/finalizer_isolate_groups_run_gc_test: SkipByDesign # uses spawnUri.
dart_2/isolates/send_object_to_spawn_uri_isolate_test: SkipByDesign # uses spawnUri
dart_2/issue32950_test: SkipByDesign # uses spawnUri.
diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc
index f694613b..e2b8a40 100644
--- a/runtime/vm/app_snapshot.cc
+++ b/runtime/vm/app_snapshot.cc
@@ -5140,7 +5140,7 @@
Deserializer::InitializeHeader(property, kWeakPropertyCid,
WeakProperty::InstanceSize());
ReadFromTo(property);
- property->untag()->next_ = WeakProperty::null();
+ property->untag()->next_seen_by_gc_ = WeakProperty::null();
}
}
};
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index dc432e3..e91180e 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -267,6 +267,10 @@
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 93e1979..501c3a8 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -68,6 +68,9 @@
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 4d28937..8d01fc7 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -2797,6 +2797,16 @@
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 4a512f8..dfd04ac 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -227,6 +227,16 @@
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 ab82fe2..995ce8cf 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -53,6 +53,15 @@
// 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 @@
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 @@
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 006ea70..9abd1fd 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -818,6 +818,13 @@
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 @@
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 @@
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 @@
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 @@
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 03a18f6..2a92d6a 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -276,6 +276,12 @@
// 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 e8a7016..1676f7c 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -110,6 +110,28 @@
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 9cc619d..d9ddcb3 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -439,6 +439,10 @@
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 f502d99..11d0013 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -1045,6 +1045,34 @@
FINAL_CLASS();
};
+class FinalizerBase : public AllStatic {
+ public:
+ static word all_entries_offset();
+ static word detachments_offset();
+ static word entries_collected_offset();
+ static word isolate_offset();
+ FINAL_CLASS();
+};
+
+class Finalizer : public AllStatic {
+ public:
+ static word type_arguments_offset();
+ static word callback_offset();
+ static word InstanceSize();
+ FINAL_CLASS();
+};
+
+class FinalizerEntry : public AllStatic {
+ public:
+ static word value_offset();
+ static word detach_offset();
+ static word token_offset();
+ static word next_offset();
+ static word finalizer_offset();
+ static word InstanceSize();
+ FINAL_CLASS();
+};
+
class MirrorReference : public AllStatic {
public:
static word InstanceSize();
@@ -1242,6 +1270,7 @@
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 6f1d535..ee0e4c2 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 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 @@
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 @@
12;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 160;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116;
+ 164;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 180;
+ 184;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 104;
+ 108;
static constexpr dart::compiler::target::word OneByteString_data_offset = 12;
static constexpr dart::compiler::target::word PointerBase_data_offset = 4;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8;
@@ -436,6 +437,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 20;
static constexpr dart::compiler::target::word Type_type_state_offset = 22;
static constexpr dart::compiler::target::word Type_nullability_offset = 23;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 24;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 20;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 12;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 8;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 16;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 16;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 24;
@@ -518,6 +535,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
28;
static constexpr dart::compiler::target::word Field_InstanceSize = 60;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 88;
@@ -754,6 +773,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
40;
@@ -761,7 +781,7 @@
IsolateGroup_shared_class_table_offset = 16;
static constexpr dart::compiler::target::word
IsolateGroup_cached_class_table_table_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 80;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 88;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40;
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 24;
static constexpr dart::compiler::target::word
@@ -790,12 +810,12 @@
24;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 320;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232;
+ 328;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 360;
+ 368;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
static constexpr dart::compiler::target::word PointerBase_data_offset = 8;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -1013,6 +1033,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 40;
static constexpr dart::compiler::target::word Type_type_state_offset = 42;
static constexpr dart::compiler::target::word Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 48;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 40;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 24;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 32;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 48;
@@ -1096,6 +1132,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
48;
static constexpr dart::compiler::target::word Field_InstanceSize = 96;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 128;
@@ -1330,6 +1368,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 24;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 28;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 40;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 32;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
20;
@@ -1337,7 +1376,7 @@
IsolateGroup_shared_class_table_offset = 8;
static constexpr dart::compiler::target::word
IsolateGroup_cached_class_table_table_offset = 16;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 40;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 44;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 20;
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 12;
static constexpr dart::compiler::target::word
@@ -1366,12 +1405,12 @@
12;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 160;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116;
+ 164;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 180;
+ 184;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 104;
+ 108;
static constexpr dart::compiler::target::word OneByteString_data_offset = 12;
static constexpr dart::compiler::target::word PointerBase_data_offset = 4;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8;
@@ -1583,6 +1622,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 20;
static constexpr dart::compiler::target::word Type_type_state_offset = 22;
static constexpr dart::compiler::target::word Type_nullability_offset = 23;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 24;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 20;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 12;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 8;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 16;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 16;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 24;
@@ -1662,6 +1717,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
28;
static constexpr dart::compiler::target::word Field_InstanceSize = 60;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 88;
@@ -1898,6 +1955,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
40;
@@ -1905,7 +1963,7 @@
IsolateGroup_shared_class_table_offset = 16;
static constexpr dart::compiler::target::word
IsolateGroup_cached_class_table_table_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 80;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 88;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40;
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 24;
static constexpr dart::compiler::target::word
@@ -1934,12 +1992,12 @@
24;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 320;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232;
+ 328;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 360;
+ 368;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
static constexpr dart::compiler::target::word PointerBase_data_offset = 8;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -2157,6 +2215,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 40;
static constexpr dart::compiler::target::word Type_type_state_offset = 42;
static constexpr dart::compiler::target::word Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 48;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 40;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 24;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 32;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 48;
@@ -2241,6 +2315,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
48;
static constexpr dart::compiler::target::word Field_InstanceSize = 96;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 128;
@@ -2475,6 +2551,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
40;
@@ -2482,7 +2559,7 @@
IsolateGroup_shared_class_table_offset = 16;
static constexpr dart::compiler::target::word
IsolateGroup_cached_class_table_table_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 80;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 88;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40;
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 16;
static constexpr dart::compiler::target::word
@@ -2511,12 +2588,12 @@
24;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 320;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232;
+ 328;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 360;
+ 368;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
static constexpr dart::compiler::target::word PointerBase_data_offset = 8;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -2734,6 +2811,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 32;
static constexpr dart::compiler::target::word Type_type_state_offset = 34;
static constexpr dart::compiler::target::word Type_nullability_offset = 35;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 36;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 32;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 20;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 24;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 12;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 16;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 20;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 24;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 40;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 36;
@@ -2817,6 +2910,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
32;
static constexpr dart::compiler::target::word Field_InstanceSize = 64;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 40;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 32;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 96;
@@ -3051,6 +3146,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
40;
@@ -3058,7 +3154,7 @@
IsolateGroup_shared_class_table_offset = 16;
static constexpr dart::compiler::target::word
IsolateGroup_cached_class_table_table_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 80;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 88;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40;
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 16;
static constexpr dart::compiler::target::word
@@ -3087,12 +3183,12 @@
24;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 320;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232;
+ 328;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 360;
+ 368;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
static constexpr dart::compiler::target::word PointerBase_data_offset = 8;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -3310,6 +3406,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 32;
static constexpr dart::compiler::target::word Type_type_state_offset = 34;
static constexpr dart::compiler::target::word Type_nullability_offset = 35;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 36;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 32;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 20;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 24;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 12;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 16;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 20;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 24;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 40;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 36;
@@ -3394,6 +3506,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
32;
static constexpr dart::compiler::target::word Field_InstanceSize = 64;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 40;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 32;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 96;
@@ -3628,6 +3742,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 24;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 28;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 40;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 32;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
20;
@@ -3635,7 +3750,7 @@
IsolateGroup_shared_class_table_offset = 8;
static constexpr dart::compiler::target::word
IsolateGroup_cached_class_table_table_offset = 16;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 40;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 44;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 20;
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 12;
static constexpr dart::compiler::target::word
@@ -3664,12 +3779,12 @@
12;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 160;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116;
+ 164;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 180;
+ 184;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 104;
+ 108;
static constexpr dart::compiler::target::word OneByteString_data_offset = 12;
static constexpr dart::compiler::target::word PointerBase_data_offset = 4;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8;
@@ -3881,6 +3996,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 20;
static constexpr dart::compiler::target::word Type_type_state_offset = 22;
static constexpr dart::compiler::target::word Type_nullability_offset = 23;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 24;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 20;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 12;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 8;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 16;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 16;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 24;
@@ -3965,6 +4096,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
28;
static constexpr dart::compiler::target::word Field_InstanceSize = 60;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 88;
@@ -4201,6 +4334,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 48;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 56;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 80;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 64;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
40;
@@ -4208,7 +4342,7 @@
IsolateGroup_shared_class_table_offset = 16;
static constexpr dart::compiler::target::word
IsolateGroup_cached_class_table_table_offset = 32;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 80;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 88;
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 40;
static constexpr dart::compiler::target::word LinkedHashBase_data_offset = 24;
static constexpr dart::compiler::target::word
@@ -4237,12 +4371,12 @@
24;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 320;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232;
+ 328;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 360;
+ 368;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
static constexpr dart::compiler::target::word PointerBase_data_offset = 8;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -4460,6 +4594,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 40;
static constexpr dart::compiler::target::word Type_type_state_offset = 42;
static constexpr dart::compiler::target::word Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 48;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 40;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 24;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 32;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 48;
@@ -4544,6 +4694,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
48;
static constexpr dart::compiler::target::word Field_InstanceSize = 96;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 128;
@@ -4775,6 +4927,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 36;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
20;
@@ -4810,12 +4963,12 @@
12;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 160;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116;
+ 164;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 180;
+ 184;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 104;
+ 108;
static constexpr dart::compiler::target::word OneByteString_data_offset = 12;
static constexpr dart::compiler::target::word PointerBase_data_offset = 4;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8;
@@ -5027,6 +5180,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 20;
static constexpr dart::compiler::target::word Type_type_state_offset = 22;
static constexpr dart::compiler::target::word Type_nullability_offset = 23;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 24;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 20;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 12;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 8;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 16;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 16;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 24;
@@ -5109,6 +5278,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
28;
static constexpr dart::compiler::target::word Field_InstanceSize = 60;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 88;
@@ -5340,6 +5511,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
40;
@@ -5375,12 +5547,12 @@
24;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 320;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232;
+ 328;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 360;
+ 368;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
static constexpr dart::compiler::target::word PointerBase_data_offset = 8;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -5598,6 +5770,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 40;
static constexpr dart::compiler::target::word Type_type_state_offset = 42;
static constexpr dart::compiler::target::word Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 48;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 40;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 24;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 32;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 48;
@@ -5681,6 +5869,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
48;
static constexpr dart::compiler::target::word Field_InstanceSize = 96;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 128;
@@ -5910,6 +6100,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 36;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
20;
@@ -5945,12 +6136,12 @@
12;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 160;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116;
+ 164;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 180;
+ 184;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 104;
+ 108;
static constexpr dart::compiler::target::word OneByteString_data_offset = 12;
static constexpr dart::compiler::target::word PointerBase_data_offset = 4;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8;
@@ -6162,6 +6353,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 20;
static constexpr dart::compiler::target::word Type_type_state_offset = 22;
static constexpr dart::compiler::target::word Type_nullability_offset = 23;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 24;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 20;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 12;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 8;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 16;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 16;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 24;
@@ -6241,6 +6448,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
28;
static constexpr dart::compiler::target::word Field_InstanceSize = 60;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 88;
@@ -6472,6 +6681,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
40;
@@ -6507,12 +6717,12 @@
24;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 320;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232;
+ 328;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 360;
+ 368;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
static constexpr dart::compiler::target::word PointerBase_data_offset = 8;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -6730,6 +6940,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 40;
static constexpr dart::compiler::target::word Type_type_state_offset = 42;
static constexpr dart::compiler::target::word Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 48;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 40;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 24;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 32;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 48;
@@ -6814,6 +7040,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
48;
static constexpr dart::compiler::target::word Field_InstanceSize = 96;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 128;
@@ -7043,6 +7271,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
40;
@@ -7078,12 +7307,12 @@
24;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 320;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232;
+ 328;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 360;
+ 368;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
static constexpr dart::compiler::target::word PointerBase_data_offset = 8;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -7301,6 +7530,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 32;
static constexpr dart::compiler::target::word Type_type_state_offset = 34;
static constexpr dart::compiler::target::word Type_nullability_offset = 35;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 36;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 32;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 20;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 24;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 12;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 16;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 20;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 24;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 40;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 36;
@@ -7384,6 +7629,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
32;
static constexpr dart::compiler::target::word Field_InstanceSize = 64;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 40;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 32;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 96;
@@ -7613,6 +7860,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
40;
@@ -7648,12 +7896,12 @@
24;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 320;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232;
+ 328;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 360;
+ 368;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
static constexpr dart::compiler::target::word PointerBase_data_offset = 8;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -7871,6 +8119,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 32;
static constexpr dart::compiler::target::word Type_type_state_offset = 34;
static constexpr dart::compiler::target::word Type_nullability_offset = 35;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 36;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 32;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 20;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 24;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 12;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 16;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 20;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 24;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 40;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 36;
@@ -7955,6 +8219,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
32;
static constexpr dart::compiler::target::word Field_InstanceSize = 64;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 40;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 32;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 96;
@@ -8184,6 +8450,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 36;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
20;
@@ -8219,12 +8486,12 @@
12;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 160;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 116;
+ 164;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 120;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 180;
+ 184;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 104;
+ 108;
static constexpr dart::compiler::target::word OneByteString_data_offset = 12;
static constexpr dart::compiler::target::word PointerBase_data_offset = 4;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8;
@@ -8436,6 +8703,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 20;
static constexpr dart::compiler::target::word Type_type_state_offset = 22;
static constexpr dart::compiler::target::word Type_nullability_offset = 23;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 24;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 20;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 12;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 8;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 16;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 4;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 12;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 16;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 20;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 24;
@@ -8520,6 +8803,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
28;
static constexpr dart::compiler::target::word Field_InstanceSize = 60;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 28;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 28;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 88;
@@ -8751,6 +9036,7 @@
static constexpr dart::compiler::target::word Int32x4_value_offset = 8;
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
+static constexpr dart::compiler::target::word Isolate_finalizers_offset = 72;
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
static constexpr dart::compiler::target::word IsolateGroup_object_store_offset =
40;
@@ -8786,12 +9072,12 @@
24;
static constexpr dart::compiler::target::word NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word ObjectStore_double_type_offset =
- 320;
-static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 232;
+ 328;
+static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 240;
static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
- 360;
+ 368;
static constexpr dart::compiler::target::word ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
static constexpr dart::compiler::target::word PointerBase_data_offset = 8;
static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -9009,6 +9295,22 @@
static constexpr dart::compiler::target::word Type_type_class_id_offset = 40;
static constexpr dart::compiler::target::word Type_type_state_offset = 42;
static constexpr dart::compiler::target::word Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word Finalizer_type_arguments_offset =
+ 48;
+static constexpr dart::compiler::target::word Finalizer_callback_offset = 40;
+static constexpr dart::compiler::target::word FinalizerBase_all_entries_offset =
+ 24;
+static constexpr dart::compiler::target::word FinalizerBase_detachments_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word FinalizerBase_isolate_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_value_offset = 8;
+static constexpr dart::compiler::target::word FinalizerEntry_detach_offset = 16;
+static constexpr dart::compiler::target::word FinalizerEntry_token_offset = 24;
+static constexpr dart::compiler::target::word FinalizerEntry_finalizer_offset =
+ 32;
+static constexpr dart::compiler::target::word FinalizerEntry_next_offset = 40;
static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
FunctionType_named_parameter_names_offset = 48;
@@ -9093,6 +9395,8 @@
static constexpr dart::compiler::target::word FfiTrampolineData_InstanceSize =
48;
static constexpr dart::compiler::target::word Field_InstanceSize = 96;
+static constexpr dart::compiler::target::word Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word FinalizerEntry_InstanceSize = 56;
static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word Function_InstanceSize = 128;
@@ -9345,6 +9649,8 @@
24;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
28;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 40;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
32;
static constexpr dart::compiler::target::word
@@ -9354,7 +9660,7 @@
static constexpr dart::compiler::target::word
AOT_IsolateGroup_cached_class_table_table_offset = 16;
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
- 40;
+ 44;
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 20;
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
12;
@@ -9389,13 +9695,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 160;
+ AOT_ObjectStore_double_type_offset = 164;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 116;
+ 120;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 180;
+ AOT_ObjectStore_string_type_offset = 184;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 104;
+ 108;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
12;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 4;
@@ -9626,6 +9932,28 @@
20;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 22;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 23;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 24;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 20;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 12;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 8;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 16;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 4;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 4;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 12;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 16;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 20;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 24;
@@ -9720,6 +10048,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 28;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 28;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 28;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44;
@@ -9982,6 +10313,8 @@
48;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
56;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 80;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
64;
static constexpr dart::compiler::target::word
@@ -9991,7 +10324,7 @@
static constexpr dart::compiler::target::word
AOT_IsolateGroup_cached_class_table_table_offset = 32;
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
- 80;
+ 88;
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40;
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
24;
@@ -10026,13 +10359,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 320;
+ AOT_ObjectStore_double_type_offset = 328;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 232;
+ 240;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 360;
+ AOT_ObjectStore_string_type_offset = 368;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
16;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8;
@@ -10264,6 +10597,28 @@
40;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 48;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 40;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 16;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 40;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 48;
@@ -10360,6 +10715,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 56;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80;
@@ -10625,6 +10983,8 @@
48;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
56;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 80;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
64;
static constexpr dart::compiler::target::word
@@ -10634,7 +10994,7 @@
static constexpr dart::compiler::target::word
AOT_IsolateGroup_cached_class_table_table_offset = 32;
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
- 80;
+ 88;
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40;
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
24;
@@ -10669,13 +11029,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 320;
+ AOT_ObjectStore_double_type_offset = 328;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 232;
+ 240;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 360;
+ AOT_ObjectStore_string_type_offset = 368;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
16;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8;
@@ -10907,6 +11267,28 @@
40;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 48;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 40;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 16;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 40;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 48;
@@ -11004,6 +11386,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 56;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80;
@@ -11265,6 +11650,8 @@
48;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
56;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 80;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
64;
static constexpr dart::compiler::target::word
@@ -11274,7 +11661,7 @@
static constexpr dart::compiler::target::word
AOT_IsolateGroup_cached_class_table_table_offset = 32;
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
- 80;
+ 88;
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40;
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
16;
@@ -11309,13 +11696,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 320;
+ AOT_ObjectStore_double_type_offset = 328;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 232;
+ 240;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 360;
+ AOT_ObjectStore_string_type_offset = 368;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
16;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8;
@@ -11547,6 +11934,28 @@
32;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 34;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 35;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 36;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 32;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 20;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 24;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 12;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 20;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 24;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 40;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 36;
@@ -11643,6 +12052,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 40;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 32;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56;
@@ -11904,6 +12316,8 @@
48;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
56;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 80;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
64;
static constexpr dart::compiler::target::word
@@ -11913,7 +12327,7 @@
static constexpr dart::compiler::target::word
AOT_IsolateGroup_cached_class_table_table_offset = 32;
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
- 80;
+ 88;
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40;
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
16;
@@ -11948,13 +12362,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 320;
+ AOT_ObjectStore_double_type_offset = 328;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 232;
+ 240;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 360;
+ AOT_ObjectStore_string_type_offset = 368;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
16;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8;
@@ -12186,6 +12600,28 @@
32;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 34;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 35;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 36;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 32;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 20;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 24;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 12;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 20;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 24;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 40;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 36;
@@ -12283,6 +12719,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 40;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 32;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56;
@@ -12544,6 +12983,8 @@
24;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
28;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 40;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
32;
static constexpr dart::compiler::target::word
@@ -12553,7 +12994,7 @@
static constexpr dart::compiler::target::word
AOT_IsolateGroup_cached_class_table_table_offset = 16;
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
- 40;
+ 44;
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 20;
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
12;
@@ -12588,13 +13029,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 160;
+ AOT_ObjectStore_double_type_offset = 164;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 116;
+ 120;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 180;
+ AOT_ObjectStore_string_type_offset = 184;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 104;
+ 108;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
12;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 4;
@@ -12825,6 +13266,28 @@
20;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 22;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 23;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 24;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 20;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 12;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 8;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 16;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 4;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 4;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 12;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 16;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 20;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 24;
@@ -12921,6 +13384,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 28;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 28;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 28;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44;
@@ -13183,6 +13649,8 @@
48;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
56;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 80;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
64;
static constexpr dart::compiler::target::word
@@ -13192,7 +13660,7 @@
static constexpr dart::compiler::target::word
AOT_IsolateGroup_cached_class_table_table_offset = 32;
static constexpr dart::compiler::target::word AOT_Isolate_single_step_offset =
- 80;
+ 88;
static constexpr dart::compiler::target::word AOT_Isolate_user_tag_offset = 40;
static constexpr dart::compiler::target::word AOT_LinkedHashBase_data_offset =
24;
@@ -13227,13 +13695,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 320;
+ AOT_ObjectStore_double_type_offset = 328;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 232;
+ 240;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 360;
+ AOT_ObjectStore_string_type_offset = 368;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
16;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8;
@@ -13465,6 +13933,28 @@
40;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 48;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 40;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 16;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 40;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 48;
@@ -13562,6 +14052,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 56;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80;
@@ -13820,6 +14313,8 @@
20;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
24;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 36;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
28;
static constexpr dart::compiler::target::word
@@ -13862,13 +14357,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 160;
+ AOT_ObjectStore_double_type_offset = 164;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 116;
+ 120;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 180;
+ AOT_ObjectStore_string_type_offset = 184;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 104;
+ 108;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
12;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 4;
@@ -14099,6 +14594,28 @@
20;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 22;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 23;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 24;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 20;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 12;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 8;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 16;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 4;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 4;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 12;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 16;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 20;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 24;
@@ -14193,6 +14710,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 28;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 28;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 28;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44;
@@ -14450,6 +14970,8 @@
40;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
48;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 72;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
56;
static constexpr dart::compiler::target::word
@@ -14492,13 +15014,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 320;
+ AOT_ObjectStore_double_type_offset = 328;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 232;
+ 240;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 360;
+ AOT_ObjectStore_string_type_offset = 368;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
16;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8;
@@ -14730,6 +15252,28 @@
40;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 48;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 40;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 16;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 40;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 48;
@@ -14826,6 +15370,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 56;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80;
@@ -15086,6 +15633,8 @@
40;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
48;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 72;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
56;
static constexpr dart::compiler::target::word
@@ -15128,13 +15677,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 320;
+ AOT_ObjectStore_double_type_offset = 328;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 232;
+ 240;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 360;
+ AOT_ObjectStore_string_type_offset = 368;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
16;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8;
@@ -15366,6 +15915,28 @@
40;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 48;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 40;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 16;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 40;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 48;
@@ -15463,6 +16034,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 56;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80;
@@ -15719,6 +16293,8 @@
40;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
48;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 72;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
56;
static constexpr dart::compiler::target::word
@@ -15761,13 +16337,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 320;
+ AOT_ObjectStore_double_type_offset = 328;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 232;
+ 240;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 360;
+ AOT_ObjectStore_string_type_offset = 368;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
16;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8;
@@ -15999,6 +16575,28 @@
32;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 34;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 35;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 36;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 32;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 20;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 24;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 12;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 20;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 24;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 40;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 36;
@@ -16095,6 +16693,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 40;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 32;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56;
@@ -16351,6 +16952,8 @@
40;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
48;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 72;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
56;
static constexpr dart::compiler::target::word
@@ -16393,13 +16996,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 320;
+ AOT_ObjectStore_double_type_offset = 328;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 232;
+ 240;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 360;
+ AOT_ObjectStore_string_type_offset = 368;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
16;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8;
@@ -16631,6 +17234,28 @@
32;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 34;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 35;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 36;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 32;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 20;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 24;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 12;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 20;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 24;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 40;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 36;
@@ -16728,6 +17353,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 40;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 32;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56;
@@ -16984,6 +17612,8 @@
20;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
24;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 36;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
28;
static constexpr dart::compiler::target::word
@@ -17026,13 +17656,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 160;
+ AOT_ObjectStore_double_type_offset = 164;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 116;
+ 120;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 180;
+ AOT_ObjectStore_string_type_offset = 184;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 104;
+ 108;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
12;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 4;
@@ -17263,6 +17893,28 @@
20;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 22;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 23;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 24;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 20;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 12;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 8;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 16;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 4;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 4;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 12;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 16;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 20;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 24;
@@ -17359,6 +18011,9 @@
static constexpr dart::compiler::target::word
AOT_FfiTrampolineData_InstanceSize = 28;
static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_Finalizer_InstanceSize = 28;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_InstanceSize =
+ 28;
static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44;
@@ -17616,6 +18271,8 @@
40;
static constexpr dart::compiler::target::word AOT_Isolate_default_tag_offset =
48;
+static constexpr dart::compiler::target::word AOT_Isolate_finalizers_offset =
+ 72;
static constexpr dart::compiler::target::word AOT_Isolate_ic_miss_code_offset =
56;
static constexpr dart::compiler::target::word
@@ -17658,13 +18315,13 @@
static constexpr dart::compiler::target::word
AOT_NativeArguments_thread_offset = 0;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_double_type_offset = 320;
+ AOT_ObjectStore_double_type_offset = 328;
static constexpr dart::compiler::target::word AOT_ObjectStore_int_type_offset =
- 232;
+ 240;
static constexpr dart::compiler::target::word
- AOT_ObjectStore_string_type_offset = 360;
+ AOT_ObjectStore_string_type_offset = 368;
static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
- 208;
+ 216;
static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
16;
static constexpr dart::compiler::target::word AOT_PointerBase_data_offset = 8;
@@ -17896,6 +18553,28 @@
40;
static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 42;
static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 43;
+static constexpr dart::compiler::target::word
+ AOT_Finalizer_type_arguments_offset = 48;
+static constexpr dart::compiler::target::word AOT_Finalizer_callback_offset =
+ 40;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_all_entries_offset = 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_detachments_offset = 16;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerBase_entries_collected_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerBase_isolate_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_value_offset =
+ 8;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_detach_offset =
+ 16;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_token_offset =
+ 24;
+static constexpr dart::compiler::target::word
+ AOT_FinalizerEntry_finalizer_offset = 32;
+static constexpr dart::compiler::target::word AOT_FinalizerEntry_next_offset =
+ 40;
static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
static constexpr dart::compiler::target::word
AOT_FunctionType_named_parameter_names_offset = 48;
@@ -17993,6 +18672,9 @@
static constexpr dart::compiler::target::word
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 cbd470c..7f4c232 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -149,6 +149,7 @@
FIELD(Int32x4, value_offset) \
FIELD(Isolate, current_tag_offset) \
FIELD(Isolate, default_tag_offset) \
+ FIELD(Isolate, finalizers_offset) \
FIELD(Isolate, ic_miss_code_offset) \
FIELD(IsolateGroup, object_store_offset) \
FIELD(IsolateGroup, shared_class_table_offset) \
@@ -300,6 +301,17 @@
FIELD(Type, type_class_id_offset) \
FIELD(Type, type_state_offset) \
FIELD(Type, nullability_offset) \
+ FIELD(Finalizer, type_arguments_offset) \
+ FIELD(Finalizer, callback_offset) \
+ FIELD(FinalizerBase, all_entries_offset) \
+ FIELD(FinalizerBase, detachments_offset) \
+ FIELD(FinalizerBase, entries_collected_offset) \
+ FIELD(FinalizerBase, isolate_offset) \
+ FIELD(FinalizerEntry, value_offset) \
+ FIELD(FinalizerEntry, detach_offset) \
+ FIELD(FinalizerEntry, token_offset) \
+ FIELD(FinalizerEntry, finalizer_offset) \
+ FIELD(FinalizerEntry, next_offset) \
FIELD(FunctionType, hash_offset) \
FIELD(FunctionType, named_parameter_names_offset) \
FIELD(FunctionType, nullability_offset) \
@@ -362,6 +374,8 @@
SIZEOF(ExternalTypedData, InstanceSize, UntaggedExternalTypedData) \
SIZEOF(FfiTrampolineData, InstanceSize, UntaggedFfiTrampolineData) \
SIZEOF(Field, InstanceSize, UntaggedField) \
+ SIZEOF(Finalizer, InstanceSize, UntaggedFinalizer) \
+ SIZEOF(FinalizerEntry, InstanceSize, UntaggedFinalizerEntry) \
SIZEOF(Float32x4, InstanceSize, UntaggedFloat32x4) \
SIZEOF(Float64x2, InstanceSize, UntaggedFloat64x2) \
SIZEOF(Function, InstanceSize, UntaggedFunction) \
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index b2fd4b3..9042281 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -370,6 +370,7 @@
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 46df59f..501568e 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -677,18 +677,14 @@
}
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 @@
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 @@
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 4f650a8..c5cc2be 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -36,8 +36,8 @@
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 @@
// 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 1e77f74..68b49e4 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -202,6 +202,7 @@
"Generate code for a generic CPU, unknown at compile time") \
D(trace_cha, bool, false, "Trace CHA operations") \
R(trace_field_guards, false, bool, false, "Trace changes in field's cids.") \
+ D(trace_finalizers, bool, false, "Traces finalizers.") \
D(trace_ic, bool, false, "Trace IC handling") \
D(trace_ic_miss_in_optimized, bool, false, \
"Trace IC miss in optimized code") \
diff --git a/runtime/vm/heap/gc_shared.cc b/runtime/vm/heap/gc_shared.cc
new file mode 100644
index 0000000..0941bd6
--- /dev/null
+++ b/runtime/vm/heap/gc_shared.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Logic shared between the Scavenger and Marker.
+
+#include "vm/heap/gc_shared.h"
+
+#include "vm/dart_api_state.h"
+#include "vm/heap/scavenger.h"
+#include "vm/log.h"
+#include "vm/message_handler.h"
+#include "vm/object.h"
+
+namespace dart {
+
+void GCLinkedLists::Clear() {
+#define FOREACH(type, var) var.Clear();
+ GC_LINKED_LIST(FOREACH)
+#undef FOREACH
+}
+
+bool GCLinkedLists::IsEmpty() {
+#define FOREACH(type, var) \
+ if (!var.IsEmpty()) { \
+ return false; \
+ }
+ GC_LINKED_LIST(FOREACH)
+ return true;
+#undef FOREACH
+}
+
+void GCLinkedLists::FlushInto(GCLinkedLists* to) {
+#define FOREACH(type, var) var.FlushInto(&to->var);
+ GC_LINKED_LIST(FOREACH)
+#undef FOREACH
+}
+
+} // namespace dart
diff --git a/runtime/vm/heap/gc_shared.h b/runtime/vm/heap/gc_shared.h
new file mode 100644
index 0000000..3320868
--- /dev/null
+++ b/runtime/vm/heap/gc_shared.h
@@ -0,0 +1,195 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Logic shared between the Scavenger and Marker.
+
+#ifndef RUNTIME_VM_HEAP_GC_SHARED_H_
+#define RUNTIME_VM_HEAP_GC_SHARED_H_
+
+#include "vm/compiler/runtime_api.h"
+#if defined(SHOULD_NOT_INCLUDE_RUNTIME)
+#error "Should not include runtime"
+#endif
+
+#include "vm/dart_api_state.h"
+#include "vm/heap/scavenger.h"
+#include "vm/log.h"
+#include "vm/message_handler.h"
+#include "vm/object.h"
+
+namespace dart {
+
+// These object types have a linked list chaining all pending objects when
+// processing these in the GC.
+// The field should not be visited by pointer visitors.
+// The field should only be set during a GC.
+//
+// Macro params:
+// - type
+// - variable name
+#define GC_LINKED_LIST(V) \
+ V(WeakProperty, weak_properties) \
+ V(WeakReference, weak_references) \
+ V(FinalizerEntry, finalizer_entries)
+
+template <typename Type, typename PtrType>
+struct GCLinkedList {
+ public:
+ void Enqueue(PtrType ptr) {
+ ptr->untag()->next_seen_by_gc_ = head;
+ if (head == Type::null()) {
+ tail = ptr;
+ }
+ head = ptr;
+ }
+
+ void FlushInto(GCLinkedList<Type, PtrType>* to) {
+ if (to->head == Type::null()) {
+ ASSERT(to->tail == Type::null());
+ to->head = head;
+ to->tail = tail;
+ } else {
+ ASSERT(to->tail != Type::null());
+ ASSERT(to->tail->untag()->next_seen_by_gc() == Type::null());
+ to->tail->untag()->next_seen_by_gc_ = head;
+ to->tail = tail;
+ }
+ Clear();
+ }
+
+ PtrType Clear() {
+ PtrType return_value = head;
+ head = Type::null();
+ tail = Type::null();
+ return return_value;
+ }
+
+ bool IsEmpty() { return head == Type::null() && tail == Type::null(); }
+
+ private:
+ PtrType head = Type::null();
+ PtrType tail = Type::null();
+};
+
+struct GCLinkedLists {
+ public:
+ void Clear();
+ bool IsEmpty();
+ void FlushInto(GCLinkedLists* to);
+
+#define FOREACH(type, var) GCLinkedList<type, type##Ptr> var;
+ GC_LINKED_LIST(FOREACH)
+#undef FOREACH
+};
+
+#ifdef DEBUG
+#define TRACE_FINALIZER(format, ...) \
+ if (FLAG_trace_finalizers) { \
+ THR_Print("%s %p " format "\n", visitor->kName, visitor, __VA_ARGS__); \
+ }
+#else
+#define TRACE_FINALIZER(format, ...)
+#endif
+
+// This function processes all finalizer entries discovered by a scavenger or
+// marker. If an entry is referencing an object that is going to die, such entry
+// is cleared and enqueued in the respective finalizer.
+//
+// Finalizer entries belonging to unreachable finalizer entries do not get
+// processed, so the callback will not be called for these finalizers.
+//
+// For more documentation see runtime/docs/gc.md.
+//
+// |GCVisitorType| is a concrete type implementing either marker or scavenger.
+// It is expected to provide |SetNullIfCollected| method for clearing fields
+// referring to dead objects and |kName| field which contains visitor name for
+// tracing output.
+template <typename GCVisitorType>
+void MournFinalized(GCVisitorType* visitor) {
+ FinalizerEntryPtr current_entry = visitor->delayed_.finalizer_entries.Clear();
+ while (current_entry != FinalizerEntry::null()) {
+ TRACE_FINALIZER("Processing Entry %p", current_entry->untag());
+ FinalizerEntryPtr next_entry =
+ current_entry->untag()->next_seen_by_gc_.Decompress(
+ current_entry->heap_base());
+ current_entry->untag()->next_seen_by_gc_ = FinalizerEntry::null();
+
+ uword heap_base = current_entry->heap_base();
+ const bool value_collected_this_gc = GCVisitorType::SetNullIfCollected(
+ heap_base, ¤t_entry->untag()->value_);
+ GCVisitorType::SetNullIfCollected(heap_base,
+ ¤t_entry->untag()->detach_);
+ GCVisitorType::SetNullIfCollected(heap_base,
+ ¤t_entry->untag()->finalizer_);
+
+ ObjectPtr token_object = current_entry->untag()->token();
+ // See sdk/lib/_internal/vm/lib/internal_patch.dart FinalizerBase.detach.
+ const bool is_detached = token_object == current_entry;
+
+ if (value_collected_this_gc && !is_detached) {
+ FinalizerBasePtr finalizer = current_entry->untag()->finalizer();
+
+ if (finalizer.IsRawNull()) {
+ TRACE_FINALIZER("Value collected entry %p finalizer null",
+ current_entry->untag());
+
+ // Do nothing, the finalizer has been GCed.
+ } else if (finalizer.IsFinalizer()) {
+ TRACE_FINALIZER("Value collected entry %p finalizer %p",
+ current_entry->untag(), finalizer->untag());
+
+ FinalizerPtr finalizer_dart = static_cast<FinalizerPtr>(finalizer);
+ // Move entry to entries collected and current head of that list as
+ // the next element. Using a atomic exchange satisfies concurrency
+ // between the parallel GC tasks.
+ // We rely on the fact that the mutator thread is not running to avoid
+ // races between GC and mutator modifying Finalizer.entries_collected.
+ //
+ // We only run in serial marker or in the finalize step in the marker,
+ // both are in safepoint.
+ // The main scavenger worker is at safepoint, the other scavenger
+ // workers are are not, but they bypass safepoint because the main
+ // worker is at a safepoint already.
+ ASSERT(Thread::Current()->IsAtSafepoint() ||
+ Thread::Current()->BypassSafepoints());
+
+ FinalizerEntryPtr previous_head =
+ finalizer_dart->untag()->exchange_entries_collected(current_entry);
+ current_entry->untag()->set_next(previous_head);
+ const bool first_entry = previous_head.IsRawNull();
+ // Schedule calling Dart finalizer.
+ if (first_entry) {
+ Isolate* isolate = finalizer->untag()->isolate_;
+ if (isolate == nullptr) {
+ TRACE_FINALIZER(
+ "Not scheduling finalizer %p callback on isolate null",
+ finalizer->untag());
+ } else {
+ TRACE_FINALIZER("Scheduling finalizer %p callback on isolate %p",
+ finalizer->untag(), isolate);
+
+ PersistentHandle* handle =
+ isolate->group()->api_state()->AllocatePersistentHandle();
+ handle->set_ptr(finalizer);
+ MessageHandler* message_handler = isolate->message_handler();
+ message_handler->PostMessage(
+ Message::New(handle, Message::kNormalPriority),
+ /*before_events*/ false);
+ }
+ }
+ } else {
+ // TODO(http://dartbug.com/47777): Implement NativeFinalizer.
+ UNREACHABLE();
+ }
+ }
+
+ current_entry = next_entry;
+ }
+}
+
+#undef TRACE_FINALIZER
+
+} // namespace dart
+
+#endif // RUNTIME_VM_HEAP_GC_SHARED_H_
diff --git a/runtime/vm/heap/heap_sources.gni b/runtime/vm/heap/heap_sources.gni
index de6d25e..a8e8d99 100644
--- a/runtime/vm/heap/heap_sources.gni
+++ b/runtime/vm/heap/heap_sources.gni
@@ -11,6 +11,8 @@
"compactor.h",
"freelist.cc",
"freelist.h",
+ "gc_shared.cc",
+ "gc_shared.h",
"heap.cc",
"heap.h",
"marker.cc",
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 3309815..f760b67 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -4,9 +4,12 @@
#include "vm/heap/marker.h"
+#include "platform/assert.h"
#include "platform/atomic.h"
#include "vm/allocation.h"
#include "vm/dart_api_state.h"
+#include "vm/flags.h"
+#include "vm/heap/gc_shared.h"
#include "vm/heap/pages.h"
#include "vm/heap/pointer_block.h"
#include "vm/isolate.h"
@@ -14,10 +17,12 @@
#include "vm/object_id_ring.h"
#include "vm/raw_object.h"
#include "vm/stack_frame.h"
+#include "vm/tagged_pointer.h"
#include "vm/thread_barrier.h"
#include "vm/thread_pool.h"
#include "vm/thread_registry.h"
#include "vm/timeline.h"
+#include "vm/token.h"
#include "vm/visitor.h"
namespace dart {
@@ -34,34 +39,35 @@
page_space_(page_space),
work_list_(marking_stack),
deferred_work_list_(deferred_marking_stack),
- delayed_weak_properties_(WeakProperty::null()),
- delayed_weak_properties_tail_(WeakProperty::null()),
- delayed_weak_references_(WeakReference::null()),
- delayed_weak_references_tail_(WeakReference::null()),
marked_bytes_(0),
marked_micros_(0) {
ASSERT(thread_->isolate_group() == isolate_group);
}
- ~MarkingVisitorBase() {
- ASSERT(delayed_weak_properties_ == WeakProperty::null());
- ASSERT(delayed_weak_references_ == WeakReference::null());
- }
+ ~MarkingVisitorBase() { ASSERT(delayed_.IsEmpty()); }
+
+#ifdef DEBUG
+ const char* kName = "Marker";
+#endif
uintptr_t marked_bytes() const { return marked_bytes_; }
int64_t marked_micros() const { return marked_micros_; }
void AddMicros(int64_t micros) { marked_micros_ += micros; }
+ bool IsMarked(ObjectPtr raw) {
+ ASSERT(raw->IsHeapObject());
+ ASSERT(raw->IsOldObject());
+ return raw->untag()->IsMarked();
+ }
+
bool ProcessPendingWeakProperties() {
bool more_to_mark = false;
- WeakPropertyPtr cur_weak = delayed_weak_properties_;
- delayed_weak_properties_tail_ = delayed_weak_properties_ =
- WeakProperty::null();
+ WeakPropertyPtr cur_weak = delayed_.weak_properties.Clear();
while (cur_weak != WeakProperty::null()) {
WeakPropertyPtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
ObjectPtr raw_key = cur_weak->untag()->key();
// Reset the next pointer in the weak property.
- cur_weak->untag()->next_ = WeakProperty::null();
+ cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null();
if (raw_key->IsSmiOrNewObject() || raw_key->untag()->IsMarked()) {
ObjectPtr raw_val = cur_weak->untag()->value();
if (!raw_val->IsSmiOrNewObject() && !raw_val->untag()->IsMarked()) {
@@ -73,7 +79,8 @@
cur_weak->untag()->VisitPointersNonvirtual(this);
} else {
// Requeue this weak property to be handled later.
- EnqueueWeakProperty(cur_weak);
+ ASSERT(IsMarked(cur_weak));
+ delayed_.weak_properties.Enqueue(cur_weak);
}
// Advance to next weak property in the queue.
cur_weak = next_weak;
@@ -125,6 +132,9 @@
} else if (class_id == kWeakReferenceCid) {
WeakReferencePtr raw_weak = static_cast<WeakReferencePtr>(raw_obj);
size = ProcessWeakReference(raw_weak);
+ } else if (class_id == kFinalizerEntryCid) {
+ FinalizerEntryPtr raw_weak = static_cast<FinalizerEntryPtr>(raw_obj);
+ size = ProcessFinalizerEntry(raw_weak);
} else {
size = raw_obj->untag()->VisitPointersNonvirtual(this);
}
@@ -182,34 +192,6 @@
}
}
- void EnqueueWeakProperty(WeakPropertyPtr raw_weak) {
- ASSERT(raw_weak->IsHeapObject());
- ASSERT(raw_weak->IsOldObject());
- ASSERT(raw_weak->IsWeakProperty());
- ASSERT(raw_weak->untag()->IsMarked());
- ASSERT(raw_weak->untag()->next_ ==
- CompressedWeakPropertyPtr(WeakProperty::null()));
- raw_weak->untag()->next_ = delayed_weak_properties_;
- if (delayed_weak_properties_ == WeakProperty::null()) {
- delayed_weak_properties_tail_ = raw_weak;
- }
- delayed_weak_properties_ = raw_weak;
- }
-
- void EnqueueWeakReference(WeakReferencePtr raw_weak) {
- ASSERT(raw_weak->IsHeapObject());
- ASSERT(raw_weak->IsOldObject());
- ASSERT(raw_weak->IsWeakReference());
- ASSERT(raw_weak->untag()->IsMarked());
- ASSERT(raw_weak->untag()->next_ ==
- CompressedWeakReferencePtr(WeakReference::null()));
- raw_weak->untag()->next_ = delayed_weak_references_;
- if (delayed_weak_references_ == WeakReference::null()) {
- delayed_weak_references_tail_ = raw_weak;
- }
- delayed_weak_references_ = raw_weak;
- }
-
intptr_t ProcessWeakProperty(WeakPropertyPtr raw_weak) {
// The fate of the weak property is determined by its key.
ObjectPtr raw_key =
@@ -218,7 +200,8 @@
if (raw_key->IsHeapObject() && raw_key->IsOldObject() &&
!raw_key->untag()->IsMarked()) {
// Key was white. Enqueue the weak property.
- EnqueueWeakProperty(raw_weak);
+ ASSERT(IsMarked(raw_weak));
+ delayed_.weak_properties.Enqueue(raw_weak);
return raw_weak->untag()->HeapSize();
}
// Key is gray or black. Make the weak property black.
@@ -235,7 +218,8 @@
!raw_target->untag()->IsMarked()) {
// Target was white. Enqueue the weak reference. It is potentially dead.
// It might still be made alive by weak properties in next rounds.
- EnqueueWeakReference(raw_weak);
+ ASSERT(IsMarked(raw_weak));
+ delayed_.weak_references.Enqueue(raw_weak);
}
// Always visit the type argument.
ObjectPtr raw_type_arguments =
@@ -245,6 +229,17 @@
return raw_weak->untag()->HeapSize();
}
+ intptr_t ProcessFinalizerEntry(FinalizerEntryPtr raw_entry) {
+ ASSERT(IsMarked(raw_entry));
+ delayed_.finalizer_entries.Enqueue(raw_entry);
+ // Only visit token and next.
+ MarkObject(LoadCompressedPointerIgnoreRace(&raw_entry->untag()->token_)
+ .Decompress(raw_entry->heap_base()));
+ MarkObject(LoadCompressedPointerIgnoreRace(&raw_entry->untag()->next_)
+ .Decompress(raw_entry->heap_base()));
+ return raw_entry->untag()->HeapSize();
+ }
+
void ProcessDeferredMarking() {
ObjectPtr raw_obj;
while ((raw_obj = deferred_work_list_.Pop()) != nullptr) {
@@ -279,15 +274,15 @@
void FinalizeMarking() {
work_list_.Finalize();
deferred_work_list_.Finalize();
+ MournFinalized(this);
}
void MournWeakProperties() {
- WeakPropertyPtr cur_weak = delayed_weak_properties_;
- delayed_weak_properties_ = WeakProperty::null();
+ WeakPropertyPtr cur_weak = delayed_.weak_properties.Clear();
while (cur_weak != WeakProperty::null()) {
WeakPropertyPtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
- cur_weak->untag()->next_ = WeakProperty::null();
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null();
RELEASE_ASSERT(!cur_weak->untag()->key()->untag()->IsMarked());
WeakProperty::Clear(cur_weak);
cur_weak = next_weak;
@@ -295,72 +290,58 @@
}
void MournWeakReferences() {
- WeakReferencePtr cur_weak = delayed_weak_references_;
- delayed_weak_references_ = WeakReference::null();
+ WeakReferencePtr cur_weak = delayed_.weak_references.Clear();
while (cur_weak != WeakReference::null()) {
WeakReferencePtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
- cur_weak->untag()->next_ = WeakReference::null();
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_ = WeakReference::null();
+
// If we did not mark the target through a weak property in a later round,
// then the target is dead and we should clear it.
- if (!cur_weak->untag()->target()->untag()->IsMarked()) {
- WeakReference::Clear(cur_weak);
- }
+ SetNullIfCollected(cur_weak->heap_base(), &cur_weak->untag()->target_);
+
cur_weak = next_weak;
}
}
+ // Returns whether the object referred to in `ptr_address` was GCed this GC.
+ static bool SetNullIfCollected(uword heap_base,
+ CompressedObjectPtr* ptr_address) {
+ ObjectPtr raw = ptr_address->Decompress(heap_base);
+ if (raw.IsRawNull()) {
+ // Object already null before this GC.
+ return false;
+ }
+ if (raw.IsNewObject()) {
+ // Object not touched during this GC.
+ return false;
+ }
+ if (raw->untag()->IsMarked()) {
+ return false;
+ }
+ *ptr_address = Object::null();
+ return true;
+ }
+
bool WaitForWork(RelaxedAtomic<uintptr_t>* num_busy) {
return work_list_.WaitForWork(num_busy);
}
- void Flush(WeakPropertyPtr* weak_properties_head,
- WeakPropertyPtr* weak_properties_tail,
- WeakReferencePtr* weak_references_head,
- WeakReferencePtr* weak_references_tail) {
+ void Flush(GCLinkedLists* global_list) {
work_list_.Flush();
deferred_work_list_.Flush();
-
- if (*weak_properties_head == WeakProperty::null()) {
- *weak_properties_head = delayed_weak_properties_;
- *weak_properties_tail = delayed_weak_properties_tail_;
- } else {
- (*weak_properties_tail)->untag()->next_ = delayed_weak_properties_;
- *weak_properties_tail = delayed_weak_properties_tail_;
- }
- delayed_weak_properties_tail_ = delayed_weak_properties_ =
- WeakProperty::null();
-
- if (*weak_references_head == WeakReference::null()) {
- *weak_references_head = delayed_weak_references_;
- *weak_references_tail = delayed_weak_references_tail_;
- } else {
- (*weak_references_tail)->untag()->next_ = delayed_weak_references_;
- *weak_references_tail = delayed_weak_references_tail_;
- }
- delayed_weak_references_tail_ = delayed_weak_references_ =
- WeakReference::null();
+ delayed_.FlushInto(global_list);
}
- void Adopt(WeakPropertyPtr weak_properties_head,
- WeakPropertyPtr weak_properties_tail,
- WeakReferencePtr weak_references_head,
- WeakReferencePtr weak_references_tail) {
- ASSERT(delayed_weak_properties_ == WeakProperty::null());
- ASSERT(delayed_weak_properties_tail_ == WeakProperty::null());
- ASSERT(delayed_weak_references_ == WeakReference::null());
- ASSERT(delayed_weak_references_tail_ == WeakReference::null());
- delayed_weak_properties_ = weak_properties_head;
- delayed_weak_properties_tail_ = weak_properties_tail;
- delayed_weak_references_ = weak_references_head;
- delayed_weak_references_tail_ = weak_references_tail;
+ void Adopt(GCLinkedLists* other) {
+ ASSERT(delayed_.IsEmpty());
+ other->FlushInto(&delayed_);
}
void AbandonWork() {
work_list_.AbandonWork();
deferred_work_list_.AbandonWork();
- delayed_weak_properties_ = WeakProperty::null();
- delayed_weak_references_ = WeakReference::null();
+ delayed_.Clear();
}
private:
@@ -430,13 +411,13 @@
PageSpace* page_space_;
MarkerWorkList work_list_;
MarkerWorkList deferred_work_list_;
- WeakPropertyPtr delayed_weak_properties_;
- WeakPropertyPtr delayed_weak_properties_tail_;
- WeakReferencePtr delayed_weak_references_;
- WeakReferencePtr delayed_weak_references_tail_;
+ GCLinkedLists delayed_;
uintptr_t marked_bytes_;
int64_t marked_micros_;
+ template <typename GCVisitorType>
+ friend void MournFinalized(GCVisitorType* visitor);
+
DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitorBase);
};
@@ -746,6 +727,9 @@
// Phase 3: Weak processing and statistics.
visitor_->MournWeakProperties();
visitor_->MournWeakReferences();
+ // Don't MournFinalized here, do it on main thread, so that we don't have
+ // to coordinate workers.
+
marker_->IterateWeakRoots(thread);
int64_t stop = OS::GetCurrentMonotonicMicros();
visitor_->AddMicros(stop - start);
@@ -984,6 +968,7 @@
visitor.FinalizeMarking();
visitor.MournWeakProperties();
visitor.MournWeakReferences();
+ MournFinalized(&visitor);
IterateWeakRoots(thread);
// All marking done; detach code, etc.
int64_t stop = OS::GetCurrentMonotonicMicros();
@@ -998,10 +983,7 @@
RelaxedAtomic<uintptr_t> num_busy = 0;
// Phase 1: Iterate over roots and drain marking stack in tasks.
- WeakPropertyPtr weak_properties_head = WeakProperty::null();
- WeakPropertyPtr weak_properties_tail = WeakProperty::null();
- WeakReferencePtr weak_references_head = WeakReference::null();
- WeakReferencePtr weak_references_tail = WeakReference::null();
+ GCLinkedLists global_list;
for (intptr_t i = 0; i < num_tasks; ++i) {
SyncMarkingVisitor* visitor = visitors_[i];
@@ -1013,12 +995,12 @@
&marking_stack_, &deferred_marking_stack_);
visitors_[i] = visitor;
}
+
// Move all work from local blocks to the global list. Any given
// visitor might not get to run if it fails to reach TryEnter soon
// enough, and we must fail to visit objects but they're sitting in
// such a visitor's local blocks.
- visitor->Flush(&weak_properties_head, &weak_properties_tail,
- &weak_references_head, &weak_references_tail);
+ visitor->Flush(&global_list);
// Need to move weak property list too.
if (i < (num_tasks - 1)) {
@@ -1029,8 +1011,7 @@
ASSERT(result);
} else {
// Last worker is the main thread.
- visitor->Adopt(weak_properties_head, weak_properties_tail,
- weak_references_head, weak_references_tail);
+ visitor->Adopt(&global_list);
ParallelMarkTask task(this, isolate_group_, &marking_stack_, barrier,
visitor, &num_busy);
task.RunEnteredIsolateGroup();
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index e8b433a..e7dcfc1 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -4,11 +4,14 @@
#include "vm/heap/scavenger.h"
+#include "platform/assert.h"
#include "platform/leak_sanitizer.h"
+#include "vm/class_id.h"
#include "vm/dart.h"
#include "vm/dart_api_state.h"
#include "vm/flag_list.h"
#include "vm/heap/become.h"
+#include "vm/heap/gc_shared.h"
#include "vm/heap/pages.h"
#include "vm/heap/pointer_block.h"
#include "vm/heap/safepoint.h"
@@ -20,6 +23,7 @@
#include "vm/object.h"
#include "vm/object_id_ring.h"
#include "vm/object_set.h"
+#include "vm/port.h"
#include "vm/stack_frame.h"
#include "vm/thread_barrier.h"
#include "vm/thread_registry.h"
@@ -131,13 +135,12 @@
freelist_(freelist),
bytes_promoted_(0),
visiting_old_object_(nullptr),
- promoted_list_(promotion_stack),
- delayed_weak_properties_(WeakProperty::null()),
- delayed_weak_references_(WeakReference::null()) {}
- ~ScavengerVisitorBase() {
- ASSERT(delayed_weak_properties_ == WeakProperty::null());
- ASSERT(delayed_weak_references_ == WeakReference::null());
- }
+ promoted_list_(promotion_stack) {}
+ ~ScavengerVisitorBase() { ASSERT(delayed_.IsEmpty()); }
+
+#ifdef DEBUG
+ const char* kName = "Scavenger";
+#endif
virtual void VisitTypedDataViewPointers(TypedDataViewPtr view,
CompressedObjectPtr* first,
@@ -299,6 +302,7 @@
MournWeakProperties();
MournOrUpdateWeakReferences();
+ MournFinalized(this);
}
page_space_->ReleaseLock(freelist_);
thread_ = nullptr;
@@ -308,13 +312,15 @@
void AbandonWork() {
promoted_list_.AbandonWork();
- delayed_weak_properties_ = WeakProperty::null();
- delayed_weak_references_ = WeakReference::null();
+ delayed_.Clear();
}
NewPage* head() const { return head_; }
NewPage* tail() const { return tail_; }
+ static bool SetNullIfCollected(uword heap_base,
+ CompressedObjectPtr* ptr_address);
+
private:
void UpdateStoreBuffer(ObjectPtr obj) {
ASSERT(obj->IsHeapObject());
@@ -511,8 +517,13 @@
inline void ProcessToSpace();
DART_FORCE_INLINE intptr_t ProcessCopied(ObjectPtr raw_obj);
inline void ProcessPromotedList();
- inline void EnqueueWeakProperty(WeakPropertyPtr raw_weak);
- inline void EnqueueWeakReference(WeakReferencePtr raw_weak);
+
+ bool IsNotForwarding(ObjectPtr raw) {
+ ASSERT(raw->IsHeapObject());
+ ASSERT(raw->IsNewObject());
+ return !IsForwarding(ReadHeaderRelaxed(raw));
+ }
+
inline void MournWeakProperties();
inline void MournOrUpdateWeakReferences();
@@ -523,15 +534,16 @@
FreeList* freelist_;
intptr_t bytes_promoted_;
ObjectPtr visiting_old_object_;
-
PromotionWorkList promoted_list_;
- WeakPropertyPtr delayed_weak_properties_;
- WeakReferencePtr delayed_weak_references_;
+ GCLinkedLists delayed_;
NewPage* head_ = nullptr;
NewPage* tail_ = nullptr; // Allocating from here.
NewPage* scan_ = nullptr; // Resolving from here.
+ template <typename GCVisitorType>
+ friend void MournFinalized(GCVisitorType* visitor);
+
DISALLOW_COPY_AND_ASSIGN(ScavengerVisitorBase);
};
@@ -1323,11 +1335,10 @@
// Finished this round of scavenging. Process the pending weak properties
// for which the keys have become reachable. Potentially this adds more
// objects to the to space.
- WeakPropertyPtr cur_weak = delayed_weak_properties_;
- delayed_weak_properties_ = WeakProperty::null();
+ WeakPropertyPtr cur_weak = delayed_.weak_properties.Clear();
while (cur_weak != WeakProperty::null()) {
WeakPropertyPtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
// Promoted weak properties are not enqueued. So we can guarantee that
// we do not need to think about store barriers here.
ASSERT(cur_weak->IsNewObject());
@@ -1341,11 +1352,12 @@
ASSERT(from_->Contains(raw_addr));
uword header = ReadHeaderRelaxed(raw_key);
// Reset the next pointer in the weak property.
- cur_weak->untag()->next_ = WeakProperty::null();
+ cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null();
if (IsForwarding(header)) {
cur_weak->untag()->VisitPointersNonvirtual(this);
} else {
- EnqueueWeakProperty(cur_weak);
+ ASSERT(IsNotForwarding(cur_weak));
+ delayed_.weak_properties.Enqueue(cur_weak);
}
// Advance to next weak property in the queue.
cur_weak = next_weak;
@@ -1378,38 +1390,6 @@
}
template <bool parallel>
-void ScavengerVisitorBase<parallel>::EnqueueWeakProperty(
- WeakPropertyPtr raw_weak) {
- ASSERT(raw_weak->IsHeapObject());
- ASSERT(raw_weak->IsNewObject());
- ASSERT(raw_weak->IsWeakProperty());
-#if defined(DEBUG)
- uword header = ReadHeaderRelaxed(raw_weak);
- ASSERT(!IsForwarding(header));
-#endif // defined(DEBUG)
- ASSERT(raw_weak->untag()->next_ ==
- CompressedWeakPropertyPtr(WeakProperty::null()));
- raw_weak->untag()->next_ = delayed_weak_properties_;
- delayed_weak_properties_ = raw_weak;
-}
-
-template <bool parallel>
-void ScavengerVisitorBase<parallel>::EnqueueWeakReference(
- WeakReferencePtr raw_weak) {
- ASSERT(raw_weak->IsHeapObject());
- ASSERT(raw_weak->IsNewObject());
- ASSERT(raw_weak->IsWeakReference());
-#if defined(DEBUG)
- uword header = ReadHeaderRelaxed(raw_weak);
- ASSERT(!IsForwarding(header));
-#endif // defined(DEBUG)
- ASSERT(raw_weak->untag()->next_ ==
- CompressedWeakReferencePtr(WeakReference::null()));
- raw_weak->untag()->next_ = delayed_weak_references_;
- delayed_weak_references_ = raw_weak;
-}
-
-template <bool parallel>
intptr_t ScavengerVisitorBase<parallel>::ProcessCopied(ObjectPtr raw_obj) {
intptr_t class_id = raw_obj->GetClassId();
if (UNLIKELY(class_id == kWeakPropertyCid)) {
@@ -1420,7 +1400,8 @@
uword header = ReadHeaderRelaxed(raw_key);
if (!IsForwarding(header)) {
// Key is white. Enqueue the weak property.
- EnqueueWeakProperty(raw_weak);
+ ASSERT(IsNotForwarding(raw_weak));
+ delayed_.weak_properties.Enqueue(raw_weak);
return raw_weak->untag()->HeapSize();
}
}
@@ -1434,7 +1415,8 @@
if (!IsForwarding(header)) {
// Target is white. Enqueue the weak reference. Always visit type
// arguments.
- EnqueueWeakReference(raw_weak);
+ ASSERT(IsNotForwarding(raw_weak));
+ delayed_.weak_references.Enqueue(raw_weak);
#if !defined(DART_COMPRESSED_POINTERS)
ScavengePointer(&raw_weak->untag()->type_arguments_);
#else
@@ -1444,6 +1426,21 @@
return raw_weak->untag()->HeapSize();
}
}
+ } else if (UNLIKELY(class_id == kFinalizerEntryCid)) {
+ FinalizerEntryPtr raw_entry = static_cast<FinalizerEntryPtr>(raw_obj);
+ ASSERT(IsNotForwarding(raw_entry));
+ delayed_.finalizer_entries.Enqueue(raw_entry);
+ // Only visit token and next.
+#if !defined(DART_COMPRESSED_POINTERS)
+ ScavengePointer(&raw_entry->untag()->token_);
+ ScavengePointer(&raw_entry->untag()->next_);
+#else
+ ScavengeCompressedPointer(raw_entry->heap_base(),
+ &raw_entry->untag()->token_);
+ ScavengeCompressedPointer(raw_entry->heap_base(),
+ &raw_entry->untag()->next_);
+#endif
+ return raw_entry->untag()->HeapSize();
}
return raw_obj->untag()->VisitPointersNonvirtual(this);
}
@@ -1507,13 +1504,12 @@
// The queued weak properties at this point do not refer to reachable keys,
// so we clear their key and value fields.
- WeakPropertyPtr cur_weak = delayed_weak_properties_;
- delayed_weak_properties_ = WeakProperty::null();
+ WeakPropertyPtr cur_weak = delayed_.weak_properties.Clear();
while (cur_weak != WeakProperty::null()) {
WeakPropertyPtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
// Reset the next pointer in the weak property.
- cur_weak->untag()->next_ = WeakProperty::null();
+ cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null();
#if defined(DEBUG)
ObjectPtr raw_key = cur_weak->untag()->key();
@@ -1537,31 +1533,48 @@
// The queued weak references at this point either should have their target
// updated or should be cleared.
- WeakReferencePtr cur_weak = delayed_weak_references_;
- delayed_weak_references_ = WeakReference::null();
+ WeakReferencePtr cur_weak = delayed_.weak_references.Clear();
while (cur_weak != WeakReference::null()) {
WeakReferencePtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
// Reset the next pointer in the weak reference.
- cur_weak->untag()->next_ = WeakReference::null();
+ cur_weak->untag()->next_seen_by_gc_ = WeakReference::null();
- ObjectPtr raw_target = cur_weak->untag()->target();
- uword raw_addr = UntaggedObject::ToAddr(raw_target);
- uword header = *reinterpret_cast<uword*>(raw_addr);
- if (IsForwarding(header)) {
- // Get the new location of the object.
- cur_weak->untag()->target_ = ForwardedObj(header);
- } else {
- ASSERT(raw_target->IsHeapObject());
- ASSERT(raw_target->IsNewObject());
- WeakReference::Clear(cur_weak);
- }
+ // If we did not mark the target through a weak property in a later round,
+ // then the target is dead and we should clear it.
+ SetNullIfCollected(cur_weak->heap_base(), &cur_weak->untag()->target_);
// Advance to next weak reference in the queue.
cur_weak = next_weak;
}
}
+// Returns whether the object referred to in `ptr_address` was GCed this GC.
+template <bool parallel>
+bool ScavengerVisitorBase<parallel>::SetNullIfCollected(
+ uword heap_base,
+ CompressedObjectPtr* ptr_address) {
+ ObjectPtr raw = ptr_address->Decompress(heap_base);
+ if (raw.IsRawNull()) {
+ // Object already null before this GC.
+ return false;
+ }
+ if (raw.IsOldObject()) {
+ // Object not touched during this GC.
+ return false;
+ }
+ uword header = *reinterpret_cast<uword*>(UntaggedObject::ToAddr(raw));
+ if (IsForwarding(header)) {
+ // Get the new location of the object.
+ *ptr_address = ForwardedObj(header);
+ return false;
+ }
+ ASSERT(raw->IsHeapObject());
+ ASSERT(raw->IsNewObject());
+ *ptr_address = Object::null();
+ return true;
+}
+
void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const {
ASSERT(Thread::Current()->IsAtSafepoint() ||
(Thread::Current()->task_kind() == Thread::kMarkerTask) ||
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 2f8c8cc..1190825 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1388,6 +1388,15 @@
}
}
}
+ } 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 @@
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 @@
}
}
+ // 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 @@
"--check-reloaded is enabled.\n");
}
}
-
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
// Then, proceed with low-level teardown.
@@ -2721,6 +2758,7 @@
visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&ic_miss_code_));
visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&tag_table_));
visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&sticky_error_));
+ visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&finalizers_));
#if !defined(PRODUCT)
visitor->VisitPointer(
reinterpret_cast<ObjectPtr*>(&pending_service_extension_calls_));
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index e714838..bd1e9fb 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -1065,6 +1065,10 @@
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 @@
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 @@
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 @@
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 0b1eb10..f5e8986 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -1300,7 +1300,8 @@
}
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 0f2d2e4..d9d0680 100644
--- a/runtime/vm/message.cc
+++ b/runtime/vm/message.cc
@@ -45,12 +45,20 @@
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 4c82bdf..46064a9 100644
--- a/runtime/vm/message.h
+++ b/runtime/vm/message.h
@@ -62,8 +62,13 @@
// 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 <typename... Args>
@@ -94,7 +99,7 @@
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 @@
// 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 @@
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 @@
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 715641b..228c745 100644
--- a/runtime/vm/message_handler.h
+++ b/runtime/vm/message_handler.h
@@ -211,6 +211,8 @@
Thread* thread() const { return Thread::Current(); }
private:
+ template <typename GCVisitorType>
+ 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 22de126..a5e5d7a 100644
--- a/runtime/vm/message_snapshot.cc
+++ b/runtime/vm/message_snapshot.cc
@@ -3916,6 +3916,11 @@
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 fe33347..6a96faf 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -118,7 +118,7 @@
cpp_vtable Object::builtin_vtables_[kNumPredefinedCids] = {};
-// These are initialized to a value that will force a illegal memory access if
+// These are initialized to a value that will force an illegal memory access if
// they are being used.
#if defined(RAW_NULL)
#error RAW_NULL should not be defined.
@@ -2341,6 +2341,14 @@
pending_classes.Add(cls);
RegisterClass(cls, Symbols::FfiDynamicLibrary(), lib);
+ cls = Class::New<Finalizer, RTN::Finalizer>(isolate_group);
+ cls.set_type_arguments_field_offset(
+ Finalizer::type_arguments_offset(),
+ RTN::Finalizer::type_arguments_offset());
+ cls.set_num_type_arguments_unsafe(1);
+ object_store->set_finalizer_class(cls);
+ RegisterPrivateClass(cls, Symbols::_FinalizerImpl(), core_lib);
+
// Pre-register the internal library so we can place the vm class
// FinalizerEntry there rather than the core library.
lib = Library::LookupLibrary(thread, Symbols::DartInternal());
@@ -2353,6 +2361,10 @@
ASSERT(!lib.IsNull());
ASSERT(lib.ptr() == Library::InternalLibrary());
+ cls = Class::New<FinalizerEntry, RTN::FinalizerEntry>(isolate_group);
+ object_store->set_finalizer_entry_class(cls);
+ RegisterClass(cls, Symbols::FinalizerEntry(), lib);
+
// Finish the initialization by compiling the bootstrap scripts containing
// the base interfaces and the implementation of the internal classes.
const Error& error = Error::Handle(
@@ -2520,6 +2532,10 @@
object_store->set_weak_property_class(cls);
cls = Class::New<WeakReference, RTN::WeakReference>(isolate_group);
object_store->set_weak_reference_class(cls);
+ cls = Class::New<Finalizer, RTN::Finalizer>(isolate_group);
+ object_store->set_finalizer_class(cls);
+ cls = Class::New<FinalizerEntry, RTN::FinalizerEntry>(isolate_group);
+ object_store->set_finalizer_entry_class(cls);
cls = Class::New<MirrorReference, RTN::MirrorReference>(isolate_group);
cls = Class::New<UserTag, RTN::UserTag>(isolate_group);
@@ -26005,14 +26021,50 @@
space, WeakReference::ContainsCompressedPointers());
return static_cast<WeakReferencePtr>(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<FinalizerPtr>(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<FinalizerEntryPtr>(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 668b201..cb4eb7d 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3177,7 +3177,29 @@
bool ForceOptimize() const {
return IsFfiFromAddress() || IsFfiGetAddress() || IsFfiLoad() ||
IsFfiStore() || IsFfiTrampoline() || IsFfiAsExternalTypedData() ||
- IsTypedDataViewFactory() || IsUtf8Scan() || IsGetNativeField();
+ IsTypedDataViewFactory() || IsUtf8Scan() || IsGetNativeField() ||
+ IsFinalizerForceOptimized();
+ }
+
+ bool IsFinalizerForceOptimized() const {
+ // Either because of unboxed/untagged data, or because we don't want the GC
+ // to trigger in between.
+ switch (recognized_kind()) {
+ case MethodRecognizer::kFinalizerBase_getIsolateFinalizers:
+ case MethodRecognizer::kFinalizerBase_setIsolate:
+ case MethodRecognizer::kFinalizerBase_setIsolateFinalizers:
+ // Unboxed/untagged representation not supported in unoptimized.
+ return true;
+ case MethodRecognizer::kFinalizerBase_exchangeEntriesCollectedWithNull:
+ // Prevent the GC from running so that the operation is atomic from
+ // a GC point of view. Always double check implementation in
+ // kernel_to_il.cc that no GC can happen in between the relevant IL
+ // instructions.
+ // TODO(https://dartbug.com/48527): Support inlining.
+ return true;
+ default:
+ return false;
+ }
}
bool CanBeInlined() const;
@@ -5920,9 +5942,7 @@
static intptr_t UnroundedSize(intptr_t length) {
return HeaderSize() + length;
}
- static intptr_t InstanceSize() {
- return 0;
- }
+ static intptr_t InstanceSize() { return 0; }
static intptr_t InstanceSize(intptr_t length) {
return RoundedAllocationSize(UnroundedSize(length));
}
@@ -11980,7 +12000,7 @@
}
static void Clear(WeakPropertyPtr raw_weak) {
- ASSERT(raw_weak->untag()->next_ ==
+ ASSERT(raw_weak->untag()->next_seen_by_gc_ ==
CompressedWeakPropertyPtr(WeakProperty::null()));
// This action is performed by the GC. No barrier.
raw_weak->untag()->key_ = Object::null();
@@ -12012,15 +12032,109 @@
return RoundedAllocationSize(sizeof(UntaggedWeakReference));
}
- static void Clear(WeakReferencePtr raw_weak) {
- ASSERT(raw_weak->untag()->next_ ==
- CompressedWeakReferencePtr(WeakReference::null()));
- // This action is performed by the GC. No barrier.
- raw_weak->untag()->target_ = Object::null();
+ private:
+ FINAL_HEAP_OBJECT_IMPLEMENTATION(WeakReference, Instance);
+ friend class Class;
+};
+
+class FinalizerEntry : public Instance {
+ public:
+ ObjectPtr value() const { return untag()->value(); }
+ void set_value(const Object& value) const { untag()->set_value(value.ptr()); }
+ static intptr_t value_offset() {
+ return OFFSET_OF(UntaggedFinalizerEntry, value_);
+ }
+
+ ObjectPtr detach() const { return untag()->detach(); }
+ void set_detach(const Object& value) const {
+ untag()->set_detach(value.ptr());
+ }
+ static intptr_t detach_offset() {
+ return OFFSET_OF(UntaggedFinalizerEntry, detach_);
+ }
+
+ ObjectPtr token() const { return untag()->token(); }
+ void set_token(const Object& value) const { untag()->set_token(value.ptr()); }
+ static intptr_t token_offset() {
+ return OFFSET_OF(UntaggedFinalizerEntry, token_);
+ }
+
+ FinalizerBasePtr finalizer() const { return untag()->finalizer(); }
+ void set_finalizer(const FinalizerBase& value) const;
+ static intptr_t finalizer_offset() {
+ return OFFSET_OF(UntaggedFinalizerEntry, finalizer_);
+ }
+
+ FinalizerEntryPtr next() const { return untag()->next(); }
+ void set_next(const FinalizerEntry& value) const {
+ untag()->set_next(value.ptr());
+ }
+ static intptr_t next_offset() {
+ return OFFSET_OF(UntaggedFinalizerEntry, next_);
+ }
+
+ static intptr_t InstanceSize() {
+ return RoundedAllocationSize(sizeof(UntaggedFinalizerEntry));
+ }
+
+ static FinalizerEntryPtr New(Heap::Space space = Heap::kNew);
+
+ private:
+ FINAL_HEAP_OBJECT_IMPLEMENTATION(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 638febe..ede344d 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 @@
// those are the only non-abstract classes (so we avoid checking more cids
// here that cannot happen in reality)
HANDLE_ILLEGAL_CASE(DynamicLibrary)
+ HANDLE_ILLEGAL_CASE(Finalizer)
HANDLE_ILLEGAL_CASE(MirrorReference)
HANDLE_ILLEGAL_CASE(Pointer)
HANDLE_ILLEGAL_CASE(ReceivePort)
@@ -1362,8 +1366,8 @@
Object::null());
// To satisfy some ASSERT()s in GC we'll use Object:null() explicitly here.
Base::StoreCompressedPointerNoBarrier(
- Types::GetWeakPropertyPtr(to), OFFSET_OF(UntaggedWeakProperty, next_),
- Object::null());
+ Types::GetWeakPropertyPtr(to),
+ OFFSET_OF(UntaggedWeakProperty, next_seen_by_gc_), Object::null());
Base::EnqueueWeakProperty(from);
}
@@ -1380,8 +1384,8 @@
from, to, OFFSET_OF(UntaggedWeakReference, type_arguments_));
// To satisfy some ASSERT()s in GC we'll use Object:null() explicitly here.
Base::StoreCompressedPointerNoBarrier(
- Types::GetWeakReferencePtr(to), OFFSET_OF(UntaggedWeakReference, next_),
- Object::null());
+ Types::GetWeakReferencePtr(to),
+ OFFSET_OF(UntaggedWeakReference, next_seen_by_gc_), Object::null());
Base::EnqueueWeakReference(from);
}
@@ -1815,7 +1819,7 @@
// 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 210f508..59245d6 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -1700,6 +1700,29 @@
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 23f9b4d..bdbc4a1 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -78,6 +78,8 @@
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 @@
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 @@
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 f86b8c5..26bce63 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -55,6 +55,7 @@
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 @@
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 @@
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 237ffb0..8a647cb 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 <limits>
+#include <memory>
#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 @@
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<bool> 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<bool> 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<bool> 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<bool> 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<bool> 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<bool> 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 eb83d68..82e1bf8 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -552,6 +552,8 @@
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(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 5a084c5..2142cd4 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -623,6 +623,20 @@
}
}
+ template <typename type,
+ typename compressed_type,
+ std::memory_order order = std::memory_order_relaxed>
+ type ExchangeCompressedPointer(compressed_type const* addr, type value) {
+ compressed_type previous_value =
+ reinterpret_cast<std::atomic<compressed_type>*>(
+ const_cast<compressed_type*>(addr))
+ ->exchange(static_cast<compressed_type>(value), order);
+ if (value.IsHeapObject()) {
+ CheckHeapPointerStore(value, Thread::Current());
+ }
+ return static_cast<type>(previous_value.Decompress(heap_base()));
+ }
+
template <std::memory_order order = std::memory_order_relaxed>
SmiPtr LoadSmi(SmiPtr const* addr) const {
return reinterpret_cast<std::atomic<SmiPtr>*>(const_cast<SmiPtr*>(addr))
@@ -3265,7 +3279,7 @@
class UntaggedWeakProperty : public UntaggedInstance {
RAW_HEAP_OBJECT_IMPLEMENTATION(WeakProperty);
- COMPRESSED_POINTER_FIELD(ObjectPtr, key)
+ COMPRESSED_POINTER_FIELD(ObjectPtr, key) // Weak reference.
VISIT_FROM(key)
COMPRESSED_POINTER_FIELD(ObjectPtr, value)
VISIT_TO(value)
@@ -3273,8 +3287,10 @@
// Linked list is chaining all pending weak properties. Not visited by
// pointer visitors.
- CompressedWeakPropertyPtr next_;
+ COMPRESSED_POINTER_FIELD(WeakPropertyPtr, next_seen_by_gc)
+ template <typename Type, typename PtrType>
+ friend struct GCLinkedList;
friend class GCMarker;
template <bool>
friend class MarkingVisitorBase;
@@ -3288,7 +3304,7 @@
class UntaggedWeakReference : public UntaggedInstance {
RAW_HEAP_OBJECT_IMPLEMENTATION(WeakReference);
- COMPRESSED_POINTER_FIELD(ObjectPtr, target)
+ COMPRESSED_POINTER_FIELD(ObjectPtr, target) // Weak reference.
VISIT_FROM(target)
COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, type_arguments)
VISIT_TO(type_arguments)
@@ -3296,8 +3312,10 @@
// Linked list is chaining all pending weak properties. Not visited by
// pointer visitors.
- CompressedWeakReferencePtr next_;
+ COMPRESSED_POINTER_FIELD(WeakReferencePtr, next_seen_by_gc)
+ template <typename Type, typename PtrType>
+ friend struct GCLinkedList;
friend class GCMarker;
template <bool>
friend class MarkingVisitorBase;
@@ -3308,6 +3326,92 @@
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 <typename GCVisitorType>
+ friend void MournFinalized(GCVisitorType* visitor);
+ friend class GCMarker;
+ template <bool>
+ friend class MarkingVisitorBase;
+ friend class Scavenger;
+ template <bool>
+ 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 <std::memory_order order = std::memory_order_relaxed>
+ FinalizerEntryPtr exchange_entries_collected(FinalizerEntryPtr value) {
+ return ExchangeCompressedPointer<FinalizerEntryPtr,
+ CompressedFinalizerEntryPtr, order>(
+ &entries_collected_, value);
+ }
+
+ template <typename GCVisitorType>
+ friend void MournFinalized(GCVisitorType* visitor);
+ friend class GCMarker;
+ template <bool>
+ friend class MarkingVisitorBase;
+ friend class Scavenger;
+ template <bool>
+ 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 <typename Type, typename PtrType>
+ friend struct GCLinkedList;
+ template <typename GCVisitorType>
+ friend void MournFinalized(GCVisitorType* visitor);
+ friend class GCMarker;
+ template <bool>
+ friend class MarkingVisitorBase;
+ friend class Scavenger;
+ template <bool>
+ 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 7784041..7953a1f 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -137,6 +137,8 @@
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 @@
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 @@
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 0f53fe7..5a0b99f 100644
--- a/runtime/vm/tagged_pointer.h
+++ b/runtime/vm/tagged_pointer.h
@@ -413,6 +413,9 @@
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 78b3bab..79ff4aa 100644
--- a/sdk/lib/_internal/vm/lib/core_patch.dart
+++ b/sdk/lib/_internal/vm/lib/core_patch.dart
@@ -13,10 +13,14 @@
show
allocateOneByteString,
allocateTwoByteString,
+ checkValidWeakTarget,
ClassID,
CodeUnits,
copyRangeFromUint8ListToOneByteString,
EfficientLengthIterable,
+ FinalizerBase,
+ FinalizerBaseMembers,
+ FinalizerEntry,
FixedLengthListBase,
IterableElementError,
ListIterator,
@@ -28,11 +32,12 @@
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: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 cf34b7f..fd5bd93 100644
--- a/sdk/lib/_internal/vm/lib/expando_patch.dart
+++ b/sdk/lib/_internal/vm/lib/expando_patch.dart
@@ -28,7 +28,8 @@
@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 @@
@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 @@
}
}
- 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 @@
@patch
class WeakReference<T extends Object> {
@patch
- factory WeakReference(T object) = _WeakReferenceImpl<T>;
+ factory WeakReference(T target) = _WeakReferenceImpl<T>;
}
@pragma("vm:entry-point")
class _WeakReferenceImpl<T extends Object> implements WeakReference<T> {
- _WeakReferenceImpl(T object) {
- Expando._checkType(object);
- _target = object;
+ _WeakReferenceImpl(T target) {
+ checkValidWeakTarget(target, 'target');
+ _target = target;
}
@pragma("vm:recognized", "other")
@@ -190,11 +179,3 @@
@pragma("vm:external-name", "WeakReference_setTarget")
external set _target(T? value);
}
-
-@patch
-class Finalizer<T> {
- @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 aec537b..a9db853 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<T> {
+ @patch
+ factory Finalizer(void Function(T) callback) = _FinalizerImpl<T>;
+}
+
+@pragma("vm:entry-point")
+class _FinalizerImpl<T> extends FinalizerBase implements Finalizer<T> {
+ @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 = <FinalizerEntry>{};
+ _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] ??= <FinalizerEntry>{}).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<T>(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 4c0fa92..547835c 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 @@
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<WeakReference<FinalizerBase>>? get _isolateFinalizers;
+ @pragma("vm:recognized", "other")
+ @pragma("vm:prefer-inline")
+ external static set _isolateFinalizers(
+ List<WeakReference<FinalizerBase>>? 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 ??= <WeakReference<FinalizerBase>>[];
+ 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<FinalizerEntry> get _allEntries;
+ @pragma("vm:recognized", "other")
+ @pragma('vm:prefer-inline')
+ external set _allEntries(Set<FinalizerEntry> 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<Set<FinalizerEntry>>? get _detachments;
+ @pragma("vm:recognized", "other")
+ @pragma('vm:prefer-inline')
+ external set _detachments(Expando<Set<FinalizerEntry>>? 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<FinalizerEntry> get allEntries => _allEntries;
+ @pragma('vm:prefer-inline')
+ set allEntries(Set<FinalizerEntry> value) => _allEntries = value;
+
+ /// See documentation on [_exchangeEntriesCollectedWithNull].
+ FinalizerEntry? exchangeEntriesCollectedWithNull() =>
+ _exchangeEntriesCollectedWithNull();
+
+ /// See documentation on [_detachments].
+ @pragma('vm:prefer-inline')
+ Expando<Set<FinalizerEntry>> get detachments {
+ _detachments ??= Expando<Set<FinalizerEntry>>();
+ return unsafeCast<Expando<Set<FinalizerEntry>>>(_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 01ef31c..3c8f968 100644
--- a/sdk/lib/core/weak.dart
+++ b/sdk/lib/core/weak.dart
@@ -207,15 +207,15 @@
/// 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 @@
/// }
/// }
/// ```
- void detach(Object detachToken);
+ void detach(Object detach);
}
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index 96ef3e5..6b2b940 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -723,6 +723,7 @@
/// therefore not be sent.
/// - [ReceivePort]
/// - [DynamicLibrary]
+ /// - [Finalizer]
/// - [Pointer]
/// - [UserTag]
/// - `MirrorReference`
diff --git a/tools/VERSION b/tools/VERSION
index 98c53de..74cb2d0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 17
PATCH 0
-PRERELEASE 226
+PRERELEASE 227
PRERELEASE_PATCH 0
\ No newline at end of file