tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */