1 // Copyright 2019 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_MARKING_VISITOR_H_
6 #define V8_HEAP_MARKING_VISITOR_H_
7 
8 #include "src/common/globals.h"
9 #include "src/heap/marking-worklist.h"
10 #include "src/heap/marking.h"
11 #include "src/heap/objects-visiting.h"
12 #include "src/heap/spaces.h"
13 #include "src/heap/worklist.h"
14 #include "src/objects/heap-object.h"   // For Worklist<HeapObject, ...>
15 #include "src/objects/js-weak-refs.h"  // For Worklist<WeakCell, ...>
16 
17 namespace v8 {
18 namespace internal {
19 
20 struct Ephemeron {
21   HeapObject key;
22   HeapObject value;
23 };
24 
25 using EphemeronWorklist = Worklist<Ephemeron, 64>;
26 
27 // Weak objects encountered during marking.
28 struct WeakObjects {
29   Worklist<TransitionArray, 64> transition_arrays;
30 
31   // Keep track of all EphemeronHashTables in the heap to process
32   // them in the atomic pause.
33   Worklist<EphemeronHashTable, 64> ephemeron_hash_tables;
34 
35   // Keep track of all ephemerons for concurrent marking tasks. Only store
36   // ephemerons in these Worklists if both key and value are unreachable at the
37   // moment.
38   //
39   // MarkCompactCollector::ProcessEphemeronsUntilFixpoint drains and fills these
40   // worklists.
41   //
42   // current_ephemerons is used as draining worklist in the current fixpoint
43   // iteration.
44   EphemeronWorklist current_ephemerons;
45 
46   // Stores ephemerons to visit in the next fixpoint iteration.
47   EphemeronWorklist next_ephemerons;
48 
49   // When draining the marking worklist new discovered ephemerons are pushed
50   // into this worklist.
51   EphemeronWorklist discovered_ephemerons;
52 
53   // TODO(marja): For old space, we only need the slot, not the host
54   // object. Optimize this by adding a different storage for old space.
55   Worklist<std::pair<HeapObject, HeapObjectSlot>, 64> weak_references;
56   Worklist<std::pair<HeapObject, Code>, 64> weak_objects_in_code;
57 
58   Worklist<JSWeakRef, 64> js_weak_refs;
59   Worklist<WeakCell, 64> weak_cells;
60 
61   Worklist<SharedFunctionInfo, 64> bytecode_flushing_candidates;
62   Worklist<JSFunction, 64> flushed_js_functions;
63 };
64 
65 struct EphemeronMarking {
66   std::vector<HeapObject> newly_discovered;
67   bool newly_discovered_overflowed;
68   size_t newly_discovered_limit;
69 };
70 
71 template <typename ConcreteState, AccessMode access_mode>
72 class MarkingStateBase {
73  public:
MarkBitFrom(HeapObject obj)74   V8_INLINE MarkBit MarkBitFrom(HeapObject obj) {
75     return MarkBitFrom(MemoryChunk::FromHeapObject(obj), obj.ptr());
76   }
77 
78   // {addr} may be tagged or aligned.
MarkBitFrom(MemoryChunk * p,Address addr)79   V8_INLINE MarkBit MarkBitFrom(MemoryChunk* p, Address addr) {
80     return static_cast<ConcreteState*>(this)->bitmap(p)->MarkBitFromIndex(
81         p->AddressToMarkbitIndex(addr));
82   }
83 
Color(HeapObject obj)84   Marking::ObjectColor Color(HeapObject obj) {
85     return Marking::Color(MarkBitFrom(obj));
86   }
87 
IsImpossible(HeapObject obj)88   V8_INLINE bool IsImpossible(HeapObject obj) {
89     return Marking::IsImpossible<access_mode>(MarkBitFrom(obj));
90   }
91 
IsBlack(HeapObject obj)92   V8_INLINE bool IsBlack(HeapObject obj) {
93     return Marking::IsBlack<access_mode>(MarkBitFrom(obj));
94   }
95 
IsWhite(HeapObject obj)96   V8_INLINE bool IsWhite(HeapObject obj) {
97     return Marking::IsWhite<access_mode>(MarkBitFrom(obj));
98   }
99 
IsGrey(HeapObject obj)100   V8_INLINE bool IsGrey(HeapObject obj) {
101     return Marking::IsGrey<access_mode>(MarkBitFrom(obj));
102   }
103 
IsBlackOrGrey(HeapObject obj)104   V8_INLINE bool IsBlackOrGrey(HeapObject obj) {
105     return Marking::IsBlackOrGrey<access_mode>(MarkBitFrom(obj));
106   }
107 
WhiteToGrey(HeapObject obj)108   V8_INLINE bool WhiteToGrey(HeapObject obj) {
109     return Marking::WhiteToGrey<access_mode>(MarkBitFrom(obj));
110   }
111 
WhiteToBlack(HeapObject obj)112   V8_INLINE bool WhiteToBlack(HeapObject obj) {
113     return WhiteToGrey(obj) && GreyToBlack(obj);
114   }
115 
GreyToBlack(HeapObject obj)116   V8_INLINE bool GreyToBlack(HeapObject obj) {
117     MemoryChunk* p = MemoryChunk::FromHeapObject(obj);
118     MarkBit markbit = MarkBitFrom(p, obj.address());
119     if (!Marking::GreyToBlack<access_mode>(markbit)) return false;
120     static_cast<ConcreteState*>(this)->IncrementLiveBytes(p, obj.Size());
121     return true;
122   }
123 
ClearLiveness(MemoryChunk * chunk)124   void ClearLiveness(MemoryChunk* chunk) {
125     static_cast<ConcreteState*>(this)->bitmap(chunk)->Clear();
126     static_cast<ConcreteState*>(this)->SetLiveBytes(chunk, 0);
127   }
128 };
129 
130 // The base class for all marking visitors. It implements marking logic with
131 // support of bytecode flushing, embedder tracing, weak and references.
132 //
133 // Derived classes are expected to provide the following:
134 // - ConcreteVisitor::marking_state method,
135 // - ConcreteVisitor::retaining_path_mode method,
136 // - ConcreteVisitor::RecordSlot method,
137 // - ConcreteVisitor::RecordRelocSlot method,
138 // - ConcreteVisitor::SynchronizePageAccess method,
139 // - ConcreteVisitor::VisitJSObjectSubclass method,
140 // - ConcreteVisitor::VisitLeftTrimmableArray method.
141 // These methods capture the difference between the concurrent and main thread
142 // marking visitors. For example, the concurrent visitor has to use the
143 // snapshotting protocol to visit JSObject and left-trimmable FixedArrays.
144 
145 template <typename ConcreteVisitor, typename MarkingState>
146 class MarkingVisitorBase : public HeapVisitor<int, ConcreteVisitor> {
147  public:
MarkingVisitorBase(int task_id,MarkingWorklists * marking_worklists,WeakObjects * weak_objects,Heap * heap,unsigned mark_compact_epoch,BytecodeFlushMode bytecode_flush_mode,bool is_embedder_tracing_enabled,bool is_forced_gc)148   MarkingVisitorBase(int task_id, MarkingWorklists* marking_worklists,
149                      WeakObjects* weak_objects, Heap* heap,
150                      unsigned mark_compact_epoch,
151                      BytecodeFlushMode bytecode_flush_mode,
152                      bool is_embedder_tracing_enabled, bool is_forced_gc)
153       : marking_worklists_(marking_worklists),
154         weak_objects_(weak_objects),
155         heap_(heap),
156         task_id_(task_id),
157         mark_compact_epoch_(mark_compact_epoch),
158         bytecode_flush_mode_(bytecode_flush_mode),
159         is_embedder_tracing_enabled_(is_embedder_tracing_enabled),
160         is_forced_gc_(is_forced_gc) {}
161 
162   V8_INLINE int VisitBytecodeArray(Map map, BytecodeArray object);
163   V8_INLINE int VisitDescriptorArray(Map map, DescriptorArray object);
164   V8_INLINE int VisitEphemeronHashTable(Map map, EphemeronHashTable object);
165   V8_INLINE int VisitFixedArray(Map map, FixedArray object);
166   V8_INLINE int VisitFixedDoubleArray(Map map, FixedDoubleArray object);
167   V8_INLINE int VisitJSApiObject(Map map, JSObject object);
168   V8_INLINE int VisitJSArrayBuffer(Map map, JSArrayBuffer object);
169   V8_INLINE int VisitJSDataView(Map map, JSDataView object);
170   V8_INLINE int VisitJSFunction(Map map, JSFunction object);
171   V8_INLINE int VisitJSTypedArray(Map map, JSTypedArray object);
172   V8_INLINE int VisitJSWeakRef(Map map, JSWeakRef object);
173   V8_INLINE int VisitMap(Map map, Map object);
174   V8_INLINE int VisitSharedFunctionInfo(Map map, SharedFunctionInfo object);
175   V8_INLINE int VisitTransitionArray(Map map, TransitionArray object);
176   V8_INLINE int VisitWeakCell(Map map, WeakCell object);
177 
178   // ObjectVisitor overrides.
VisitPointer(HeapObject host,ObjectSlot p)179   V8_INLINE void VisitPointer(HeapObject host, ObjectSlot p) final {
180     VisitPointersImpl(host, p, p + 1);
181   }
VisitPointer(HeapObject host,MaybeObjectSlot p)182   V8_INLINE void VisitPointer(HeapObject host, MaybeObjectSlot p) final {
183     VisitPointersImpl(host, p, p + 1);
184   }
VisitPointers(HeapObject host,ObjectSlot start,ObjectSlot end)185   V8_INLINE void VisitPointers(HeapObject host, ObjectSlot start,
186                                ObjectSlot end) final {
187     VisitPointersImpl(host, start, end);
188   }
VisitPointers(HeapObject host,MaybeObjectSlot start,MaybeObjectSlot end)189   V8_INLINE void VisitPointers(HeapObject host, MaybeObjectSlot start,
190                                MaybeObjectSlot end) final {
191     VisitPointersImpl(host, start, end);
192   }
193   V8_INLINE void VisitEmbeddedPointer(Code host, RelocInfo* rinfo) final;
194   V8_INLINE void VisitCodeTarget(Code host, RelocInfo* rinfo) final;
VisitCustomWeakPointers(HeapObject host,ObjectSlot start,ObjectSlot end)195   void VisitCustomWeakPointers(HeapObject host, ObjectSlot start,
196                                ObjectSlot end) final {
197     // Weak list pointers should be ignored during marking. The lists are
198     // reconstructed after GC.
199   }
200 
201  protected:
concrete_visitor()202   ConcreteVisitor* concrete_visitor() {
203     return static_cast<ConcreteVisitor*>(this);
204   }
205   template <typename THeapObjectSlot>
206   void ProcessStrongHeapObject(HeapObject host, THeapObjectSlot slot,
207                                HeapObject heap_object);
208   template <typename THeapObjectSlot>
209   void ProcessWeakHeapObject(HeapObject host, THeapObjectSlot slot,
210                              HeapObject heap_object);
211 
212   template <typename TSlot>
213   V8_INLINE void VisitPointerImpl(HeapObject host, TSlot p);
214 
215   template <typename TSlot>
216   V8_INLINE void VisitPointersImpl(HeapObject host, TSlot start, TSlot end);
217 
218   V8_INLINE void VisitDescriptors(DescriptorArray descriptors,
219                                   int number_of_own_descriptors);
220   template <typename T>
221   int VisitEmbedderTracingSubclass(Map map, T object);
222   V8_INLINE int VisitFixedArrayWithProgressBar(Map map, FixedArray object,
223                                                MemoryChunk* chunk);
224   // Marks the descriptor array black without pushing it on the marking work
225   // list and visits its header. Returns the size of the descriptor array
226   // if it was successully marked as black.
227   V8_INLINE size_t MarkDescriptorArrayBlack(HeapObject host,
228                                             DescriptorArray descriptors);
229   // Marks the object grey and pushes it on the marking work list.
230   V8_INLINE void MarkObject(HeapObject host, HeapObject obj);
231 
232   MarkingWorklists* const marking_worklists_;
233   WeakObjects* const weak_objects_;
234   Heap* const heap_;
235   const int task_id_;
236   const unsigned mark_compact_epoch_;
237   const BytecodeFlushMode bytecode_flush_mode_;
238   const bool is_embedder_tracing_enabled_;
239   const bool is_forced_gc_;
240 };
241 
242 }  // namespace internal
243 }  // namespace v8
244 
245 #endif  // V8_HEAP_MARKING_VISITOR_H_
246