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 #ifndef V8_HEAP_CPPGC_MARKER_H_
6 #define V8_HEAP_CPPGC_MARKER_H_
7
8 #include <memory>
9
10 #include "include/cppgc/heap.h"
11 #include "include/cppgc/visitor.h"
12 #include "src/base/macros.h"
13 #include "src/base/platform/time.h"
14 #include "src/heap/base/worklist.h"
15 #include "src/heap/cppgc/concurrent-marker.h"
16 #include "src/heap/cppgc/globals.h"
17 #include "src/heap/cppgc/incremental-marking-schedule.h"
18 #include "src/heap/cppgc/marking-state.h"
19 #include "src/heap/cppgc/marking-visitor.h"
20 #include "src/heap/cppgc/marking-worklists.h"
21 #include "src/heap/cppgc/task-handle.h"
22
23 namespace cppgc {
24 namespace internal {
25
26 class HeapBase;
27 class MarkerFactory;
28
29 // Marking algorithm. Example for a valid call sequence creating the marking
30 // phase:
31 // 1. StartMarking() [Called implicitly when creating a Marker using
32 // MarkerFactory]
33 // 2. AdvanceMarkingWithDeadline() [Optional, depending on environment.]
34 // 3. EnterAtomicPause()
35 // 4. AdvanceMarkingWithDeadline()
36 // 5. LeaveAtomicPause()
37 //
38 // Alternatively, FinishMarking combines steps 3.-5.
39 class V8_EXPORT_PRIVATE MarkerBase {
40 public:
41 struct MarkingConfig {
42 enum class CollectionType : uint8_t {
43 kMinor,
44 kMajor,
45 };
46 using StackState = cppgc::Heap::StackState;
47 enum MarkingType : uint8_t {
48 kAtomic,
49 kIncremental,
50 kIncrementalAndConcurrent
51 };
52
DefaultMarkingConfig53 static constexpr MarkingConfig Default() { return {}; }
54
55 const CollectionType collection_type = CollectionType::kMajor;
56 StackState stack_state = StackState::kMayContainHeapPointers;
57 MarkingType marking_type = MarkingType::kIncremental;
58 };
59
60 virtual ~MarkerBase();
61
62 MarkerBase(const MarkerBase&) = delete;
63 MarkerBase& operator=(const MarkerBase&) = delete;
64
65 // Signals entering the atomic marking pause. The method
66 // - stops incremental/concurrent marking;
67 // - flushes back any in-construction worklists if needed;
68 // - Updates the MarkingConfig if the stack state has changed;
69 void EnterAtomicPause(MarkingConfig::StackState);
70
71 // Makes marking progress.
72 // TODO(chromium:1056170): Remove TimeDelta argument when unified heap no
73 // longer uses it.
74 bool AdvanceMarkingWithMaxDuration(v8::base::TimeDelta);
75
76 // Makes marking progress when allocation a new lab.
77 void AdvanceMarkingOnAllocation();
78
79 // Signals leaving the atomic marking pause. This method expects no more
80 // objects to be marked and merely updates marking states if needed.
81 void LeaveAtomicPause();
82
83 // Combines:
84 // - EnterAtomicPause()
85 // - AdvanceMarkingWithDeadline()
86 // - ProcessWeakness()
87 // - LeaveAtomicPause()
88 void FinishMarking(MarkingConfig::StackState);
89
90 void ProcessWeakness();
91
92 inline void WriteBarrierForInConstructionObject(HeapObjectHeader&);
93 inline void WriteBarrierForObject(HeapObjectHeader&);
94
heap()95 HeapBase& heap() { return heap_; }
96
MarkingWorklistsForTesting()97 MarkingWorklists& MarkingWorklistsForTesting() { return marking_worklists_; }
MutatorMarkingStateForTesting()98 MutatorMarkingState& MutatorMarkingStateForTesting() {
99 return mutator_marking_state_;
100 }
VisitorForTesting()101 cppgc::Visitor& VisitorForTesting() { return visitor(); }
102 void ClearAllWorklistsForTesting();
103
104 bool IncrementalMarkingStepForTesting(MarkingConfig::StackState);
105
106 class IncrementalMarkingTask final : public cppgc::Task {
107 public:
108 using Handle = SingleThreadedHandle;
109
110 IncrementalMarkingTask(MarkerBase*, MarkingConfig::StackState);
111
112 static Handle Post(cppgc::TaskRunner*, MarkerBase*);
113
114 private:
115 void Run() final;
116
117 MarkerBase* const marker_;
118 MarkingConfig::StackState stack_state_;
119 // TODO(chromium:1056170): Change to CancelableTask.
120 Handle handle_;
121 };
122
123 void DisableIncrementalMarkingForTesting();
124
125 void WaitForConcurrentMarkingForTesting();
126
127 void NotifyCompactionCancelled();
128
129 protected:
130 static constexpr v8::base::TimeDelta kMaximumIncrementalStepDuration =
131 v8::base::TimeDelta::FromMilliseconds(2);
132
133 class Key {
134 private:
135 Key() = default;
136 friend class MarkerFactory;
137 };
138
139 MarkerBase(Key, HeapBase&, cppgc::Platform*, MarkingConfig);
140
141 // Initialize marking according to the given config. This method will
142 // trigger incremental/concurrent marking if needed.
143 void StartMarking();
144
145 virtual cppgc::Visitor& visitor() = 0;
146 virtual ConservativeTracingVisitor& conservative_visitor() = 0;
147 virtual heap::base::StackVisitor& stack_visitor() = 0;
148
149 // Makes marking progress.
150 // TODO(chromium:1056170): Remove TimeDelta argument when unified heap no
151 // longer uses it.
152 bool AdvanceMarkingWithDeadline(
153 v8::base::TimeDelta = kMaximumIncrementalStepDuration);
154
155 bool ProcessWorklistsWithDeadline(size_t, v8::base::TimeTicks);
156
157 void VisitRoots(MarkingConfig::StackState);
158
159 void MarkNotFullyConstructedObjects();
160
161 void ScheduleIncrementalMarkingTask();
162
163 bool IncrementalMarkingStep(MarkingConfig::StackState);
164
165 HeapBase& heap_;
166 MarkingConfig config_ = MarkingConfig::Default();
167
168 cppgc::Platform* platform_;
169 std::shared_ptr<cppgc::TaskRunner> foreground_task_runner_;
170 IncrementalMarkingTask::Handle incremental_marking_handle_;
171
172 MarkingWorklists marking_worklists_;
173 MutatorMarkingState mutator_marking_state_;
174 bool is_marking_started_{false};
175
176 IncrementalMarkingSchedule schedule_;
177
178 std::unique_ptr<ConcurrentMarkerBase> concurrent_marker_{nullptr};
179
180 bool incremental_marking_disabled_for_testing_{false};
181
182 friend class MarkerFactory;
183 };
184
185 class V8_EXPORT_PRIVATE MarkerFactory {
186 public:
187 template <typename T, typename... Args>
CreateAndStartMarking(Args &&...args)188 static std::unique_ptr<T> CreateAndStartMarking(Args&&... args) {
189 static_assert(std::is_base_of<MarkerBase, T>::value,
190 "MarkerFactory can only create subclasses of MarkerBase");
191 std::unique_ptr<T> marker =
192 std::make_unique<T>(MarkerBase::Key(), std::forward<Args>(args)...);
193 marker->StartMarking();
194 return marker;
195 }
196 };
197
198 class V8_EXPORT_PRIVATE Marker final : public MarkerBase {
199 public:
200 Marker(Key, HeapBase&, cppgc::Platform*,
201 MarkingConfig = MarkingConfig::Default());
202
203 protected:
visitor()204 cppgc::Visitor& visitor() final { return marking_visitor_; }
conservative_visitor()205 ConservativeTracingVisitor& conservative_visitor() final {
206 return conservative_marking_visitor_;
207 }
stack_visitor()208 heap::base::StackVisitor& stack_visitor() final {
209 return conservative_marking_visitor_;
210 }
211
212 private:
213 MutatorMarkingVisitor marking_visitor_;
214 ConservativeMarkingVisitor conservative_marking_visitor_;
215 };
216
WriteBarrierForInConstructionObject(HeapObjectHeader & header)217 void MarkerBase::WriteBarrierForInConstructionObject(HeapObjectHeader& header) {
218 mutator_marking_state_.not_fully_constructed_worklist()
219 .Push<AccessMode::kAtomic>(&header);
220 }
221
WriteBarrierForObject(HeapObjectHeader & header)222 void MarkerBase::WriteBarrierForObject(HeapObjectHeader& header) {
223 mutator_marking_state_.write_barrier_worklist().Push(&header);
224 }
225
226 } // namespace internal
227 } // namespace cppgc
228
229 #endif // V8_HEAP_CPPGC_MARKER_H_
230