Skip to content

Commit 4b322a3

Browse files
dcharkesCommit Bot
authored andcommitted
[vm] Finalizer / NativeFinalizer fixes
1. Run native finalizers before sending isolate exit message. This way users can rely on the isolate exit message for both (1) no Dart code executing anymore on that isolate _and_ (2) all native finalizers having run. Alternatively, we could opt to not provide this second guarantee and document this. 2. Fix UBSAN error by making SetArgumentTo42's argument a `void*`. 3. Fix bug in debug mode, stop reading tags from forwarding addresses. 4. Small optimization: Don't promote 0 bytes from new to old space. 5. Skip finalizer_isolate_groups_run_gc_test in optcounter mode. In hot reload mode, GC is guaranteed to run. On all other bots GC does not run (nothing happens in the other isolate group). However, in optcounter mode enough happens in the other isolate group to trigger GCs. Alternatively, we could loosen the test to allow either a GC to happen or not. TEST=runtime/tests/vm/dart(_2)/finalizer/* TEST=runtime/tests/vm/dart(_2)/isolates/fast_object_copy_test.dart TEST=runtime/vm/object_test.cc TEST=tests/ffi(_2)/vmspecific_native_finalizer_* Closes: #48740 Closes: #48715 Closes: #48674 Change-Id: I5e260e087aef48524f2214f5b332caeda18f2e37 Cq-Include-Trybots: luci.dart.try:vm-kernel-ubsan-linux-release-x64-try,vm-kernel-precomp-ubsan-linux-release-x64-try,vm-canary-linux-debug-try,vm-kernel-optcounter-threshold-linux-release-x64-try,vm-kernel-optcounter-threshold-linux-release-ia32-try,app-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240043 Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
1 parent 139385c commit 4b322a3

File tree

7 files changed

+49
-22
lines changed

7 files changed

+49
-22
lines changed

runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,8 +1111,8 @@ DART_EXPORT void ReleaseClosureCallback() {
11111111
////////////////////////////////////////////////////////////////////////////////
11121112
// NativeFinalizer tests
11131113

1114-
DART_EXPORT void SetArgumentTo42(intptr_t* token) {
1115-
*token = 42;
1114+
DART_EXPORT void SetArgumentTo42(void* token) {
1115+
*reinterpret_cast<intptr_t*>(token) = 42;
11161116
}
11171117

11181118
////////////////////////////////////////////////////////////////////////////////

runtime/lib/ffi.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,10 +273,10 @@ DEFINE_FFI_NATIVE_ENTRY(FinalizerEntry_SetExternalSize,
273273
}
274274
// The next call cannot be in safepoint.
275275
if (external_size_diff > 0) {
276-
IsolateGroup::Current()->heap()->AllocatedExternal(external_size_diff,
276+
thread->isolate_group()->heap()->AllocatedExternal(external_size_diff,
277277
space);
278278
} else {
279-
IsolateGroup::Current()->heap()->FreedExternal(-external_size_diff, space);
279+
thread->isolate_group()->heap()->FreedExternal(-external_size_diff, space);
280280
}
281281
};
282282

runtime/tests/vm/vm.status

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,12 @@ dart_2/causal_stacks/sync_async_start_pkg_test_test: SkipByDesign # Asserts exac
5858
[ $builder_tag == optimization_counter_threshold ]
5959
cc/*: Skip # Many tests want see unoptimized code running
6060
dart/appjit*: SkipByDesign # Test needs to a particular opt-counter value
61+
dart/finalizer/finalizer_isolate_groups_run_gc_test: SkipByDesign # GC happens at unpredictable times.
6162
dart/kernel_determinism_test: SkipSlow
6263
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
6364
dart/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
6465
dart_2/appjit*: SkipByDesign # Test needs to a particular opt-counter value
66+
dart_2/finalizer/finalizer_isolate_groups_run_gc_test: SkipByDesign # GC happens at unpredictable times.
6567
dart_2/kernel_determinism_test: SkipSlow
6668
dart_2/minimal_kernel_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
6769
dart_2/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold

runtime/vm/heap/gc_shared.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ void GCLinkedLists::FlushInto(GCLinkedLists* to) {
3737
}
3838

3939
Heap::Space SpaceForExternal(FinalizerEntryPtr raw_entry) {
40-
ASSERT(!raw_entry->untag()->value().IsSmi());
40+
// Not Smi, these cannot be integers. They either need to be valid Expando
41+
// keys (Finalizer) or Finalizable (NativeFinalizer).
42+
ASSERT(raw_entry->untag()->value().IsHeapObject());
4143
return raw_entry->untag()->value()->IsOldObject() ? Heap::kOld : Heap::kNew;
4244
}
4345

runtime/vm/heap/scavenger.cc

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,9 +1212,13 @@ void Scavenger::IterateStoreBuffers(ScavengerVisitorBase<parallel>* visitor) {
12121212
if (UNLIKELY(class_id == kFinalizerEntryCid)) {
12131213
FinalizerEntryPtr raw_entry =
12141214
static_cast<FinalizerEntryPtr>(raw_object);
1215+
if (FLAG_trace_finalizers) {
1216+
THR_Print("Scavenger::IterateStoreBuffers Processing Entry %p\n",
1217+
raw_entry->untag());
1218+
}
12151219
// Detect `FinalizerEntry::value` promotion to update external space.
12161220
//
1217-
// This treats old-space FinalizerEntry fields as strong. Values, deatch
1221+
// This treats old-space FinalizerEntry fields as strong. Values, detach
12181222
// keys, and finalizers in new space won't be reclaimed until after they
12191223
// are promoted.
12201224
// This will only visit the strong references, end enqueue the entry.
@@ -1225,13 +1229,15 @@ void Scavenger::IterateStoreBuffers(ScavengerVisitorBase<parallel>* visitor) {
12251229
const Heap::Space after_gc_space = SpaceForExternal(raw_entry);
12261230
if (after_gc_space == Heap::kOld) {
12271231
const intptr_t external_size = raw_entry->untag()->external_size_;
1228-
if (FLAG_trace_finalizers) {
1229-
THR_Print(
1230-
"Scavenger %p Store buffer, promoting external size %" Pd
1231-
" bytes from new to old space\n",
1232-
visitor, external_size);
1232+
if (external_size > 0) {
1233+
if (FLAG_trace_finalizers) {
1234+
THR_Print(
1235+
"Scavenger %p Store buffer, promoting external size %" Pd
1236+
" bytes from new to old space\n",
1237+
visitor, external_size);
1238+
}
1239+
visitor->isolate_group()->heap()->PromotedExternal(external_size);
12331240
}
1234-
visitor->isolate_group()->heap()->PromotedExternal(external_size);
12351241
}
12361242
}
12371243
} else {

runtime/vm/isolate.cc

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2462,23 +2462,16 @@ void Isolate::ProcessFreeSampleBlocks(Thread* thread) {
24622462
}
24632463
#endif // !defined(PRODUCT)
24642464

2465-
void Isolate::LowLevelShutdown() {
2465+
void Isolate::RunAndCleanupFinalizersOnShutdown() {
2466+
if (finalizers_ == GrowableObjectArray::null()) return;
2467+
24662468
// Ensure we have a zone and handle scope so that we can call VM functions,
24672469
// but we no longer allocate new heap objects.
24682470
Thread* thread = Thread::Current();
24692471
StackZone stack_zone(thread);
24702472
HandleScope handle_scope(thread);
24712473
NoSafepointScope no_safepoint_scope;
24722474

2473-
// Notify exit listeners that this isolate is shutting down.
2474-
if (group()->object_store() != nullptr) {
2475-
const Error& error = Error::Handle(thread->sticky_error());
2476-
if (error.IsNull() || !error.IsUnwindError() ||
2477-
UnwindError::Cast(error).is_user_initiated()) {
2478-
NotifyExitListeners();
2479-
}
2480-
}
2481-
24822475
// Set live finalizers isolate to null, before deleting the message handler.
24832476
const auto& finalizers =
24842477
GrowableObjectArray::Handle(stack_zone.GetZone(), finalizers_);
@@ -2517,6 +2510,24 @@ void Isolate::LowLevelShutdown() {
25172510
}
25182511
}
25192512
}
2513+
}
2514+
2515+
void Isolate::LowLevelShutdown() {
2516+
// Ensure we have a zone and handle scope so that we can call VM functions,
2517+
// but we no longer allocate new heap objects.
2518+
Thread* thread = Thread::Current();
2519+
StackZone stack_zone(thread);
2520+
HandleScope handle_scope(thread);
2521+
NoSafepointScope no_safepoint_scope;
2522+
2523+
// Notify exit listeners that this isolate is shutting down.
2524+
if (group()->object_store() != nullptr) {
2525+
const Error& error = Error::Handle(thread->sticky_error());
2526+
if (error.IsNull() || !error.IsUnwindError() ||
2527+
UnwindError::Cast(error).is_user_initiated()) {
2528+
NotifyExitListeners();
2529+
}
2530+
}
25202531

25212532
// Close all the ports owned by this isolate.
25222533
PortMap::ClosePorts(message_handler());
@@ -2629,6 +2640,11 @@ void Isolate::Shutdown() {
26292640
// Then, proceed with low-level teardown.
26302641
Isolate::UnMarkIsolateReady(this);
26312642

2643+
// Ensure native finalizers are run before isolate has shutdown message is
2644+
// sent. This way users can rely on the exit message that an isolate will not
2645+
// run any Dart code anymore _and_ will not run any native finalizers anymore.
2646+
RunAndCleanupFinalizersOnShutdown();
2647+
26322648
// Post message before LowLevelShutdown that sends onExit message.
26332649
// This ensures that exit message comes last.
26342650
if (bequest_.get() != nullptr) {

runtime/vm/isolate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,7 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry<Isolate> {
14821482
void KillLocked(LibMsgId msg_id);
14831483

14841484
void Shutdown();
1485+
void RunAndCleanupFinalizersOnShutdown();
14851486
void LowLevelShutdown();
14861487

14871488
// Unregister the [isolate] from the thread, remove it from the isolate group,

0 commit comments

Comments
 (0)