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
28 // Marking algorithm. Example for a valid call sequence creating the marking
29 // phase:
30 // 1. StartMarking()
31 // 2. AdvanceMarkingWithLimits() [Optional, depending on environment.]
32 // 3. EnterAtomicPause()
33 // 4. AdvanceMarkingWithLimits()
34 // 5. LeaveAtomicPause()
35 //
36 // Alternatively, FinishMarking combines steps 3.-5.
37 class V8_EXPORT_PRIVATE MarkerBase {
38 public:
39 class IncrementalMarkingTask;
40
41 struct MarkingConfig {
42 enum class CollectionType : uint8_t {
43 kMinor,
44 kMajor,
45 };
46 using StackState = cppgc::Heap::StackState;
47 using MarkingType = cppgc::Heap::MarkingType;
48 enum class IsForcedGC : uint8_t {
49 kNotForced,
50 kForced,
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 IsForcedGC is_forced_gc = IsForcedGC::kNotForced;
59 };
60
61 enum class WriteBarrierType {
62 kDijkstra,
63 kSteele,
64 };
65
66 // Pauses concurrent marking if running while this scope is active.
67 class PauseConcurrentMarkingScope final {
68 public:
69 explicit PauseConcurrentMarkingScope(MarkerBase&);
70 ~PauseConcurrentMarkingScope();
71
72 private:
73 MarkerBase& marker_;
74 const bool resume_on_exit_;
75 };
76
77 virtual ~MarkerBase();
78
79 MarkerBase(const MarkerBase&) = delete;
80 MarkerBase& operator=(const MarkerBase&) = delete;
81
82 // Signals entering the atomic marking pause. The method
83 // - stops incremental/concurrent marking;
84 // - flushes back any in-construction worklists if needed;
85 // - Updates the MarkingConfig if the stack state has changed;
86 void EnterAtomicPause(MarkingConfig::StackState);
87
88 // Makes marking progress. A `marked_bytes_limit` of 0 means that the limit
89 // is determined by the internal marking scheduler.
90 //
91 // TODO(chromium:1056170): Remove TimeDelta argument when unified heap no
92 // longer uses it.
93 bool AdvanceMarkingWithLimits(
94 v8::base::TimeDelta = kMaximumIncrementalStepDuration,
95 size_t marked_bytes_limit = 0);
96
97 // Signals leaving the atomic marking pause. This method expects no more
98 // objects to be marked and merely updates marking states if needed.
99 void LeaveAtomicPause();
100
101 // Initialize marking according to the given config. This method will
102 // trigger incremental/concurrent marking if needed.
103 void StartMarking();
104
105 // Combines:
106 // - EnterAtomicPause()
107 // - AdvanceMarkingWithLimits()
108 // - ProcessWeakness()
109 // - LeaveAtomicPause()
110 void FinishMarking(MarkingConfig::StackState);
111
112 void ProcessWeakness();
113
114 bool JoinConcurrentMarkingIfNeeded();
115
116 inline void WriteBarrierForInConstructionObject(HeapObjectHeader&);
117
118 template <WriteBarrierType type>
119 inline void WriteBarrierForObject(HeapObjectHeader&);
120
heap()121 HeapBase& heap() { return heap_; }
122
Visitor()123 cppgc::Visitor& Visitor() { return visitor(); }
124
IsMarking()125 bool IsMarking() const { return is_marking_; }
126
127 void SetMainThreadMarkingDisabledForTesting(bool);
128 void WaitForConcurrentMarkingForTesting();
129 void ClearAllWorklistsForTesting();
130 bool IncrementalMarkingStepForTesting(MarkingConfig::StackState);
131
MarkingWorklistsForTesting()132 MarkingWorklists& MarkingWorklistsForTesting() { return marking_worklists_; }
MutatorMarkingStateForTesting()133 MutatorMarkingState& MutatorMarkingStateForTesting() {
134 return mutator_marking_state_;
135 }
136
137 protected:
138 class IncrementalMarkingAllocationObserver;
139
140 using IncrementalMarkingTaskHandle = SingleThreadedHandle;
141
142 static constexpr v8::base::TimeDelta kMaximumIncrementalStepDuration =
143 v8::base::TimeDelta::FromMilliseconds(2);
144
145 MarkerBase(HeapBase&, cppgc::Platform*, MarkingConfig);
146
147 virtual cppgc::Visitor& visitor() = 0;
148 virtual ConservativeTracingVisitor& conservative_visitor() = 0;
149 virtual heap::base::StackVisitor& stack_visitor() = 0;
150
151 bool ProcessWorklistsWithDeadline(size_t, v8::base::TimeTicks);
152
153 void VisitRoots(MarkingConfig::StackState);
154
155 bool VisitCrossThreadPersistentsIfNeeded();
156
157 void MarkNotFullyConstructedObjects();
158
159 void ScheduleIncrementalMarkingTask();
160
161 bool IncrementalMarkingStep(MarkingConfig::StackState);
162
163 void AdvanceMarkingOnAllocation();
164
165 void HandleNotFullyConstructedObjects();
166
167 HeapBase& heap_;
168 MarkingConfig config_ = MarkingConfig::Default();
169
170 cppgc::Platform* platform_;
171 std::shared_ptr<cppgc::TaskRunner> foreground_task_runner_;
172 IncrementalMarkingTaskHandle incremental_marking_handle_;
173 std::unique_ptr<IncrementalMarkingAllocationObserver>
174 incremental_marking_allocation_observer_;
175
176 MarkingWorklists marking_worklists_;
177 MutatorMarkingState mutator_marking_state_;
178 bool is_marking_{false};
179
180 IncrementalMarkingSchedule schedule_;
181
182 std::unique_ptr<ConcurrentMarkerBase> concurrent_marker_{nullptr};
183
184 bool main_marking_disabled_for_testing_{false};
185 bool visited_cross_thread_persistents_in_atomic_pause_{false};
186 };
187
188 class V8_EXPORT_PRIVATE Marker final : public MarkerBase {
189 public:
190 Marker(HeapBase&, cppgc::Platform*, MarkingConfig = MarkingConfig::Default());
191
192 protected:
visitor()193 cppgc::Visitor& visitor() final { return marking_visitor_; }
conservative_visitor()194 ConservativeTracingVisitor& conservative_visitor() final {
195 return conservative_marking_visitor_;
196 }
stack_visitor()197 heap::base::StackVisitor& stack_visitor() final {
198 return conservative_marking_visitor_;
199 }
200
201 private:
202 MutatorMarkingVisitor marking_visitor_;
203 ConservativeMarkingVisitor conservative_marking_visitor_;
204 };
205
WriteBarrierForInConstructionObject(HeapObjectHeader & header)206 void MarkerBase::WriteBarrierForInConstructionObject(HeapObjectHeader& header) {
207 mutator_marking_state_.not_fully_constructed_worklist()
208 .Push<AccessMode::kAtomic>(&header);
209 }
210
211 template <MarkerBase::WriteBarrierType type>
WriteBarrierForObject(HeapObjectHeader & header)212 void MarkerBase::WriteBarrierForObject(HeapObjectHeader& header) {
213 switch (type) {
214 case MarkerBase::WriteBarrierType::kDijkstra:
215 mutator_marking_state_.write_barrier_worklist().Push(&header);
216 break;
217 case MarkerBase::WriteBarrierType::kSteele:
218 mutator_marking_state_.retrace_marked_objects_worklist().Push(&header);
219 break;
220 }
221 }
222
223 } // namespace internal
224 } // namespace cppgc
225
226 #endif // V8_HEAP_CPPGC_MARKER_H_
227