Tracer.h (16799B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef js_Tracer_h 8 #define js_Tracer_h 9 10 #include "gc/Allocator.h" 11 #include "gc/Barrier.h" 12 #include "gc/TraceKind.h" 13 #include "js/HashTable.h" 14 #include "js/TracingAPI.h" 15 16 namespace JS { 17 using CompartmentSet = 18 js::HashSet<Compartment*, js::DefaultHasher<Compartment*>, 19 js::SystemAllocPolicy>; 20 } // namespace JS 21 22 namespace js { 23 24 class TaggedProto; 25 namespace wasm { 26 class AnyRef; 27 } // namespace wasm 28 29 // Internal Tracing API 30 // 31 // Tracing is an abstract visitation of each edge in a JS heap graph.[1] The 32 // most common (and performance sensitive) use of this infrastructure is for GC 33 // "marking" as part of the mark-and-sweep collector; however, this 34 // infrastructure is much more general than that and is used for many other 35 // purposes as well. 36 // 37 // One commonly misunderstood subtlety of the tracing architecture is the role 38 // of graph vertices versus graph edges. Graph vertices are the heap 39 // allocations -- GC things -- that are returned by Allocate. Graph edges are 40 // pointers -- including tagged pointers like Value and jsid -- that link the 41 // allocations into a complex heap. The tracing API deals *only* with edges. 42 // Any action taken on the target of a graph edge is independent of the tracing 43 // itself. 44 // 45 // Another common misunderstanding relates to the role of the JSTracer. The 46 // JSTracer instance determines what tracing does when visiting an edge; it 47 // does not itself participate in the tracing process, other than to be passed 48 // through as opaque data. It works like a closure in that respect. 49 // 50 // Tracing implementations internal to SpiderMonkey should use these interfaces 51 // instead of the public interfaces in js/TracingAPI.h. Unlike the public 52 // tracing methods, these work on internal types and avoid an external call. 53 // 54 // Note that the implementations for these methods are, surprisingly, in 55 // js/src/gc/Marking.cpp. This is so that the compiler can inline as much as 56 // possible in the common, marking pathways. Conceptually, however, they remain 57 // as part of the generic "tracing" architecture, rather than the more specific 58 // marking implementation of tracing. 59 // 60 // 1 - In SpiderMonkey, we call this concept tracing rather than visiting 61 // because "visiting" is already used by the compiler. Also, it's been 62 // called "tracing" forever and changing it would be extremely difficult at 63 // this point. 64 65 class GCMarker; 66 67 // Debugging functions to check tracing invariants. 68 #ifdef DEBUG 69 template <typename T> 70 void CheckTracedThing(JSTracer* trc, T* thing); 71 template <typename T> 72 void CheckTracedThing(JSTracer* trc, const T& thing); 73 #else 74 template <typename T> 75 inline void CheckTracedThing(JSTracer* trc, T* thing) {} 76 template <typename T> 77 inline void CheckTracedThing(JSTracer* trc, const T& thing) {} 78 #endif 79 80 namespace gc { 81 82 // Our barrier templates are parameterized on the pointer types so that we can 83 // share the definitions with Value and jsid. Thus, we need to strip the 84 // pointer before sending the type to BaseGCType and re-add it on the other 85 // side. As such: 86 template <typename T> 87 struct PtrBaseGCType { 88 using type = T; 89 }; 90 template <typename T> 91 struct PtrBaseGCType<T*> { 92 using type = typename BaseGCType<T>::type*; 93 }; 94 95 // Cast a possibly-derived T** pointer to a base class pointer. 96 template <typename T> 97 typename PtrBaseGCType<T>::type* ConvertToBase(T* thingp) { 98 return reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp); 99 } 100 101 // Internal methods to trace edges. 102 103 #define DEFINE_TRACE_FUNCTION(name, type, _1, _2) \ 104 MOZ_ALWAYS_INLINE bool TraceEdgeInternal(JSTracer* trc, type** thingp, \ 105 const char* name) { \ 106 CheckTracedThing(trc, *thingp); \ 107 trc->on##name##Edge(thingp, name); \ 108 return *thingp; \ 109 } 110 JS_FOR_EACH_TRACEKIND(DEFINE_TRACE_FUNCTION) 111 #undef DEFINE_TRACE_FUNCTION 112 113 bool TraceEdgeInternal(JSTracer* trc, Value* thingp, const char* name); 114 bool TraceEdgeInternal(JSTracer* trc, jsid* thingp, const char* name); 115 bool TraceEdgeInternal(JSTracer* trc, TaggedProto* thingp, const char* name); 116 bool TraceEdgeInternal(JSTracer* trc, wasm::AnyRef* thingp, const char* name); 117 118 template <typename T> 119 void TraceRangeInternal(JSTracer* trc, size_t len, T* vec, const char* name); 120 121 #ifdef DEBUG 122 void AssertRootMarkingPhase(JSTracer* trc); 123 template <typename T> 124 void AssertShouldMarkInZone(GCMarker* marker, T* thing); 125 #else 126 inline void AssertRootMarkingPhase(JSTracer* trc) {} 127 template <typename T> 128 void AssertShouldMarkInZone(GCMarker* marker, T* thing) {} 129 #endif 130 131 } // namespace gc 132 133 // Trace through a strong edge in the live object graph on behalf of 134 // tracing. The effect of tracing the edge depends on the JSTracer being 135 // used. For pointer types, |*thingp| must not be null. 136 // 137 // Note that weak edges are handled separately. GC things with weak edges must 138 // not trace those edges during marking tracing (which would keep the referent 139 // alive) but instead arrange for the edge to be swept by calling 140 // js::gc::IsAboutToBeFinalized or TraceWeakEdge during sweeping. 141 // 142 // GC things that are weakly held in containers can use WeakMap or a container 143 // wrapped in the WeakCache<> template to perform the appropriate sweeping. 144 145 template <typename T> 146 inline void TraceEdge(JSTracer* trc, const WriteBarriered<T>* thingp, 147 const char* name) { 148 gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp->unbarrieredAddress()), 149 name); 150 } 151 152 template <typename T> 153 inline void TraceEdge(JSTracer* trc, WeakHeapPtr<T>* thingp, const char* name) { 154 gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp->unbarrieredAddress()), 155 name); 156 } 157 158 template <class BC, class T> 159 inline void TraceCellHeaderEdge(JSTracer* trc, 160 gc::CellWithTenuredGCPointer<BC, T>* thingp, 161 const char* name) { 162 T* thing = thingp->headerPtr(); 163 gc::TraceEdgeInternal(trc, gc::ConvertToBase(&thing), name); 164 if (thing != thingp->headerPtr()) { 165 thingp->unbarrieredSetHeaderPtr(thing); 166 } 167 } 168 169 template <class T> 170 inline void TraceCellHeaderEdge(JSTracer* trc, gc::CellWithGCPointer<T>* thingp, 171 const char* name) { 172 T* thing = thingp->headerPtr(); 173 gc::TraceEdgeInternal(trc, gc::ConvertToBase(&thing), name); 174 if (thing != thingp->headerPtr()) { 175 thingp->unbarrieredSetHeaderPtr(thing); 176 } 177 } 178 179 // Trace through a possibly-null edge in the live object graph on behalf of 180 // tracing. 181 182 template <typename T> 183 inline void TraceNullableEdge(JSTracer* trc, const WriteBarriered<T>* thingp, 184 const char* name) { 185 if (InternalBarrierMethods<T>::isMarkable(thingp->get())) { 186 TraceEdge(trc, thingp, name); 187 } 188 } 189 190 template <typename T> 191 inline void TraceNullableEdge(JSTracer* trc, WeakHeapPtr<T>* thingp, 192 const char* name) { 193 if (InternalBarrierMethods<T>::isMarkable(thingp->unbarrieredGet())) { 194 TraceEdge(trc, thingp, name); 195 } 196 } 197 198 template <class BC, class T> 199 inline void TraceNullableCellHeaderEdge( 200 JSTracer* trc, gc::CellWithTenuredGCPointer<BC, T>* thingp, 201 const char* name) { 202 T* thing = thingp->headerPtr(); 203 if (thing) { 204 gc::TraceEdgeInternal(trc, gc::ConvertToBase(&thing), name); 205 if (thing != thingp->headerPtr()) { 206 thingp->unbarrieredSetHeaderPtr(thing); 207 } 208 } 209 } 210 211 // Trace through a "root" edge. These edges are the initial edges in the object 212 // graph traversal. Root edges are asserted to only be traversed in the initial 213 // phase of a GC. 214 215 template <typename T> 216 inline void TraceRoot(JSTracer* trc, T* thingp, const char* name) { 217 gc::AssertRootMarkingPhase(trc); 218 gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name); 219 } 220 221 template <typename T> 222 inline void TraceRoot(JSTracer* trc, const HeapPtr<T>* thingp, 223 const char* name) { 224 TraceRoot(trc, thingp->unbarrieredAddress(), name); 225 } 226 227 // Buffers are typically owned by other GC things. Permit creation of 'tenured 228 // owned' buffers as part of creating the owning GC thing. 229 template <typename T> 230 void TraceBufferRoot(JSTracer* trc, JS::Zone* zone, T** bufferp, 231 const char* name) { 232 void** ptrp = reinterpret_cast<void**>(bufferp); 233 gc::TraceBufferEdgeInternal(trc, zone, ptrp, name); 234 } 235 236 template <typename T> 237 void BufferHolder<T>::trace(JSTracer* trc) { 238 if (buffer) { 239 TraceBufferRoot(trc, zone, &buffer, "BufferHolder buffer"); 240 JS::GCPolicy<T>::trace(trc, buffer, "BufferHolder data"); 241 } 242 } 243 244 // Idential to TraceRoot, except that this variant will not crash if |*thingp| 245 // is null. 246 247 template <typename T> 248 inline void TraceNullableRoot(JSTracer* trc, T* thingp, const char* name) { 249 gc::AssertRootMarkingPhase(trc); 250 if (InternalBarrierMethods<T>::isMarkable(*thingp)) { 251 gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name); 252 } 253 } 254 255 template <typename T> 256 inline void TraceNullableRoot(JSTracer* trc, WeakHeapPtr<T>* thingp, 257 const char* name) { 258 TraceNullableRoot(trc, thingp->unbarrieredAddress(), name); 259 } 260 261 // Like TraceEdge, but for edges that do not use one of the automatic barrier 262 // classes and, thus, must be treated specially for moving GC. This method is 263 // separate from TraceEdge to make accidental use of such edges more obvious. 264 265 template <typename T> 266 inline void TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, 267 const char* name) { 268 gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name); 269 } 270 271 template <typename T> 272 inline void TraceManuallyBarrieredNullableEdge(JSTracer* trc, T* thingp, 273 const char* name) { 274 if (InternalBarrierMethods<T>::isMarkable(*thingp)) { 275 gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name); 276 } 277 } 278 279 // The result of tracing a weak edge, which can be either: 280 // 281 // - the target is dead (and the edge has been cleared), or 282 // - the target is alive (and the edge may have been updated) 283 // 284 // This includes the initial and final values of the edge to allow cleanup if 285 // the target is dead or access to the referent if it is alive. 286 template <typename T> 287 struct TraceWeakResult { 288 const bool live_; 289 const T initial_; 290 const T final_; 291 292 bool isLive() const { return live_; } 293 bool isDead() const { return !live_; } 294 bool wasMoved() const { return isLive() && final_ != initial_; } 295 296 MOZ_IMPLICIT operator bool() const { return isLive(); } 297 298 T initialTarget() const { return initial_; } 299 300 T finalTarget() const { 301 MOZ_ASSERT(isLive()); 302 return final_; 303 } 304 }; 305 306 // Trace through a weak edge. If *thingp is not marked at the end of marking, it 307 // is replaced by nullptr. Returns a TraceWeakResult to describe what happened 308 // and allow cleanup. 309 template <typename T> 310 inline TraceWeakResult<T> TraceWeakEdge(JSTracer* trc, BarrieredBase<T>* thingp, 311 const char* name) { 312 T* addr = thingp->unbarrieredAddress(); 313 T initial = *addr; 314 bool live = !InternalBarrierMethods<T>::isMarkable(initial) || 315 gc::TraceEdgeInternal(trc, gc::ConvertToBase(addr), name); 316 return TraceWeakResult<T>{live, initial, *addr}; 317 } 318 template <typename T> 319 inline TraceWeakResult<T> TraceManuallyBarrieredWeakEdge(JSTracer* trc, 320 T* thingp, 321 const char* name) { 322 T initial = *thingp; 323 bool live = !InternalBarrierMethods<T>::isMarkable(initial) || 324 gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name); 325 return TraceWeakResult<T>{live, initial, *thingp}; 326 } 327 328 // Trace all edges contained in the given array. 329 330 template <typename T> 331 void TraceRange(JSTracer* trc, size_t len, BarrieredBase<T>* vec, 332 const char* name) { 333 gc::TraceRangeInternal(trc, len, 334 gc::ConvertToBase(vec[0].unbarrieredAddress()), name); 335 } 336 337 // Trace all root edges in the given array. 338 339 template <typename T> 340 void TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name) { 341 gc::AssertRootMarkingPhase(trc); 342 gc::TraceRangeInternal(trc, len, gc::ConvertToBase(vec), name); 343 } 344 345 // Note that this doesn't trace the contents of the alloc. 346 // TODO: Unify this with other TraceEdge methods. 347 template <typename T> 348 void TraceBufferEdge(JSTracer* trc, gc::Cell* owner, T** bufferp, 349 const char* name) { 350 void** ptrp = reinterpret_cast<void**>(bufferp); 351 gc::TraceBufferEdgeInternal(trc, owner, ptrp, name); 352 } 353 354 // As below but with manual barriers. 355 template <typename T> 356 void TraceManuallyBarrieredCrossCompartmentEdge(JSTracer* trc, JSObject* src, 357 T* dst, const char* name); 358 359 // Trace an edge that crosses compartment boundaries. If the compartment of the 360 // destination thing is not being GC'd, then the edge will not be traced. 361 template <typename T> 362 void TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, 363 const WriteBarriered<T>* dst, const char* name) { 364 TraceManuallyBarrieredCrossCompartmentEdge( 365 trc, src, gc::ConvertToBase(dst->unbarrieredAddress()), name); 366 } 367 368 // Trace an edge that's guaranteed to be same-zone but may cross a compartment 369 // boundary. This should NOT be used for object => object edges, as those have 370 // to be in the cross-compartment wrapper map. 371 // 372 // WARNING: because this turns off certain compartment checks, you most likely 373 // don't want to use this! If you still think you need this function, talk to a 374 // GC peer first. 375 template <typename T> 376 void TraceSameZoneCrossCompartmentEdge(JSTracer* trc, 377 const BarrieredBase<T>* dst, 378 const char* name); 379 380 // Trace a weak map key. For debugger weak maps these may be cross compartment, 381 // but the compartment must always be within the current sweep group. 382 template <typename T> 383 void TraceWeakMapKeyEdgeInternal(JSTracer* trc, Zone* weakMapZone, T** thingp, 384 const char* name); 385 386 template <typename T> 387 void TraceWeakMapKeyEdgeInternal(JSTracer* trc, Zone* weakMapZone, T* thingp, 388 const char* name); 389 390 template <typename T> 391 inline void TraceWeakMapKeyEdge(JSTracer* trc, Zone* weakMapZone, 392 const WriteBarriered<T>* thingp, 393 const char* name) { 394 TraceWeakMapKeyEdgeInternal( 395 trc, weakMapZone, gc::ConvertToBase(thingp->unbarrieredAddress()), name); 396 } 397 398 // Trace a root edge that uses the base GC thing type, instead of a more 399 // specific type. 400 void TraceGenericPointerRoot(JSTracer* trc, gc::Cell** thingp, 401 const char* name); 402 403 // Trace a non-root edge that uses the base GC thing type, instead of a more 404 // specific type. 405 void TraceManuallyBarrieredGenericPointerEdge(JSTracer* trc, gc::Cell** thingp, 406 const char* name); 407 408 void TraceGCCellPtrRoot(JSTracer* trc, JS::GCCellPtr* thingp, const char* name); 409 410 void TraceManuallyBarrieredGCCellPtr(JSTracer* trc, JS::GCCellPtr* thingp, 411 const char* name); 412 413 namespace gc { 414 415 // Trace through a shape or group iteratively during cycle collection to avoid 416 // deep or infinite recursion. 417 void TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape); 418 419 /** 420 * Trace every value within |compartments| that is wrapped by a 421 * cross-compartment wrapper from a compartment that is not an element of 422 * |compartments|. 423 */ 424 void TraceIncomingCCWs(JSTracer* trc, const JS::CompartmentSet& compartments); 425 426 /* Get information about a GC thing. Used when dumping the heap. */ 427 void GetTraceThingInfo(char* buf, size_t bufsize, void* thing, 428 JS::TraceKind kind, bool includeDetails); 429 430 // Overloaded function to call the correct GenericTracer method based on the 431 // argument type. 432 #define DEFINE_DISPATCH_FUNCTION(name, type, _1, _2) \ 433 inline void DispatchToOnEdge(JSTracer* trc, type** thingp, \ 434 const char* name) { \ 435 trc->on##name##Edge(thingp, name); \ 436 } 437 JS_FOR_EACH_TRACEKIND(DEFINE_DISPATCH_FUNCTION) 438 #undef DEFINE_DISPATCH_FUNCTION 439 440 } // namespace gc 441 } // namespace js 442 443 #endif /* js_Tracer_h */