• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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