tor-browser

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

GCMarker.h (21285B)


      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 gc_GCMarker_h
      8 #define gc_GCMarker_h
      9 
     10 #include "mozilla/Variant.h"
     11 #include "mozilla/XorShift128PlusRNG.h"
     12 
     13 #include "gc/Barrier.h"
     14 #include "js/HashTable.h"
     15 #include "js/TracingAPI.h"
     16 #include "js/TypeDecls.h"
     17 #include "threading/ProtectedData.h"
     18 
     19 class JSRope;
     20 
     21 namespace JS {
     22 class SliceBudget;
     23 }
     24 
     25 namespace js {
     26 
     27 class GCMarker;
     28 class WeakMapBase;
     29 
     30 #ifdef DEBUG
     31 // Force stack resizing to ensure OOM test coverage in debug builds.
     32 static const size_t MARK_STACK_BASE_CAPACITY = 4;
     33 #else
     34 static const size_t MARK_STACK_BASE_CAPACITY = 4096;
     35 #endif
     36 
     37 enum class SlotsOrElementsKind {
     38  Unused = 0,  // Must match SlotsOrElementsRangeTag
     39  Elements,
     40  FixedSlots,
     41  DynamicSlots
     42 };
     43 
     44 namespace gc {
     45 
     46 enum IncrementalProgress { NotFinished = 0, Finished };
     47 
     48 class AutoSetMarkColor;
     49 class AutoUpdateMarkStackRanges;
     50 struct Cell;
     51 class MarkStackIter;
     52 class ParallelMarkTask;
     53 class UnmarkGrayTracer;
     54 
     55 // Ephemerons are edges from a source to a target that are only materialized
     56 // into a table when the owner is marked. (The owner is something like a
     57 // WeakMap, which contains a set of ephemerons each going from a WeakMap key to
     58 // its value.) When marking a ephemeron, only the color of the owner is needed:
     59 // the target is marked with the minimum (least-marked) color of the owner and
     60 // source. So an EphemeronEdge need store only the owner color and the target
     61 // pointer, which can fit into a tagged pointer since targets are aligned Cells.
     62 //
     63 // Note: if the owner's color changes, new EphemeronEdges will be created for
     64 // it.
     65 class EphemeronEdge {
     66  static constexpr uintptr_t ColorMask = 0x3;
     67  static_assert(uintptr_t(MarkColor::Gray) <= ColorMask);
     68  static_assert(uintptr_t(MarkColor::Black) <= ColorMask);
     69  static_assert(ColorMask < CellAlignBytes);
     70 
     71  uintptr_t taggedTarget;
     72 
     73 public:
     74  EphemeronEdge(MarkColor color, TenuredCell* cell)
     75      : taggedTarget(uintptr_t(cell) | uintptr_t(color)) {
     76    MOZ_ASSERT((uintptr_t(cell) & ColorMask) == 0);
     77  }
     78 
     79  MarkColor color() const { return MarkColor(taggedTarget & ColorMask); }
     80  TenuredCell* target() const {
     81    return reinterpret_cast<TenuredCell*>(taggedTarget & ~ColorMask);
     82  }
     83 };
     84 
     85 using EphemeronEdgeVector = Vector<EphemeronEdge, 2, js::SystemAllocPolicy>;
     86 
     87 using EphemeronEdgeTable =
     88    HashMap<TenuredCell*, EphemeronEdgeVector, PointerHasher<TenuredCell*>,
     89            js::SystemAllocPolicy>;
     90 
     91 /*
     92 * The mark stack. Pointers in this stack are "gray" in the GC sense, but
     93 * their references may be marked either black or gray (in the CC sense).
     94 *
     95 * When the mark stack is full, the GC does not call js::TraceChildren to mark
     96 * the reachable "children" of the thing. Rather the thing is put aside and
     97 * js::TraceChildren is called later when the mark stack is empty.
     98 *
     99 * To implement such delayed marking of the children with minimal overhead for
    100 * the normal case of sufficient stack, we link arenas into a list using
    101 * Arena::setNextDelayedMarkingArena(). The head of the list is stored in
    102 * GCMarker::delayedMarkingList. GCMarker::delayMarkingChildren() adds arenas
    103 * to the list as necessary while markAllDelayedChildren() pops the arenas from
    104 * the stack until it is empty.
    105 */
    106 class MarkStack {
    107 public:
    108  /*
    109   * We use a common mark stack to mark GC things of different types and use
    110   * the explicit tags to distinguish them when it cannot be deduced from
    111   * the context of push or pop operation.
    112   */
    113  enum Tag {
    114    SlotsOrElementsRangeTag = 0,  // Must match SlotsOrElementsKind::Unused.
    115    ObjectTag,
    116    SymbolTag,
    117    JitCodeTag,
    118    ScriptTag,
    119    TempRopeTag,
    120 
    121    LastTag = TempRopeTag
    122  };
    123 
    124  static const uintptr_t TagMask = 7;
    125  static_assert(TagMask >= uintptr_t(LastTag),
    126                "The tag mask must subsume the tags.");
    127  static_assert(TagMask <= gc::CellAlignMask,
    128                "The tag mask must be embeddable in a Cell*.");
    129 
    130  class TaggedPtr {
    131    uintptr_t bits;
    132 
    133    Cell* ptr() const;
    134 
    135    explicit TaggedPtr(uintptr_t bits);
    136 
    137   public:
    138    TaggedPtr(Tag tag, Cell* ptr);
    139    static TaggedPtr fromBits(uintptr_t bits);
    140 
    141    uintptr_t asBits() const;
    142    Tag tag() const;
    143    template <typename T>
    144    T* as() const;
    145 
    146    JSObject* asRangeObject() const;
    147    JSRope* asTempRope() const;
    148 
    149    void assertValid() const;
    150  };
    151 
    152  class SlotsOrElementsRange {
    153    uintptr_t startAndKind_;
    154    TaggedPtr ptr_;
    155 
    156    static constexpr size_t StartShift = 2;
    157    static constexpr size_t KindMask = (1 << StartShift) - 1;
    158 
    159    SlotsOrElementsRange(uintptr_t startAndKind, uintptr_t ptr);
    160 
    161   public:
    162    SlotsOrElementsRange(SlotsOrElementsKind kind, JSObject* obj, size_t start);
    163    static SlotsOrElementsRange fromBits(uintptr_t startAndKind, uintptr_t ptr);
    164 
    165    void assertValid() const;
    166 
    167    uintptr_t asBits0() const;
    168    uintptr_t asBits1() const;
    169 
    170    SlotsOrElementsKind kind() const;
    171    size_t start() const;
    172    TaggedPtr ptr() const;
    173 
    174    void setStart(size_t newStart);
    175    void setEmpty();
    176  };
    177 
    178  MarkStack();
    179  ~MarkStack();
    180 
    181  MarkStack(const MarkStack& other) = delete;
    182  MarkStack& operator=(const MarkStack& other) = delete;
    183 
    184  void swap(MarkStack& other);
    185 
    186  // The unit for capacity is mark stack words.
    187  size_t capacity() const { return capacity_; }
    188 #ifdef JS_GC_ZEAL
    189  void setMaxCapacity(size_t maxCapacity);
    190 #endif
    191 
    192  size_t position() const { return topIndex_; }
    193 
    194  [[nodiscard]] bool init();
    195  [[nodiscard]] bool resetStackCapacity();
    196 
    197  template <typename T>
    198  [[nodiscard]] bool push(T* ptr);
    199  void infalliblePush(const SlotsOrElementsRange& range);
    200  void infalliblePush(JSObject* obj, SlotsOrElementsKind kind, size_t start);
    201  [[nodiscard]] bool push(const TaggedPtr& ptr);
    202  void infalliblePush(const TaggedPtr& ptr);
    203 
    204  // GCMarker::eagerlyMarkChildren uses unused marking stack as temporary
    205  // storage to hold rope pointers.
    206  [[nodiscard]] bool pushTempRope(JSRope* rope);
    207 
    208  bool isEmpty() const { return position() == 0; }
    209  bool hasEntries() const { return !isEmpty(); }
    210 
    211  Tag peekTag() const;
    212  TaggedPtr popPtr();
    213  SlotsOrElementsRange popSlotsOrElementsRange();
    214 
    215  void clearAndResetCapacity();
    216  void clearAndFreeStack();
    217 
    218  void poisonUnused();
    219 
    220  [[nodiscard]] bool ensureSpace(size_t count);
    221 
    222  static size_t moveWork(GCMarker* marker, MarkStack& dst, MarkStack& src,
    223                         bool allowDistribute);
    224 
    225  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    226 
    227 private:
    228  uintptr_t at(size_t index) const {
    229    MOZ_ASSERT(topIndex_ <= capacity_);
    230    MOZ_ASSERT(index < topIndex_);
    231    return stack_[index];
    232  }
    233  uintptr_t* ptr(size_t index) {
    234    MOZ_ASSERT(topIndex_ <= capacity_);
    235    MOZ_ASSERT(index <= topIndex_);
    236    return stack_ + index;
    237  }
    238 
    239  // Return a pointer to the first unused word beyond the top of the stack.
    240  uintptr_t* end() { return ptr(topIndex_); }
    241 
    242  // Grow the stack, ensuring there is space to push |count| more words.
    243  [[nodiscard]] bool enlarge(size_t count);
    244 
    245  [[nodiscard]] bool resize(size_t newCapacity);
    246 
    247  TaggedPtr peekPtr() const;
    248 
    249  [[nodiscard]] bool pushTaggedPtr(Tag tag, Cell* ptr);
    250 
    251  bool indexIsEntryBase(size_t index) const;
    252 
    253  // Area of memory containing the stack.
    254  MainThreadOrGCTaskData<uintptr_t*> stack_;
    255 
    256  // Size of the stack in words.
    257  MainThreadOrGCTaskData<size_t> capacity_;
    258 
    259  // Index of the top of the stack.
    260  MainThreadOrGCTaskData<size_t> topIndex_;
    261 
    262 #ifdef JS_GC_ZEAL
    263  // The maximum stack capacity to grow to.
    264  MainThreadOrGCTaskData<size_t> maxCapacity_{SIZE_MAX};
    265 #endif
    266 
    267 #ifdef DEBUG
    268  MainThreadOrGCTaskData<bool> elementsRangesAreValid;
    269  friend class js::GCMarker;
    270 #endif
    271 
    272  friend class MarkStackIter;
    273 };
    274 
    275 static_assert(unsigned(SlotsOrElementsKind::Unused) ==
    276                  unsigned(MarkStack::SlotsOrElementsRangeTag),
    277              "To split the mark stack we depend on being able to tell the "
    278              "difference between SlotsOrElementsRange::startAndKind_ and a "
    279              "tagged SlotsOrElementsRange");
    280 
    281 class MOZ_STACK_CLASS MarkStackIter {
    282  MarkStack& stack_;
    283  size_t pos_;
    284 
    285 public:
    286  explicit MarkStackIter(MarkStack& stack);
    287 
    288  bool done() const;
    289  void next();
    290 
    291  MarkStack::Tag peekTag() const;
    292  MarkStack::TaggedPtr peekPtr() const;
    293  bool isSlotsOrElementsRange() const;
    294  MarkStack::SlotsOrElementsRange slotsOrElementsRange() const;
    295  void setSlotsOrElementsRange(const MarkStack::SlotsOrElementsRange& range);
    296 
    297 private:
    298  size_t position() const;
    299 };
    300 
    301 // Bitmask of options to parameterize MarkingTracerT.
    302 namespace MarkingOptions {
    303 enum : uint32_t {
    304  None = 0,
    305 
    306  // Set the compartment's hasMarkedCells flag for roots.
    307  MarkRootCompartments = 1,
    308 
    309  // The marking tracer is operating in parallel. Use appropriate atomic
    310  // accesses to update the mark bits correctly.
    311  ParallelMarking = 2,
    312 
    313  // Mark any implicit edges if we are in weak marking mode.
    314  MarkImplicitEdges = 4,
    315 };
    316 }  // namespace MarkingOptions
    317 
    318 // A default set of marking options that works during normal marking and weak
    319 // marking modes. Used for barriers and testing code.
    320 constexpr uint32_t NormalMarkingOptions = MarkingOptions::MarkImplicitEdges;
    321 
    322 template <uint32_t markingOptions>
    323 class MarkingTracerT
    324    : public GenericTracerImpl<MarkingTracerT<markingOptions>> {
    325 public:
    326  MarkingTracerT(JSRuntime* runtime, GCMarker* marker);
    327  virtual ~MarkingTracerT() = default;
    328 
    329  template <typename T>
    330  void onEdge(T** thingp, const char* name);
    331  friend class GenericTracerImpl<MarkingTracerT<markingOptions>>;
    332 
    333  GCMarker* getMarker();
    334 };
    335 
    336 using MarkingTracer = MarkingTracerT<MarkingOptions::None>;
    337 using RootMarkingTracer = MarkingTracerT<MarkingOptions::MarkRootCompartments>;
    338 using WeakMarkingTracer = MarkingTracerT<MarkingOptions::MarkImplicitEdges>;
    339 using ParallelMarkingTracer = MarkingTracerT<MarkingOptions::ParallelMarking>;
    340 
    341 enum ShouldReportMarkTime : bool {
    342  ReportMarkTime = true,
    343  DontReportMarkTime = false
    344 };
    345 
    346 } /* namespace gc */
    347 
    348 class GCMarker {
    349  enum MarkingState : uint8_t {
    350    // Have not yet started marking.
    351    NotActive,
    352 
    353    // Root marking mode. This sets the hasMarkedCells flag on compartments
    354    // containing objects and scripts, which is used to make sure we clean up
    355    // dead compartments.
    356    RootMarking,
    357 
    358    // Main marking mode. Weakmap marking will be populating the
    359    // gcEphemeronEdges tables but not consulting them. The state will
    360    // transition to WeakMarking until it is done, then back to RegularMarking.
    361    RegularMarking,
    362 
    363    // Like RegularMarking but with multiple threads running in parallel.
    364    ParallelMarking,
    365 
    366    // Same as RegularMarking except now every marked obj/script is immediately
    367    // looked up in the gcEphemeronEdges table to find edges generated by
    368    // weakmap keys, and traversing them to their values. Transitions back to
    369    // RegularMarking when done.
    370    WeakMarking,
    371  };
    372 
    373 public:
    374  explicit GCMarker(JSRuntime* rt);
    375  [[nodiscard]] bool init();
    376 
    377  JSRuntime* runtime() { return runtime_; }
    378  JSTracer* tracer() {
    379    return tracer_.match([](auto& t) -> JSTracer* { return &t; });
    380  }
    381 
    382 #ifdef JS_GC_ZEAL
    383  void setMaxCapacity(size_t maxCap) { stack.setMaxCapacity(maxCap); }
    384 #endif
    385 
    386  bool isActive() const { return state != NotActive; }
    387  bool isRegularMarking() const { return state == RegularMarking; }
    388  bool isParallelMarking() const { return state == ParallelMarking; }
    389  bool isWeakMarking() const { return state == WeakMarking; }
    390 
    391  gc::MarkColor markColor() const { return markColor_; }
    392 
    393  bool isDrained() const { return stack.isEmpty() && otherStack.isEmpty(); }
    394 
    395  bool hasEntriesForCurrentColor() { return stack.hasEntries(); }
    396  bool hasBlackEntries() const { return hasEntries(gc::MarkColor::Black); }
    397  bool hasGrayEntries() const { return hasEntries(gc::MarkColor::Gray); }
    398  bool hasEntries(gc::MarkColor color) const;
    399 
    400  bool canDonateWork() const;
    401  bool shouldDonateWork() const;
    402 
    403  void start();
    404  void stop();
    405  void reset();
    406 
    407  [[nodiscard]] bool markUntilBudgetExhausted(
    408      JS::SliceBudget& budget,
    409      gc::ShouldReportMarkTime reportTime = gc::ReportMarkTime);
    410 
    411  void setRootMarkingMode(bool newState);
    412 
    413  bool enterWeakMarkingMode();
    414  void leaveWeakMarkingMode();
    415 
    416  void enterParallelMarkingMode();
    417  void leaveParallelMarkingMode();
    418 
    419  // Do not use linear-time weak marking for the rest of this collection.
    420  // Currently, this will only be triggered by an OOM when updating needed data
    421  // structures.
    422  void abortLinearWeakMarking();
    423 
    424 #ifdef DEBUG
    425  // We can't check atom marking if the helper thread lock is already held by
    426  // the current thread. This allows us to disable the check.
    427  void setCheckAtomMarking(bool check);
    428 
    429  bool shouldCheckCompartments() { return strictCompartmentChecking; }
    430 
    431  bool markOneObjectForTest(JSObject* obj);
    432 #endif
    433 
    434  bool markCurrentColorInParallel(gc::ParallelMarkTask* task,
    435                                  JS::SliceBudget& budget);
    436 
    437  template <uint32_t markingOptions, gc::MarkColor>
    438  bool markOneColor(JS::SliceBudget& budget);
    439 
    440  static size_t moveWork(GCMarker* dst, GCMarker* src, bool allowDistribute);
    441 
    442  [[nodiscard]] bool initStack();
    443  void resetStackCapacity();
    444  void freeStack();
    445 
    446  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    447 
    448  static GCMarker* fromTracer(JSTracer* trc) {
    449    MOZ_ASSERT(trc->isMarkingTracer());
    450    auto* marker = reinterpret_cast<GCMarker*>(uintptr_t(trc) -
    451                                               offsetof(GCMarker, tracer_));
    452    MOZ_ASSERT(marker->tracer() == trc);
    453    return marker;
    454  }
    455 
    456  // Internal public methods, for ease of use by the rest of the GC:
    457 
    458  // If |thing| is unmarked, mark it and then traverse its children.
    459  template <uint32_t, typename T>
    460  void markAndTraverse(T* thing);
    461 
    462  template <typename T>
    463  void markImplicitEdges(T* markedThing);
    464 
    465 private:
    466  /*
    467   * Care must be taken changing the mark color from gray to black. The cycle
    468   * collector depends on the invariant that there are no black to gray edges
    469   * in the GC heap. This invariant lets the CC not trace through black
    470   * objects. If this invariant is violated, the cycle collector may free
    471   * objects that are still reachable.
    472   */
    473  void setMarkColor(gc::MarkColor newColor);
    474  friend class js::gc::AutoSetMarkColor;
    475 
    476  template <typename Tracer>
    477  void setMarkingStateAndTracer(MarkingState prev, MarkingState next);
    478 
    479  // The mutator can shift object elements which could invalidate any elements
    480  // index on the mark stack. Change the index to be relative to the elements
    481  // allocation (to ignore shifted elements) while the mutator is running.
    482  void updateRangesAtStartOfSlice();
    483  void updateRangesAtEndOfSlice();
    484  friend class gc::AutoUpdateMarkStackRanges;
    485 
    486  template <uint32_t markingOptions>
    487  bool processMarkStackTop(JS::SliceBudget& budget);
    488  friend class gc::GCRuntime;
    489 
    490  // Helper methods that coerce their second argument to the base pointer
    491  // type.
    492  template <uint32_t markingOptions, typename S>
    493  void markAndTraverseObjectEdge(S source, JSObject* target) {
    494    markAndTraverseEdge<markingOptions>(source, target);
    495  }
    496  template <uint32_t markingOptions, typename S>
    497  void markAndTraverseStringEdge(S source, JSString* target) {
    498    markAndTraverseEdge<markingOptions>(source, target);
    499  }
    500 
    501  template <uint32_t markingOptions, typename S, typename T>
    502  void markAndTraverseEdge(S* source, T* target);
    503  template <uint32_t markingOptions, typename S, typename T>
    504  void markAndTraverseEdge(S* source, const T& target);
    505 
    506  template <uint32_t markingOptions>
    507  bool markAndTraversePrivateGCThing(JSObject* source, gc::Cell* target);
    508 
    509  template <uint32_t markingOptions>
    510  bool markAndTraverseSymbol(JSObject* source, JS::Symbol* target);
    511 
    512  template <typename S, typename T>
    513  void checkTraversedEdge(S source, T* target);
    514 
    515  // Mark the given GC thing, but do not trace its children. Return true
    516  // if the thing became marked.
    517  template <uint32_t markingOptions, typename T>
    518  [[nodiscard]] bool mark(T* thing);
    519 
    520  // Traverse a GC thing's children, using a strategy depending on the type.
    521  // This can either processing them immediately or push them onto the mark
    522  // stack for later.
    523 #define DEFINE_TRAVERSE_METHOD(_1, Type, _2, _3) \
    524  template <uint32_t>                            \
    525  void traverse(Type* thing);
    526  JS_FOR_EACH_TRACEKIND(DEFINE_TRAVERSE_METHOD)
    527 #undef DEFINE_TRAVERSE_METHOD
    528 
    529  // Process a marked thing's children by calling T::traceChildren().
    530  template <uint32_t markingOptions, typename T>
    531  void traceChildren(T* thing);
    532 
    533  // Process a marked thing's children recursively using an iterative loop and
    534  // manual dispatch, for kinds where this is possible.
    535  template <uint32_t markingOptions, typename T>
    536  void scanChildren(T* thing);
    537 
    538  // Push a marked thing onto the mark stack. Its children will be marked later.
    539  template <uint32_t markingOptions, typename T>
    540  void pushThing(T* thing);
    541 
    542  template <uint32_t markingOptions>
    543  void eagerlyMarkChildren(JSLinearString* str);
    544  template <uint32_t markingOptions>
    545  void eagerlyMarkChildren(JSRope* rope);
    546  template <uint32_t markingOptions>
    547  void eagerlyMarkChildren(JSString* str);
    548  template <uint32_t markingOptions>
    549  void eagerlyMarkChildren(Shape* shape);
    550  template <uint32_t markingOptions>
    551  void eagerlyMarkChildren(PropMap* map);
    552  template <uint32_t markingOptions>
    553  void eagerlyMarkChildren(Scope* scope);
    554 
    555  template <typename T>
    556  inline void pushTaggedPtr(T* ptr);
    557 
    558  inline void pushValueRange(JSObject* obj, SlotsOrElementsKind kind,
    559                             size_t start, size_t end);
    560 
    561  // Mark through edges whose target color depends on the colors of two source
    562  // entities (eg a WeakMap and one of its keys), and push the target onto the
    563  // mark stack.
    564  void markEphemeronEdges(gc::EphemeronEdgeVector& edges,
    565                          gc::MarkColor srcColor);
    566  friend class JS::Zone;
    567 
    568 #ifdef DEBUG
    569  void checkZone(gc::Cell* cell);
    570 #else
    571  void checkZone(gc::Cell* cell) {}
    572 #endif
    573 
    574  template <uint32_t markingOptions>
    575  bool doMarking(JS::SliceBudget& budget, gc::ShouldReportMarkTime reportTime);
    576 
    577  void delayMarkingChildrenOnOOM(gc::Cell* cell);
    578 
    579  /*
    580   * The JSTracer used for marking. This can change depending on the current
    581   * state.
    582   */
    583  mozilla::Variant<gc::MarkingTracer, gc::RootMarkingTracer,
    584                   gc::WeakMarkingTracer, gc::ParallelMarkingTracer>
    585      tracer_;
    586 
    587  JSRuntime* const runtime_;
    588 
    589  // The main mark stack, holding entries of color |markColor_|.
    590  gc::MarkStack stack;
    591 
    592  // The auxiliary mark stack, which may contain entries of the other color.
    593  gc::MarkStack otherStack;
    594 
    595  // Track whether we're using the main or auxiliary stack.
    596  MainThreadOrGCTaskData<bool> haveSwappedStacks;
    597 
    598  // The current mark stack color.
    599  MainThreadOrGCTaskData<gc::MarkColor> markColor_;
    600 
    601  Vector<JS::GCCellPtr, 0, SystemAllocPolicy> unmarkGrayStack;
    602  friend class gc::UnmarkGrayTracer;
    603 
    604  /* Track the state of marking. */
    605  MainThreadOrGCTaskData<MarkingState> state;
    606 
    607  /* Whether we successfully added all edges to the implicit edges table. */
    608  MainThreadOrGCTaskData<bool> haveAllImplicitEdges;
    609 
    610 public:
    611  /*
    612   * Whether weakmaps can be marked incrementally.
    613   *
    614   * JSGC_INCREMENTAL_WEAKMAP_ENABLED
    615   * pref: javascript.options.mem.incremental_weakmap
    616   */
    617  MainThreadOrGCTaskData<bool> incrementalWeakMapMarkingEnabled;
    618 
    619  /* Random number generator state. */
    620  MainThreadOrGCTaskData<mozilla::non_crypto::XorShift128PlusRNG> random;
    621 
    622 #ifdef DEBUG
    623 private:
    624  /* Assert that start and stop are called with correct ordering. */
    625  MainThreadOrGCTaskData<bool> started;
    626 
    627  /*
    628   * Whether to check that atoms traversed are present in atom marking
    629   * bitmap.
    630   */
    631  MainThreadOrGCTaskData<bool> checkAtomMarking;
    632 
    633  /*
    634   * If this is true, all marked objects must belong to a compartment being
    635   * GCed. This is used to look for compartment bugs.
    636   */
    637  MainThreadOrGCTaskData<bool> strictCompartmentChecking;
    638 
    639 public:
    640  /*
    641   * The compartment and zone of the object whose trace hook is currently being
    642   * called, if any. Used to catch cross-compartment edges traced without use of
    643   * TraceCrossCompartmentEdge.
    644   */
    645  MainThreadOrGCTaskData<Compartment*> tracingCompartment;
    646  MainThreadOrGCTaskData<Zone*> tracingZone;
    647 #endif  // DEBUG
    648 };
    649 
    650 namespace gc {
    651 
    652 /*
    653 * Temporarily change the mark color while this class is on the stack.
    654 *
    655 * During incremental sweeping this also transitions zones in the
    656 * current sweep group into the Mark or MarkGray state as appropriate.
    657 */
    658 class MOZ_RAII AutoSetMarkColor {
    659  GCMarker& marker_;
    660  MarkColor initialColor_;
    661 
    662 public:
    663  AutoSetMarkColor(GCMarker& marker, MarkColor newColor)
    664      : marker_(marker), initialColor_(marker.markColor()) {
    665    marker_.setMarkColor(newColor);
    666  }
    667 
    668  AutoSetMarkColor(GCMarker& marker, CellColor newColor)
    669      : AutoSetMarkColor(marker, AsMarkColor(newColor)) {}
    670 
    671  ~AutoSetMarkColor() { marker_.setMarkColor(initialColor_); }
    672 };
    673 
    674 } /* namespace gc */
    675 
    676 } /* namespace js */
    677 
    678 #endif /* gc_GCMarker_h */