tor-browser

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

RootMarking.cpp (15373B)


      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 #ifdef MOZ_VALGRIND
      8 #  include <valgrind/memcheck.h>
      9 #endif
     10 
     11 #include "jstypes.h"
     12 
     13 #include "debugger/DebugAPI.h"
     14 #include "gc/ClearEdgesTracer.h"
     15 #include "gc/GCInternals.h"
     16 #include "gc/PublicIterators.h"
     17 #include "jit/JitFrames.h"
     18 #include "jit/JitRuntime.h"
     19 #include "js/ValueArray.h"
     20 #include "vm/BigIntType.h"
     21 #include "vm/Compartment.h"
     22 #include "vm/HelperThreadState.h"
     23 #include "vm/JSContext.h"
     24 
     25 using namespace js;
     26 using namespace js::gc;
     27 
     28 using mozilla::LinkedList;
     29 
     30 using JS::AutoGCRooter;
     31 using JS::SliceBudget;
     32 
     33 using RootRange = RootedValueMap::Range;
     34 using RootEntry = RootedValueMap::Entry;
     35 using RootEnum = RootedValueMap::Enum;
     36 
     37 template <typename Base, typename T>
     38 inline void TypedRootedGCThingBase<Base, T>::trace(JSTracer* trc,
     39                                                   const char* name) {
     40  auto* self = this->template derived<T>();
     41  TraceNullableRoot(trc, self->address(), name);
     42 }
     43 
     44 template <typename T>
     45 static inline void TraceExactStackRootList(JSTracer* trc,
     46                                           StackRootedBase* listHead,
     47                                           const char* name) {
     48  // Check size of Rooted<T> does not increase.
     49  static_assert(sizeof(Rooted<T>) == sizeof(T) + 2 * sizeof(uintptr_t));
     50 
     51  for (StackRootedBase* root = listHead; root; root = root->previous()) {
     52    static_cast<Rooted<T>*>(root)->trace(trc, name);
     53  }
     54 }
     55 
     56 static inline void TraceExactStackRootTraceableList(JSTracer* trc,
     57                                                    StackRootedBase* listHead,
     58                                                    const char* name) {
     59  for (StackRootedBase* root = listHead; root; root = root->previous()) {
     60    static_cast<StackRootedTraceableBase*>(root)->trace(trc, name);
     61  }
     62 }
     63 
     64 static inline void TraceStackRoots(JSTracer* trc,
     65                                   JS::RootedListHeads& stackRoots) {
     66 #define TRACE_ROOTS(name, type, _, _1)                                \
     67  TraceExactStackRootList<type*>(trc, stackRoots[JS::RootKind::name], \
     68                                 "exact-" #name);
     69  JS_FOR_EACH_TRACEKIND(TRACE_ROOTS)
     70 #undef TRACE_ROOTS
     71  TraceExactStackRootList<jsid>(trc, stackRoots[JS::RootKind::Id], "exact-id");
     72  TraceExactStackRootList<Value>(trc, stackRoots[JS::RootKind::Value],
     73                                 "exact-value");
     74 
     75  // RootedTraceable uses virtual dispatch.
     76  JS::AutoSuppressGCAnalysis nogc;
     77 
     78  TraceExactStackRootTraceableList(trc, stackRoots[JS::RootKind::Traceable],
     79                                   "Traceable");
     80 }
     81 
     82 void JS::RootingContext::traceStackRoots(JSTracer* trc) {
     83  TraceStackRoots(trc, stackRoots_);
     84 }
     85 
     86 static void TraceExactStackRoots(JSContext* cx, JSTracer* trc) {
     87  cx->traceStackRoots(trc);
     88 }
     89 
     90 template <typename T>
     91 static inline void TracePersistentRootedList(
     92    JSTracer* trc, LinkedList<PersistentRootedBase>& list, const char* name) {
     93  for (PersistentRootedBase* root : list) {
     94    static_cast<PersistentRooted<T>*>(root)->trace(trc, name);
     95  }
     96 }
     97 
     98 static inline void TracePersistentRootedTraceableList(
     99    JSTracer* trc, LinkedList<PersistentRootedBase>& list, const char* name) {
    100  for (PersistentRootedBase* root : list) {
    101    static_cast<PersistentRootedTraceableBase*>(root)->trace(trc, name);
    102  }
    103 }
    104 
    105 void JSRuntime::tracePersistentRoots(JSTracer* trc) {
    106 #define TRACE_ROOTS(name, type, _, _1)                                       \
    107  TracePersistentRootedList<type*>(trc, heapRoots.ref()[JS::RootKind::name], \
    108                                   "persistent-" #name);
    109  JS_FOR_EACH_TRACEKIND(TRACE_ROOTS)
    110 #undef TRACE_ROOTS
    111  TracePersistentRootedList<jsid>(trc, heapRoots.ref()[JS::RootKind::Id],
    112                                  "persistent-id");
    113  TracePersistentRootedList<Value>(trc, heapRoots.ref()[JS::RootKind::Value],
    114                                   "persistent-value");
    115 
    116  // RootedTraceable uses virtual dispatch.
    117  JS::AutoSuppressGCAnalysis nogc;
    118 
    119  TracePersistentRootedTraceableList(
    120      trc, heapRoots.ref()[JS::RootKind::Traceable], "persistent-traceable");
    121 }
    122 
    123 static void TracePersistentRooted(JSRuntime* rt, JSTracer* trc) {
    124  rt->tracePersistentRoots(trc);
    125 }
    126 
    127 template <typename T>
    128 static void FinishPersistentRootedChain(
    129    LinkedList<PersistentRootedBase>& list) {
    130  while (!list.isEmpty()) {
    131    static_cast<PersistentRooted<T>*>(list.getFirst())->reset();
    132  }
    133 }
    134 
    135 void JSRuntime::finishPersistentRoots() {
    136 #define FINISH_ROOT_LIST(name, type, _, _1) \
    137  FinishPersistentRootedChain<type*>(heapRoots.ref()[JS::RootKind::name]);
    138  JS_FOR_EACH_TRACEKIND(FINISH_ROOT_LIST)
    139 #undef FINISH_ROOT_LIST
    140  FinishPersistentRootedChain<jsid>(heapRoots.ref()[JS::RootKind::Id]);
    141  FinishPersistentRootedChain<Value>(heapRoots.ref()[JS::RootKind::Value]);
    142 
    143  // Note that we do not finalize the Traceable list as we do not know how to
    144  // safely clear members. We instead assert that none escape the RootLists.
    145  // See the comment on RootLists::~RootLists for details.
    146 }
    147 
    148 JS_PUBLIC_API void js::TraceValueArray(JSTracer* trc, size_t length,
    149                                       Value* elements) {
    150  TraceRootRange(trc, length, elements, "JS::RootedValueArray");
    151 }
    152 
    153 void AutoGCRooter::trace(JSTracer* trc) {
    154  switch (kind_) {
    155    case Kind::Wrapper:
    156      static_cast<AutoWrapperRooter*>(this)->trace(trc);
    157      break;
    158 
    159    case Kind::WrapperVector:
    160      static_cast<AutoWrapperVector*>(this)->trace(trc);
    161      break;
    162 
    163    case Kind::Custom:
    164      static_cast<JS::CustomAutoRooter*>(this)->trace(trc);
    165      break;
    166 
    167    default:
    168      MOZ_CRASH("Bad AutoGCRooter::Kind");
    169      break;
    170  }
    171 }
    172 
    173 void AutoWrapperRooter::trace(JSTracer* trc) {
    174  /*
    175   * We need to use TraceManuallyBarrieredEdge here because we trace wrapper
    176   * roots in every slice. This is because of some rule-breaking in
    177   * RemapAllWrappersForObject; see comment there.
    178   */
    179  TraceManuallyBarrieredEdge(trc, &value.get(), "js::AutoWrapperRooter.value");
    180 }
    181 
    182 void AutoWrapperVector::trace(JSTracer* trc) {
    183  /*
    184   * We need to use TraceManuallyBarrieredEdge here because we trace wrapper
    185   * roots in every slice. This is because of some rule-breaking in
    186   * RemapAllWrappersForObject; see comment there.
    187   */
    188  for (WrapperValue& value : *this) {
    189    TraceManuallyBarrieredEdge(trc, &value.get(),
    190                               "js::AutoWrapperVector.vector");
    191  }
    192 }
    193 
    194 void JS::RootingContext::traceAllGCRooters(JSTracer* trc) {
    195  for (AutoGCRooter* list : autoGCRooters_) {
    196    traceGCRooterList(trc, list);
    197  }
    198 }
    199 
    200 void JS::RootingContext::traceWrapperGCRooters(JSTracer* trc) {
    201  traceGCRooterList(trc, autoGCRooters_[AutoGCRooter::Kind::Wrapper]);
    202  traceGCRooterList(trc, autoGCRooters_[AutoGCRooter::Kind::WrapperVector]);
    203 }
    204 
    205 /* static */
    206 inline void JS::RootingContext::traceGCRooterList(JSTracer* trc,
    207                                                  AutoGCRooter* head) {
    208  for (AutoGCRooter* rooter = head; rooter; rooter = rooter->down) {
    209    rooter->trace(trc);
    210  }
    211 }
    212 
    213 void PropertyDescriptor::trace(JSTracer* trc) {
    214  TraceRoot(trc, &value_, "Descriptor::value");
    215  if (getter_) {
    216    TraceRoot(trc, &getter_, "Descriptor::getter");
    217  }
    218  if (setter_) {
    219    TraceRoot(trc, &setter_, "Descriptor::setter");
    220  }
    221 }
    222 
    223 void js::gc::GCRuntime::traceRuntimeForMajorGC(JSTracer* trc,
    224                                               AutoGCSession& session) {
    225  MOZ_ASSERT(!TlsContext.get()->suppressGC);
    226 
    227  gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
    228 
    229  // We only need to trace atoms when we're marking; atoms are never moved by
    230  // compacting GC.
    231  if (atomsZone()->isGCMarking()) {
    232    traceRuntimeAtoms(trc);
    233  }
    234 
    235  {
    236    // Trace incoming cross compartment edges from uncollected compartments,
    237    // skipping gray edges which are traced later.
    238    gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_CCWS);
    239    Compartment::traceIncomingCrossCompartmentEdgesForZoneGC(
    240        trc, Compartment::NonGrayEdges);
    241  }
    242 
    243  traceRuntimeCommon(trc, MarkRuntime);
    244 }
    245 
    246 void js::gc::GCRuntime::traceRuntimeForMinorGC(JSTracer* trc,
    247                                               AutoGCSession& session) {
    248  MOZ_ASSERT(!TlsContext.get()->suppressGC);
    249 
    250  // Note that we *must* trace the runtime during the SHUTDOWN_GC's minor GC
    251  // despite having called FinishRoots already. This is because FinishRoots
    252  // does not clear the crossCompartmentWrapper map. It cannot do this
    253  // because Proxy's trace for CrossCompartmentWrappers asserts presence in
    254  // the map. And we can reach its trace function despite having finished the
    255  // roots via the edges stored by the pre-barrier verifier when we finish
    256  // the verifier for the last time.
    257  gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
    258 
    259  traceRuntimeCommon(trc, TraceRuntime);
    260 }
    261 
    262 void js::TraceRuntime(JSTracer* trc) {
    263  MOZ_ASSERT(!trc->isMarkingTracer());
    264 
    265  JSRuntime* rt = trc->runtime();
    266  AutoEmptyNurseryAndPrepareForTracing prep(rt->mainContextFromOwnThread());
    267  gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
    268  rt->gc.traceRuntime(trc, prep);
    269 }
    270 
    271 void js::TraceRuntimeWithoutEviction(JSTracer* trc) {
    272  MOZ_ASSERT(!trc->isMarkingTracer());
    273 
    274  JSRuntime* rt = trc->runtime();
    275  AutoTraceSession session(rt);
    276  gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
    277  rt->gc.traceRuntime(trc, session);
    278 }
    279 
    280 void js::gc::GCRuntime::traceRuntime(JSTracer* trc, AutoHeapSession& session) {
    281  MOZ_ASSERT(!rt->isBeingDestroyed());
    282 
    283  gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
    284 
    285  traceRuntimeAtoms(trc);
    286  traceRuntimeCommon(trc, TraceRuntime);
    287 }
    288 
    289 void js::gc::GCRuntime::traceRuntimeAtoms(JSTracer* trc) {
    290  gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_RUNTIME_DATA);
    291  TraceAtoms(trc);
    292  jit::JitRuntime::TraceAtomZoneRoots(trc);
    293 }
    294 
    295 void js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc,
    296                                           TraceOrMarkRuntime traceOrMark) {
    297  {
    298    gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_STACK);
    299 
    300    JSContext* cx = rt->mainContextFromOwnThread();
    301 
    302    // Trace active interpreter and JIT stack roots.
    303    TraceInterpreterActivations(cx, trc);
    304    jit::TraceJitActivations(cx, trc);
    305 
    306    // Trace legacy C stack roots.
    307    cx->traceAllGCRooters(trc);
    308 
    309    // Trace C stack roots.
    310    TraceExactStackRoots(cx, trc);
    311 
    312    for (RootRange r = rootsHash.ref().all(); !r.empty(); r.popFront()) {
    313      const RootEntry& entry = r.front();
    314      TraceRoot(trc, entry.key(), entry.value());
    315    }
    316  }
    317 
    318  // Trace runtime global roots.
    319  TracePersistentRooted(rt, trc);
    320 
    321 #ifdef JS_HAS_INTL_API
    322  // Trace the shared Intl data.
    323  rt->traceSharedIntlData(trc);
    324 #endif
    325 
    326  // Trace the JSContext.
    327  rt->mainContextFromOwnThread()->trace(trc);
    328 
    329  // Trace all realm roots, but not the realm itself; it is traced via the
    330  // parent pointer if traceRoots actually traces anything.
    331  for (RealmsIter r(rt); !r.done(); r.next()) {
    332    r->traceRoots(trc, traceOrMark);
    333  }
    334 
    335  if (!JS::RuntimeHeapIsMinorCollecting()) {
    336    // Trace the self-hosting stencil. The contents of this are always tenured.
    337    rt->traceSelfHostingStencil(trc);
    338 
    339    for (ZonesIter zone(this, ZoneSelector::SkipAtoms); !zone.done();
    340         zone.next()) {
    341      zone->traceRootsInMajorGC(trc);
    342    }
    343 
    344    // Trace interpreter entry code generated with --emit-interpreter-entry
    345    if (rt->hasJitRuntime() && rt->jitRuntime()->hasInterpreterEntryMap()) {
    346      rt->jitRuntime()->getInterpreterEntryMap()->traceTrampolineCode(trc);
    347    }
    348  }
    349 
    350  // Trace helper thread roots.
    351  HelperThreadState().trace(trc);
    352 
    353  // Trace Debugger.Frames that have live hooks, since dropping them would be
    354  // observable. In effect, they are rooted by the stack frames.
    355  DebugAPI::traceFramesWithLiveHooks(trc);
    356 
    357  // Trace the embedding's black and gray roots.
    358  if (!JS::RuntimeHeapIsMinorCollecting()) {
    359    gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_EMBEDDING);
    360 
    361    /*
    362     * The embedding can register additional roots here.
    363     *
    364     * We don't need to trace these in a minor GC because all pointers into
    365     * the nursery should be in the store buffer, and we want to avoid the
    366     * time taken to trace all these roots.
    367     */
    368    traceEmbeddingBlackRoots(trc);
    369 
    370    /* During GC, we don't trace gray roots at this stage. */
    371    if (traceOrMark == TraceRuntime) {
    372      traceEmbeddingGrayRoots(trc);
    373    }
    374  }
    375 
    376  traceKeptObjects(trc);
    377 }
    378 
    379 void GCRuntime::traceEmbeddingBlackRoots(JSTracer* trc) {
    380  // The analysis doesn't like the function pointer below.
    381  JS::AutoSuppressGCAnalysis nogc;
    382 
    383  for (const auto& callback : blackRootTracers.ref()) {
    384    (*callback.op)(trc, callback.data);
    385  }
    386 }
    387 
    388 void GCRuntime::traceEmbeddingGrayRoots(JSTracer* trc) {
    389  SliceBudget budget = SliceBudget::unlimited();
    390  MOZ_ALWAYS_TRUE(traceEmbeddingGrayRoots(trc, budget) == Finished);
    391 }
    392 
    393 IncrementalProgress GCRuntime::traceEmbeddingGrayRoots(JSTracer* trc,
    394                                                       SliceBudget& budget) {
    395  // The analysis doesn't like the function pointer below.
    396  JS::AutoSuppressGCAnalysis nogc;
    397 
    398  const auto& callback = grayRootTracer.ref();
    399  if (!callback.op) {
    400    return Finished;
    401  }
    402 
    403  return callback.op(trc, budget, callback.data) ? Finished : NotFinished;
    404 }
    405 
    406 #ifdef DEBUG
    407 class AssertNoRootsTracer final : public JS::CallbackTracer {
    408  void onChild(JS::GCCellPtr thing, const char* name) override {
    409    MOZ_CRASH("There should not be any roots during runtime shutdown");
    410  }
    411 
    412 public:
    413  // This skips tracking WeakMap entries because they are not roots.
    414  explicit AssertNoRootsTracer(JSRuntime* rt)
    415      : JS::CallbackTracer(rt, JS::TracerKind::Callback,
    416                           JS::WeakMapTraceAction::Skip) {}
    417 };
    418 #endif  // DEBUG
    419 
    420 void js::gc::GCRuntime::finishRoots() {
    421  AutoNoteSingleThreadedRegion anstr;
    422 
    423  rt->finishAtoms();
    424  restoreSharedAtomsZone();
    425 
    426  rootsHash.ref().clear();
    427 
    428  rt->finishPersistentRoots();
    429 
    430  rt->finishSelfHosting();
    431 
    432  for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
    433    zone->finishRoots();
    434  }
    435 
    436 #ifdef JS_GC_ZEAL
    437  clearSelectedForMarking();
    438 #endif
    439 
    440  // Clear out the interpreter entry map before the final gc.
    441  ClearInterpreterEntryMap(rt);
    442 
    443  // Clear any remaining roots from the embedding (as otherwise they will be
    444  // left dangling after we shut down) and remove the callbacks.
    445  ClearEdgesTracer trc(rt);
    446  traceEmbeddingBlackRoots(&trc);
    447  traceEmbeddingGrayRoots(&trc);
    448  clearBlackAndGrayRootTracers();
    449 }
    450 
    451 void js::gc::GCRuntime::checkNoRuntimeRoots(AutoGCSession& session) {
    452 #ifdef DEBUG
    453  AssertNoRootsTracer trc(rt);
    454  traceRuntimeForMajorGC(&trc, session);
    455 #endif  // DEBUG
    456 }
    457 
    458 JS_PUBLIC_API void JS::AddPersistentRoot(JS::RootingContext* cx, RootKind kind,
    459                                         PersistentRootedBase* root) {
    460  JSRuntime* rt = static_cast<JSContext*>(cx)->runtime();
    461  rt->heapRoots.ref()[kind].insertBack(root);
    462 }
    463 
    464 JS_PUBLIC_API void JS::AddPersistentRoot(JSRuntime* rt, RootKind kind,
    465                                         PersistentRootedBase* root) {
    466  rt->heapRoots.ref()[kind].insertBack(root);
    467 }