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
16namespace cppgc {
17namespace internal {
18
19PrefinalizerRegistration::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
26bool PreFinalizer::operator==(const PreFinalizer& other) const {
27  return (object == other.object) && (callback == other.callback);
28}
29
30PreFinalizerHandler::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
40void 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
51void 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
85bool PreFinalizerHandler::CurrentThreadIsCreationThread() {
86#ifdef DEBUG
87  return creation_thread_id_ == v8::base::OS::GetCurrentThreadId();
88#else
89  return true;
90#endif
91}
92
93void 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