• 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 #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