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/memory-chunk.h" 12 #include "src/heap/objects-visiting.h" 13 #include "src/heap/spaces.h" 14 #include "src/heap/weak-object-worklists.h" 15 16 namespace v8 { 17 namespace internal { 18 19 struct EphemeronMarking { 20 std::vector<HeapObject> newly_discovered; 21 bool newly_discovered_overflowed; 22 size_t newly_discovered_limit; 23 }; 24 25 template <typename ConcreteState, AccessMode access_mode> 26 class MarkingStateBase { 27 public: 28 // Declares that this marking state is not collecting retainers, so the 29 // marking visitor may update the heap state to store information about 30 // progress, and may avoid fully visiting an object if it is safe to do so. 31 static constexpr bool kCollectRetainers = false; 32 MarkingStateBase(PtrComprCageBase cage_base)33 explicit MarkingStateBase(PtrComprCageBase cage_base) 34 #if V8_COMPRESS_POINTERS 35 : cage_base_(cage_base) 36 #endif 37 { 38 } 39 40 // The pointer compression cage base value used for decompression of all 41 // tagged values except references to Code objects. cage_base()42 V8_INLINE PtrComprCageBase cage_base() const { 43 #if V8_COMPRESS_POINTERS 44 return cage_base_; 45 #else 46 return PtrComprCageBase{}; 47 #endif // V8_COMPRESS_POINTERS 48 } 49 MarkBitFrom(HeapObject obj)50 V8_INLINE MarkBit MarkBitFrom(HeapObject obj) { 51 return MarkBitFrom(BasicMemoryChunk::FromHeapObject(obj), obj.ptr()); 52 } 53 54 // {addr} may be tagged or aligned. MarkBitFrom(BasicMemoryChunk * p,Address addr)55 V8_INLINE MarkBit MarkBitFrom(BasicMemoryChunk* p, Address addr) { 56 return static_cast<ConcreteState*>(this)->bitmap(p)->MarkBitFromIndex( 57 p->AddressToMarkbitIndex(addr)); 58 } 59 Color(HeapObject obj)60 Marking::ObjectColor Color(HeapObject obj) { 61 return Marking::Color(MarkBitFrom(obj)); 62 } 63 IsImpossible(HeapObject obj)64 V8_INLINE bool IsImpossible(HeapObject obj) { 65 return Marking::IsImpossible<access_mode>(MarkBitFrom(obj)); 66 } 67 IsBlack(HeapObject obj)68 V8_INLINE bool IsBlack(HeapObject obj) { 69 return Marking::IsBlack<access_mode>(MarkBitFrom(obj)); 70 } 71 IsWhite(HeapObject obj)72 V8_INLINE bool IsWhite(HeapObject obj) { 73 return Marking::IsWhite<access_mode>(MarkBitFrom(obj)); 74 } 75 IsGrey(HeapObject obj)76 V8_INLINE bool IsGrey(HeapObject obj) { 77 return Marking::IsGrey<access_mode>(MarkBitFrom(obj)); 78 } 79 IsBlackOrGrey(HeapObject obj)80 V8_INLINE bool IsBlackOrGrey(HeapObject obj) { 81 return Marking::IsBlackOrGrey<access_mode>(MarkBitFrom(obj)); 82 } 83 WhiteToGrey(HeapObject obj)84 V8_INLINE bool WhiteToGrey(HeapObject obj) { 85 return Marking::WhiteToGrey<access_mode>(MarkBitFrom(obj)); 86 } 87 WhiteToBlack(HeapObject obj)88 V8_INLINE bool WhiteToBlack(HeapObject obj) { 89 return WhiteToGrey(obj) && GreyToBlack(obj); 90 } 91 GreyToBlack(HeapObject obj)92 V8_INLINE bool GreyToBlack(HeapObject obj) { 93 BasicMemoryChunk* chunk = BasicMemoryChunk::FromHeapObject(obj); 94 MarkBit markbit = MarkBitFrom(chunk, obj.address()); 95 if (!Marking::GreyToBlack<access_mode>(markbit)) return false; 96 static_cast<ConcreteState*>(this)->IncrementLiveBytes( 97 MemoryChunk::cast(chunk), obj.Size(cage_base())); 98 return true; 99 } 100 GreyToBlackUnaccounted(HeapObject obj)101 V8_INLINE bool GreyToBlackUnaccounted(HeapObject obj) { 102 return Marking::GreyToBlack<access_mode>(MarkBitFrom(obj)); 103 } 104 ClearLiveness(MemoryChunk * chunk)105 void ClearLiveness(MemoryChunk* chunk) { 106 static_cast<ConcreteState*>(this)->bitmap(chunk)->Clear(); 107 static_cast<ConcreteState*>(this)->SetLiveBytes(chunk, 0); 108 } 109 AddStrongReferenceForReferenceSummarizer(HeapObject host,HeapObject obj)110 void AddStrongReferenceForReferenceSummarizer(HeapObject host, 111 HeapObject obj) { 112 // This is not a reference summarizer, so there is nothing to do here. 113 } 114 AddWeakReferenceForReferenceSummarizer(HeapObject host,HeapObject obj)115 void AddWeakReferenceForReferenceSummarizer(HeapObject host, HeapObject obj) { 116 // This is not a reference summarizer, so there is nothing to do here. 117 } 118 119 private: 120 #if V8_COMPRESS_POINTERS 121 const PtrComprCageBase cage_base_; 122 #endif // V8_COMPRESS_POINTERS 123 }; 124 125 // The base class for all marking visitors. It implements marking logic with 126 // support of bytecode flushing, embedder tracing, weak and references. 127 // 128 // Derived classes are expected to provide the following: 129 // - ConcreteVisitor::marking_state method, 130 // - ConcreteVisitor::retaining_path_mode method, 131 // - ConcreteVisitor::RecordSlot method, 132 // - ConcreteVisitor::RecordRelocSlot method, 133 // - ConcreteVisitor::SynchronizePageAccess method, 134 // - ConcreteVisitor::VisitJSObjectSubclass method, 135 // - ConcreteVisitor::VisitLeftTrimmableArray method. 136 // These methods capture the difference between the concurrent and main thread 137 // marking visitors. For example, the concurrent visitor has to use the 138 // snapshotting protocol to visit JSObject and left-trimmable FixedArrays. 139 140 template <typename ConcreteVisitor, typename MarkingState> 141 class MarkingVisitorBase : public HeapVisitor<int, ConcreteVisitor> { 142 public: MarkingVisitorBase(MarkingWorklists::Local * local_marking_worklists,WeakObjects::Local * local_weak_objects,Heap * heap,unsigned mark_compact_epoch,base::EnumSet<CodeFlushMode> code_flush_mode,bool is_embedder_tracing_enabled,bool should_keep_ages_unchanged)143 MarkingVisitorBase(MarkingWorklists::Local* local_marking_worklists, 144 WeakObjects::Local* local_weak_objects, Heap* heap, 145 unsigned mark_compact_epoch, 146 base::EnumSet<CodeFlushMode> code_flush_mode, 147 bool is_embedder_tracing_enabled, 148 bool should_keep_ages_unchanged) 149 : HeapVisitor<int, ConcreteVisitor>(heap), 150 local_marking_worklists_(local_marking_worklists), 151 local_weak_objects_(local_weak_objects), 152 heap_(heap), 153 mark_compact_epoch_(mark_compact_epoch), 154 code_flush_mode_(code_flush_mode), 155 is_embedder_tracing_enabled_(is_embedder_tracing_enabled), 156 should_keep_ages_unchanged_(should_keep_ages_unchanged), 157 is_shared_heap_(heap->IsShared()) 158 #ifdef V8_SANDBOXED_EXTERNAL_POINTERS 159 , 160 external_pointer_table_(&heap->isolate()->external_pointer_table()) 161 #endif // V8_SANDBOXED_EXTERNAL_POINTERS 162 { 163 } 164 165 V8_INLINE int VisitBytecodeArray(Map map, BytecodeArray object); 166 V8_INLINE int VisitDescriptorArray(Map map, DescriptorArray object); 167 V8_INLINE int VisitEphemeronHashTable(Map map, EphemeronHashTable object); 168 V8_INLINE int VisitFixedArray(Map map, FixedArray object); 169 V8_INLINE int VisitFixedDoubleArray(Map map, FixedDoubleArray object); 170 V8_INLINE int VisitJSApiObject(Map map, JSObject object); 171 V8_INLINE int VisitJSArrayBuffer(Map map, JSArrayBuffer object); 172 V8_INLINE int VisitJSDataView(Map map, JSDataView object); 173 V8_INLINE int VisitJSFunction(Map map, JSFunction object); 174 V8_INLINE int VisitJSTypedArray(Map map, JSTypedArray object); 175 V8_INLINE int VisitJSWeakRef(Map map, JSWeakRef object); 176 V8_INLINE int VisitMap(Map map, Map object); 177 V8_INLINE int VisitSharedFunctionInfo(Map map, SharedFunctionInfo object); 178 V8_INLINE int VisitTransitionArray(Map map, TransitionArray object); 179 V8_INLINE int VisitWeakCell(Map map, WeakCell object); 180 181 // ObjectVisitor overrides. VisitMapPointer(HeapObject host)182 void VisitMapPointer(HeapObject host) final { 183 Map map = host.map(ObjectVisitorWithCageBases::cage_base()); 184 MarkObject(host, map); 185 concrete_visitor()->RecordSlot(host, host.map_slot(), map); 186 } VisitPointer(HeapObject host,ObjectSlot p)187 V8_INLINE void VisitPointer(HeapObject host, ObjectSlot p) final { 188 VisitPointersImpl(host, p, p + 1); 189 } VisitPointer(HeapObject host,MaybeObjectSlot p)190 V8_INLINE void VisitPointer(HeapObject host, MaybeObjectSlot p) final { 191 VisitPointersImpl(host, p, p + 1); 192 } VisitPointers(HeapObject host,ObjectSlot start,ObjectSlot end)193 V8_INLINE void VisitPointers(HeapObject host, ObjectSlot start, 194 ObjectSlot end) final { 195 VisitPointersImpl(host, start, end); 196 } VisitPointers(HeapObject host,MaybeObjectSlot start,MaybeObjectSlot end)197 V8_INLINE void VisitPointers(HeapObject host, MaybeObjectSlot start, 198 MaybeObjectSlot end) final { 199 VisitPointersImpl(host, start, end); 200 } VisitCodePointer(HeapObject host,CodeObjectSlot slot)201 V8_INLINE void VisitCodePointer(HeapObject host, CodeObjectSlot slot) final { 202 VisitCodePointerImpl(host, slot); 203 } 204 V8_INLINE void VisitEmbeddedPointer(Code host, RelocInfo* rinfo) final; 205 V8_INLINE void VisitCodeTarget(Code host, RelocInfo* rinfo) final; VisitCustomWeakPointers(HeapObject host,ObjectSlot start,ObjectSlot end)206 void VisitCustomWeakPointers(HeapObject host, ObjectSlot start, 207 ObjectSlot end) final { 208 // Weak list pointers should be ignored during marking. The lists are 209 // reconstructed after GC. 210 } 211 VisitExternalPointer(HeapObject host,ExternalPointer_t ptr)212 V8_INLINE void VisitExternalPointer(HeapObject host, 213 ExternalPointer_t ptr) final { 214 #ifdef V8_SANDBOXED_EXTERNAL_POINTERS 215 uint32_t index = ptr >> kExternalPointerIndexShift; 216 external_pointer_table_->Mark(index); 217 #endif // V8_SANDBOXED_EXTERNAL_POINTERS 218 } 219 220 protected: concrete_visitor()221 ConcreteVisitor* concrete_visitor() { 222 return static_cast<ConcreteVisitor*>(this); 223 } 224 template <typename THeapObjectSlot> 225 void ProcessStrongHeapObject(HeapObject host, THeapObjectSlot slot, 226 HeapObject heap_object); 227 template <typename THeapObjectSlot> 228 void ProcessWeakHeapObject(HeapObject host, THeapObjectSlot slot, 229 HeapObject heap_object); 230 231 template <typename TSlot> 232 V8_INLINE void VisitPointerImpl(HeapObject host, TSlot p); 233 234 template <typename TSlot> 235 V8_INLINE void VisitPointersImpl(HeapObject host, TSlot start, TSlot end); 236 237 // Similar to VisitPointersImpl() but using code cage base for loading from 238 // the slot. 239 V8_INLINE void VisitCodePointerImpl(HeapObject host, CodeObjectSlot slot); 240 241 V8_INLINE void VisitDescriptors(DescriptorArray descriptors, 242 int number_of_own_descriptors); 243 244 V8_INLINE int VisitDescriptorsForMap(Map map); 245 246 template <typename T> 247 int VisitEmbedderTracingSubclass(Map map, T object); 248 template <typename T> 249 int VisitEmbedderTracingSubClassWithEmbedderTracing(Map map, T object); 250 template <typename T> 251 int VisitEmbedderTracingSubClassNoEmbedderTracing(Map map, T object); 252 253 V8_INLINE int VisitFixedArrayWithProgressBar(Map map, FixedArray object, 254 ProgressBar& progress_bar); 255 // Marks the descriptor array black without pushing it on the marking work 256 // list and visits its header. Returns the size of the descriptor array 257 // if it was successully marked as black. 258 V8_INLINE int MarkDescriptorArrayBlack(DescriptorArray descriptors); 259 // Marks the object grey and pushes it on the marking work list. 260 V8_INLINE void MarkObject(HeapObject host, HeapObject obj); 261 AddStrongReferenceForReferenceSummarizer(HeapObject host,HeapObject obj)262 V8_INLINE void AddStrongReferenceForReferenceSummarizer(HeapObject host, 263 HeapObject obj) { 264 concrete_visitor() 265 ->marking_state() 266 ->AddStrongReferenceForReferenceSummarizer(host, obj); 267 } 268 AddWeakReferenceForReferenceSummarizer(HeapObject host,HeapObject obj)269 V8_INLINE void AddWeakReferenceForReferenceSummarizer(HeapObject host, 270 HeapObject obj) { 271 concrete_visitor()->marking_state()->AddWeakReferenceForReferenceSummarizer( 272 host, obj); 273 } 274 CanUpdateValuesInHeap()275 constexpr bool CanUpdateValuesInHeap() { 276 return !MarkingState::kCollectRetainers; 277 } 278 279 MarkingWorklists::Local* const local_marking_worklists_; 280 WeakObjects::Local* const local_weak_objects_; 281 Heap* const heap_; 282 const unsigned mark_compact_epoch_; 283 const base::EnumSet<CodeFlushMode> code_flush_mode_; 284 const bool is_embedder_tracing_enabled_; 285 const bool should_keep_ages_unchanged_; 286 const bool is_shared_heap_; 287 #ifdef V8_SANDBOXED_EXTERNAL_POINTERS 288 ExternalPointerTable* const external_pointer_table_; 289 #endif // V8_SANDBOXED_EXTERNAL_POINTERS 290 }; 291 292 } // namespace internal 293 } // namespace v8 294 295 #endif // V8_HEAP_MARKING_VISITOR_H_ 296