1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/heap/cppgc/prefinalizer-handler.h"
6
7 #include <algorithm>
8 #include <memory>
9
10 #include "src/base/platform/platform.h"
11 #include "src/heap/cppgc/heap-page.h"
12 #include "src/heap/cppgc/heap.h"
13 #include "src/heap/cppgc/liveness-broker.h"
14 #include "src/heap/cppgc/stats-collector.h"
15
16 namespace cppgc {
17 namespace internal {
18
PrefinalizerRegistration(void * object,Callback callback)19 PrefinalizerRegistration::PrefinalizerRegistration(void* object,
20 Callback callback) {
21 auto* page = BasePage::FromPayload(object);
22 DCHECK(!page->space().is_compactable());
23 page->heap().prefinalizer_handler()->RegisterPrefinalizer({object, callback});
24 }
25
operator ==(const PreFinalizer & other) const26 bool PreFinalizer::operator==(const PreFinalizer& other) const {
27 return (object == other.object) && (callback == other.callback);
28 }
29
PreFinalizerHandler(HeapBase & heap)30 PreFinalizerHandler::PreFinalizerHandler(HeapBase& heap)
31 : current_ordered_pre_finalizers_(&ordered_pre_finalizers_),
32 heap_(heap)
33 #ifdef DEBUG
34 ,
35 creation_thread_id_(v8::base::OS::GetCurrentThreadId())
36 #endif // DEBUG
37 {
38 }
39
RegisterPrefinalizer(PreFinalizer pre_finalizer)40 void PreFinalizerHandler::RegisterPrefinalizer(PreFinalizer pre_finalizer) {
41 DCHECK(CurrentThreadIsCreationThread());
42 DCHECK_EQ(ordered_pre_finalizers_.end(),
43 std::find(ordered_pre_finalizers_.begin(),
44 ordered_pre_finalizers_.end(), pre_finalizer));
45 DCHECK_EQ(current_ordered_pre_finalizers_->end(),
46 std::find(current_ordered_pre_finalizers_->begin(),
47 current_ordered_pre_finalizers_->end(), pre_finalizer));
48 current_ordered_pre_finalizers_->push_back(pre_finalizer);
49 }
50
InvokePreFinalizers()51 void PreFinalizerHandler::InvokePreFinalizers() {
52 StatsCollector::EnabledScope stats_scope(heap_.stats_collector(),
53 StatsCollector::kAtomicSweep);
54 StatsCollector::EnabledScope nested_stats_scope(
55 heap_.stats_collector(), StatsCollector::kSweepInvokePreFinalizers);
56
57 DCHECK(CurrentThreadIsCreationThread());
58 LivenessBroker liveness_broker = LivenessBrokerFactory::Create();
59 is_invoking_ = true;
60 DCHECK_EQ(0u, bytes_allocated_in_prefinalizers);
61 // Reset all LABs to force allocations to the slow path for black allocation.
62 heap_.object_allocator().ResetLinearAllocationBuffers();
63 // Prefinalizers can allocate other objects with prefinalizers, which will
64 // modify ordered_pre_finalizers_ and break iterators.
65 std::vector<PreFinalizer> new_ordered_pre_finalizers;
66 current_ordered_pre_finalizers_ = &new_ordered_pre_finalizers;
67 ordered_pre_finalizers_.erase(
68 ordered_pre_finalizers_.begin(),
69 std::remove_if(ordered_pre_finalizers_.rbegin(),
70 ordered_pre_finalizers_.rend(),
71 [liveness_broker](const PreFinalizer& pf) {
72 return (pf.callback)(liveness_broker, pf.object);
73 })
74 .base());
75 // Newly added objects with prefinalizers will always survive the current GC
76 // cycle, so it's safe to add them after clearing out the older prefinalizers.
77 ordered_pre_finalizers_.insert(ordered_pre_finalizers_.end(),
78 new_ordered_pre_finalizers.begin(),
79 new_ordered_pre_finalizers.end());
80 current_ordered_pre_finalizers_ = &ordered_pre_finalizers_;
81 is_invoking_ = false;
82 ordered_pre_finalizers_.shrink_to_fit();
83 }
84
CurrentThreadIsCreationThread()85 bool PreFinalizerHandler::CurrentThreadIsCreationThread() {
86 #ifdef DEBUG
87 return creation_thread_id_ == v8::base::OS::GetCurrentThreadId();
88 #else
89 return true;
90 #endif
91 }
92
NotifyAllocationInPrefinalizer(size_t size)93 void PreFinalizerHandler::NotifyAllocationInPrefinalizer(size_t size) {
94 DCHECK_GT(bytes_allocated_in_prefinalizers + size,
95 bytes_allocated_in_prefinalizers);
96 bytes_allocated_in_prefinalizers += size;
97 }
98
99 } // namespace internal
100 } // namespace cppgc
101