Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/js/src/gc/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 25 kB image not shown  

Quelle  GCMarker.h

  Sprache: C
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef gc_GCMarker_h
#define gc_GCMarker_h

#include "mozilla/Variant.h"
#include "mozilla/XorShift128PlusRNG.h"

#include "gc/Barrier.h"
#include "gc/Cell.h"
#include "gc/WeakMap.h"
#include "js/HashTable.h"
#include "js/TracingAPI.h"
#include "js/TypeDecls.h"
#include "threading/ProtectedData.h"

class JSRope;

namespace JS {
class SliceBudget;
}

namespace js {

class GCMarker;
class WeakMapBase;

#ifdef DEBUG
// Force stack resizing to ensure OOM test coverage in debug builds.
static const size_t MARK_STACK_BASE_CAPACITY = 4;
#else
static const size_t MARK_STACK_BASE_CAPACITY = 4096;
#endif

enum class SlotsOrElementsKind {
  Unused = 0,  // Must match SlotsOrElementsRangeTag
  Elements,
  FixedSlots,
  DynamicSlots
};

namespace gc {

enum IncrementalProgress { NotFinished = 0, Finished };

class AutoSetMarkColor;
class AutoUpdateMarkStackRanges;
class Cell;
class MarkStackIter;
class ParallelMarkTask;
template <uint32_t markingOptions>
class UnmarkGrayTracer;

// Ephemerons are edges from a source to a target that are only materialized
// into a table when the owner is marked. (The owner is something like a
// WeakMap, which contains a set of ephemerons each going from a WeakMap key to
// its value.) When marking a ephemeron, only the color of the owner is needed:
// the target is marked with the minimum (least-marked) color of the owner and
// source. So an EphemeronEdge need store only the owner color and the target
// pointer, which can fit into a tagged pointer since targets are aligned Cells.
//
// Note: if the owner's color changes, new EphemeronEdges will be created for
// it.
class EphemeronEdge {
  static constexpr uintptr_t ColorMask = 0x3;
  static_assert(uintptr_t(MarkColor::Gray) <= ColorMask);
  static_assert(uintptr_t(MarkColor::Black) <= ColorMask);
  static_assert(ColorMask < CellAlignBytes);

  uintptr_t taggedTarget;

 public:
  EphemeronEdge(MarkColor color, TenuredCell* cell)
      : taggedTarget(uintptr_t(cell) | uintptr_t(color)) {
    MOZ_ASSERT((uintptr_t(cell) & ColorMask) == 0);
  }

  MarkColor color() const { return MarkColor(taggedTarget & ColorMask); }
  TenuredCell* target() const {
    return reinterpret_cast<TenuredCell*>(taggedTarget & ~ColorMask);
  }
};

using EphemeronEdgeVector = Vector<EphemeronEdge, 2, js::SystemAllocPolicy>;

using EphemeronEdgeTable =
    HashMap<TenuredCell*, EphemeronEdgeVector, PointerHasher<TenuredCell*>,
            js::SystemAllocPolicy>;

/*
 * The mark stack. Pointers in this stack are "gray" in the GC sense, but
 * their references may be marked either black or gray (in the CC sense).
 *
 * When the mark stack is full, the GC does not call js::TraceChildren to mark
 * the reachable "children" of the thing. Rather the thing is put aside and
 * js::TraceChildren is called later when the mark stack is empty.
 *
 * To implement such delayed marking of the children with minimal overhead for
 * the normal case of sufficient stack, we link arenas into a list using
 * Arena::setNextDelayedMarkingArena(). The head of the list is stored in
 * GCMarker::delayedMarkingList. GCMarker::delayMarkingChildren() adds arenas
 * to the list as necessary while markAllDelayedChildren() pops the arenas from
 * the stack until it is empty.
 */

class MarkStack {
 public:
  /*
   * We use a common mark stack to mark GC things of different types and use
   * the explicit tags to distinguish them when it cannot be deduced from
   * the context of push or pop operation.
   */

  enum Tag {
    SlotsOrElementsRangeTag = 0,  // Must match SlotsOrElementsKind::Unused.
    ObjectTag,
    SymbolTag,
    JitCodeTag,
    ScriptTag,
    TempRopeTag,

    LastTag = TempRopeTag
  };

  static const uintptr_t TagMask = 7;
  static_assert(TagMask >= uintptr_t(LastTag),
                "The tag mask must subsume the tags.");
  static_assert(TagMask <= gc::CellAlignMask,
                "The tag mask must be embeddable in a Cell*.");

  class TaggedPtr {
    uintptr_t bits;

    Cell* ptr() const;

    explicit TaggedPtr(uintptr_t bits);

   public:
    TaggedPtr(Tag tag, Cell* ptr);
    static TaggedPtr fromBits(uintptr_t bits);

    uintptr_t asBits() const;
    Tag tag() const;
    template <typename T>
    T* as() const;

    JSObject* asRangeObject() const;
    JSRope* asTempRope() const;

    void assertValid() const;
  };

  class SlotsOrElementsRange {
    uintptr_t startAndKind_;
    TaggedPtr ptr_;

    static constexpr size_t StartShift = 2;
    static constexpr size_t KindMask = (1 << StartShift) - 1;

    SlotsOrElementsRange(uintptr_t startAndKind, uintptr_t ptr);

   public:
    SlotsOrElementsRange(SlotsOrElementsKind kind, JSObject* obj, size_t start);
    static SlotsOrElementsRange fromBits(uintptr_t startAndKind, uintptr_t ptr);

    void assertValid() const;

    uintptr_t asBits0() const;
    uintptr_t asBits1() const;

    SlotsOrElementsKind kind() const;
    size_t start() const;
    TaggedPtr ptr() const;

    void setStart(size_t newStart);
    void setEmpty();
  };

  MarkStack();
  ~MarkStack();

  MarkStack(const MarkStack& other) = delete;
  MarkStack& operator=(const MarkStack& other) = delete;

  void swap(MarkStack& other);

  // The unit for capacity is mark stack words.
  size_t capacity() const { return capacity_; }
#ifdef JS_GC_ZEAL
  void setMaxCapacity(size_t maxCapacity);
#endif

  size_t position() const { return topIndex_; }

  [[nodiscard]] bool init();
  [[nodiscard]] bool resetStackCapacity();

  template <typename T>
  [[nodiscard]] bool push(T* ptr);
  void infalliblePush(const SlotsOrElementsRange& range);
  void infalliblePush(JSObject* obj, SlotsOrElementsKind kind, size_t start);
  [[nodiscard]] bool push(const TaggedPtr& ptr);
  void infalliblePush(const TaggedPtr& ptr);

  // GCMarker::eagerlyMarkChildren uses unused marking stack as temporary
  // storage to hold rope pointers.
  [[nodiscard]] bool pushTempRope(JSRope* rope);

  bool isEmpty() const { return position() == 0; }
  bool hasEntries() const { return !isEmpty(); }

  Tag peekTag() const;
  TaggedPtr popPtr();
  SlotsOrElementsRange popSlotsOrElementsRange();

  void clearAndResetCapacity();
  void clearAndFreeStack();

  void poisonUnused();

  // Ensuring there is space to push |count| more words, growing the stack if
  // necessary.
  template <bool checkMaxCapacity = true>
  [[nodiscard]] bool ensureSpace(size_t count);

  static void moveAllWork(MarkStack& dst, MarkStack& src);
  static size_t moveSomeWork(GCMarker* marker, MarkStack& dst, MarkStack& src,
                             bool allowDistribute);

  size_t sizeOfExcludingThis() const;

 private:
  uintptr_t at(size_t index) const {
    MOZ_ASSERT(topIndex_ <= capacity_);
    MOZ_ASSERT(index < topIndex_);
    return stack_[index];
  }
  uintptr_t* ptr(size_t index) {
    MOZ_ASSERT(topIndex_ <= capacity_);
    MOZ_ASSERT(index <= topIndex_);
    return stack_ + index;
  }

  // Return a pointer to the first unused word beyond the top of the stack.
  uintptr_t* end() { return ptr(topIndex_); }

  [[nodiscard]] bool resize(size_t newCapacity);

  TaggedPtr peekPtr() const;

  [[nodiscard]] bool pushTaggedPtr(Tag tag, Cell* ptr);

  bool indexIsEntryBase(size_t index) const;

  // Area of memory containing the stack.
  MainThreadOrGCTaskData<uintptr_t*> stack_;

  // Size of the stack in words.
  MainThreadOrGCTaskData<size_t> capacity_;

  // Index of the top of the stack.
  MainThreadOrGCTaskData<size_t> topIndex_;

#ifdef JS_GC_ZEAL
  // The maximum stack capacity to grow to.
  MainThreadOrGCTaskData<size_t> maxCapacity_{SIZE_MAX};
#endif

#ifdef DEBUG
 public:
  MainThreadOrGCTaskData<bool> elementsRangesAreValid;
#endif

  friend class MarkStackIter;
};

static_assert(unsigned(SlotsOrElementsKind::Unused) ==
                  unsigned(MarkStack::SlotsOrElementsRangeTag),
              "To split the mark stack we depend on being able to tell the "
              "difference between SlotsOrElementsRange::startAndKind_ and a "
              "tagged SlotsOrElementsRange");

class MOZ_STACK_CLASS MarkStackIter {
  MarkStack& stack_;
  size_t pos_;

 public:
  explicit MarkStackIter(MarkStack& stack);

  bool done() const;
  void next();

  MarkStack::Tag peekTag() const;
  MarkStack::TaggedPtr peekPtr() const;
  bool isSlotsOrElementsRange() const;
  MarkStack::SlotsOrElementsRange slotsOrElementsRange() const;
  void setSlotsOrElementsRange(const MarkStack::SlotsOrElementsRange& range);

 private:
  size_t position() const;
};

// Bitmask of options to parameterize MarkingTracerT.
namespace MarkingOptions {
enum : uint32_t {
  None = 0,

  // Set the compartment's hasMarkedCells flag for roots.
  MarkRootCompartments = 1,

  // The marking tracer is using multiple threads. Use appropriate atomic
  // accesses to update the mark bits correctly.
  AtomicMarking = 2,

  // The marking tracer is operating concurrently with the main thread. Use
  // appropriate atomic accesses to update the mark bits correctly. Don't trace
  // objects that are not safe to access off the main thread.
  ConcurrentMarking = 4,

  // Mark any implicit edges if we are in weak marking mode.
  MarkImplicitEdges = 8,
};
}  // namespace MarkingOptions

// A default set of marking options that works during normal marking and weak
// marking modes. Used for barriers and testing code.
constexpr uint32_t NormalMarkingOptions = MarkingOptions::MarkImplicitEdges;

constexpr uint32_t ConcurrentMarkingOptions =
    MarkingOptions::AtomicMarking | MarkingOptions::ConcurrentMarking;

enum ShouldReportMarkTime : bool {
  ReportMarkTime = true,
  DontReportMarkTime = false
};

template <uint32_t markingOptions>
class MarkingTracerT
    : public GenericTracerImpl<MarkingTracerT<markingOptions>> {
 public:
  MarkingTracerT(JSRuntime* runtime, GCMarker* marker);
  virtual ~MarkingTracerT() = default;

  template <typename T>
  bool onEdge(T** thingp, const char* name);
  friend class GenericTracerImpl<MarkingTracerT<markingOptions>>;

  GCMarker* gcMarker();
  const GCMarker* gcMarker() const;

  // If |thing| is unmarked, mark it and then traverse its children.
  template <typename T>
  void markAndTraverse(T* thing);

  bool doMarking(JS::SliceBudget& budget, gc::ShouldReportMarkTime reportTime);

  bool processMarkStackTop(JS::SliceBudget& budget);

  template <typename T>
  void maybeMarkImplicitEdges(T* markedThing);
  template <typename T>
  void markImplicitEdges(T* markedThing);

  void markEphemeronEdges(gc::EphemeronEdgeVector& edges,
                          gc::MarkColor srcColor);

  static constexpr bool hasOption(uint32_t option) {
    return markingOptions & option;
  }

 private:
  gc::MarkColor markColor() const { return gcMarker()->markColor(); }
  Zone* tracingZone() const { return gcMarker()->tracingZone; }

  template <gc::MarkColor color>
  bool markOneColor(JS::SliceBudget& budget);

  bool markCurrentColor(JS::SliceBudget& budget);
  friend class GCRuntime;

  bool callOrDelayTraceHook(JSObject* obj, const JSClass* clasp,
                            JS::SliceBudget& budget);

  // Helper methods that coerce their second argument to the base pointer
  // type.
  template <typename S>
  void markAndTraverseObjectEdge(S source, JSObject* target) {
    markAndTraverseEdge(source, target);
  }
  template <typename S>
  void markAndTraverseStringEdge(S source, JSString* target) {
    markAndTraverseEdge(source, target);
  }

  template <typename S, typename T>
  void markAndTraverseEdge(S* source, T* target);
  template <typename S, typename T>
  void markAndTraverseEdge(S* source, const T& target);

  bool markAndTraversePrivateGCThing(JSObject* source, gc::Cell* target);

  bool markAndTraverseSymbol(JSObject* source, JS::Symbol* target);

  // Mark the given GC thing, but do not trace its children. Return true
  // if the thing became marked.
  template <typename T>
  [[nodiscard]] bool mark(T* thing);

  // Traverse a GC thing's children, using a strategy depending on the type.
  // This can either processing them immediately or push them onto the mark
  // stack for later.
#define DEFINE_TRAVERSE_METHOD(_1, Type, _2, _3void traverse(Type* thing);
  JS_FOR_EACH_TRACEKIND(DEFINE_TRAVERSE_METHOD)
#undef DEFINE_TRAVERSE_METHOD

  // Process a marked thing's children by calling T::traceChildren().
  template <typename T>
  void traceChildren(T* thing);

  // Process a marked thing's children recursively using an iterative loop and
  // manual dispatch, for kinds where this is possible.
  template <typename T>
  void scanChildren(T* thing);

  // Push a marked thing onto the mark stack. Its children will be marked later.
  template <typename T>
  void pushThing(T* thing);

  void eagerlyMarkChildren(JSString* str);
  void eagerlyMarkChildren(JSLinearString* str);
  void eagerlyMarkChildren(JSRope* rope);
  void eagerlyMarkChildren(Shape* shape);
  void eagerlyMarkChildren(BaseShape* shape);
  void eagerlyMarkChildren(PropMap* map);
  void eagerlyMarkChildren(Scope* scope);
};

using MarkingTracer = MarkingTracerT<MarkingOptions::None>;
using RootMarkingTracer = MarkingTracerT<MarkingOptions::MarkRootCompartments>;
using WeakMarkingTracer = MarkingTracerT<MarkingOptions::MarkImplicitEdges>;
using ParallelMarkingTracer = MarkingTracerT<MarkingOptions::AtomicMarking>;
using ConcurrentMarkingTracer = MarkingTracerT<ConcurrentMarkingOptions>;

/* namespace gc */

class GCMarker {
  template <uint32_t>
  friend class gc::MarkingTracerT;

  enum MarkingState : uint8_t {
    // Have not yet started marking.
    NotActive,

    // Root marking mode. This sets the hasMarkedCells flag on compartments
    // containing objects and scripts, which is used to make sure we clean up
    // dead compartments.
    RootMarking,

    // Main marking mode. Weakmap marking will be populating the
    // gcEphemeronEdges tables but not consulting them. The state will
    // transition to WeakMarking until it is done, then back to RegularMarking.
    RegularMarking,

    // Like RegularMarking but with multiple threads running in parallel.
    ParallelMarking,

    // Same as above, but there is a single thread running (possibly not the
    // main marker thread).
    ParallelMarkingSingleThread,

    // Like RegularMarking but with a single thread running in the background.
    ConcurrentMarking,

    // Same as RegularMarking except now every marked obj/script is immediately
    // looked up in the gcEphemeronEdges table to find edges generated by
    // weakmap keys, and traversing them to their values. Transitions back to
    // RegularMarking when done.
    WeakMarking,
  };

 public:
  explicit GCMarker(JSRuntime* rt);
  [[nodiscard]] bool init();

  JSRuntime* runtime() { return runtime_; }
  JSTracer* tracer() {
    return tracer_.match([](auto& t) -> JSTracer* { return &t; });
  }

  gc::MarkingTracer* getRegularTracer() {
    MOZ_ASSERT(isRegularMarking());
    return &tracer_.as<gc::MarkingTracer>();
  }

  gc::WeakMarkingTracer* getWeakMarkingTracer() {
    MOZ_ASSERT(isWeakMarking());
    return &tracer_.as<gc::WeakMarkingTracer>();
  }

  template <typename F>
  decltype(auto) matchTracer(F&& f) {
    return tracer_.match(std::forward<F>(f));
  }

  template <typename F>
  decltype(auto) matchRegularOrParallelTracer(F&& f) {
    if (isRegularMarking()) {
      return f(tracer_.as<gc::MarkingTracer>());
    }
    MOZ_ASSERT(isParallelMarking());
    return f(tracer_.as<gc::ParallelMarkingTracer>());
  }

#ifdef JS_GC_ZEAL
  void setMaxCapacity(size_t maxCap) { stack.setMaxCapacity(maxCap); }
#endif

  bool isActive() const { return state != NotActive; }
  bool isRegularMarking() const { return state == RegularMarking; }
  bool isParallelMarking() const {
    return state == ParallelMarking || state == ParallelMarkingSingleThread;
  }
  bool isParallelMarkingMultipleThreads() const {
    return state == ParallelMarking;
  }
  bool isWeakMarking() const { return state == WeakMarking; }
  bool isConcurrentMarking() const { return state == ConcurrentMarking; }

  gc::MarkColor markColor() const { return markColor_; }

  bool isDrained() const;
  bool isMarkStackEmpty() const {
    return stack.isEmpty() && otherStack.isEmpty();
  }

  bool hasEntriesForCurrentColor() { return stack.hasEntries(); }
  bool hasBlackEntries() const { return hasEntries(gc::MarkColor::Black); }
  bool hasGrayEntries() const { return hasEntries(gc::MarkColor::Gray); }
  bool hasEntries(gc::MarkColor color) const;

  bool canDonateWork() const;
  bool shouldDonateWork() const;

  void start();
  void stop();
  void reset();

  [[nodiscard]] bool markUntilBudgetExhausted(
      JS::SliceBudget& budget,
      gc::ShouldReportMarkTime reportTime = gc::ReportMarkTime);

  void setRootMarkingMode(bool newState);

  bool enterWeakMarkingMode();
  void leaveWeakMarkingMode();

  void enterParallelMarkingMode();
  void leaveParallelMarkingMode();

  void enterConcurrentMarkingMode();
  void leaveConcurrentMarkingMode();

  // Only relevant when parallel marking: transition to a mode where it is known
  // that a single thread is running.
  void enterSingleThreadedMode();
  void leaveSingleThreadedMode();

  // Do not use linear-time weak marking for the rest of this collection.
  // Currently, this will only be triggered by an OOM when updating needed data
  // structures.
  void abortLinearWeakMarking();

#ifdef DEBUG
  // We can't check atom marking if the helper thread lock is already held by
  // the current thread. This allows us to disable the check.
  void setCheckAtomMarking(bool check);

  bool shouldCheckCompartments() { return strictCompartmentChecking; }

  void markOneObjectForTest(JSObject* obj);

  bool isRootMarking() const { return state == RootMarking; }
#endif

  bool markCurrentColorInParallel(gc::ParallelMarkTask* task,
                                  JS::SliceBudget& budget);

  // Trace the children of WeakMaps that were marked while draining the mark
  // stack (on any thread).
  void markDeferredWeakMapChildren(WeakMapList& deferred);

  static void moveAllWork(GCMarker* dst, GCMarker* src);
  static size_t moveSomeWork(GCMarker* dst, GCMarker* src,
                             bool allowDistribute);

  [[nodiscard]] bool initStack();
  void resetStackCapacity();
  void freeStack();

  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;

  static GCMarker* fromTracer(JSTracer* trc) {
    MOZ_ASSERT(trc->isMarkingTracer());
    auto* marker = reinterpret_cast<GCMarker*>(uintptr_t(trc) -
                                               offsetof(GCMarker, tracer_));
    MOZ_ASSERT(marker->tracer() == trc);
    return marker;
  }

  // Internal public methods, for ease of use by the rest of the GC:

#ifdef JS_GC_CONCURRENT_MARKING

  using MainThreadBuffer = js::Vector<JSObject*, 0, SystemAllocPolicy>;

  bool processMainThreadBuffers(JS::SliceBudget& budget);
  bool processMainThreadBuffer(MainThreadBuffer& buffer,
                               JS::SliceBudget& budget);

  bool mainThreadBuffersAreEmpty() const {
    return blackMainThreadBuffer_.ref().empty() &&
           grayMainThreadBuffer_.ref().empty();
  }

  bool addToMainThreadBuffer(JSObject* object, JS::SliceBudget& budget);

#endif  // JS_GC_CONCURRENT_MARKING

 private:
  /*
   * Care must be taken changing the mark color from gray to black. The cycle
   * collector depends on the invariant that there are no black to gray edges
   * in the GC heap. This invariant lets the CC not trace through black
   * objects. If this invariant is violated, the cycle collector may free
   * objects that are still reachable.
   */

  void setMarkColor(gc::MarkColor newColor);
  friend class js::gc::AutoSetMarkColor;

  void swapMarkStacks();

  template <typename Tracer>
  void setMarkingStateAndTracer(MarkingState prev, MarkingState next);

  // The mutator can shift object elements which could invalidate any elements
  // index on the mark stack. Change the index to be relative to the elements
  // allocation (to ignore shifted elements) while the mutator is running.
  void updateRangesAtStartOfSlice();
  void updateRangesAtEndOfSlice();
  friend class gc::AutoUpdateMarkStackRanges;
  friend class gc::GCRuntime;

  template <typename S, typename T>
  void checkTraversedEdge(S source, T* target);

  template <typename T>
  inline void pushTaggedPtr(T* ptr);

  inline void pushValueRange(JSObject* obj, SlotsOrElementsKind kind,
                             size_t start, size_t end);

#ifdef DEBUG
  void checkZone(gc::Cell* cell);
#else
  void checkZone(gc::Cell* cell) {}
#endif

  void delayMarkingChildrenOnOOM(gc::Cell* cell);

  // Called by stop() and reset().
  void deactivate();

  /*
   * The JSTracer used for marking. This can change depending on the current
   * state.
   */

  mozilla::Variant<gc::MarkingTracer, gc::RootMarkingTracer,
                   gc::WeakMarkingTracer, gc::ParallelMarkingTracer,
                   gc::ConcurrentMarkingTracer>
      tracer_;

  JSRuntime* const runtime_;

  // The main mark stack, holding entries of color |markColor_|.
  gc::MarkStack stack;

  // The auxiliary mark stack, which may contain entries of the other color.
  gc::MarkStack otherStack;

  // Track whether we're using the main or auxiliary stack.
  MainThreadOrGCTaskData<bool> haveSwappedStacks;

  // The current mark stack color.
  MainThreadOrGCTaskData<gc::MarkColor> markColor_;

#ifdef JS_GC_CONCURRENT_MARKING
  // List of cells that have tracing work that cannot be performed concurrently
  // with the main thread.
  MainThreadOrGCTaskData<MainThreadBuffer> blackMainThreadBuffer_;
  MainThreadOrGCTaskData<MainThreadBuffer> grayMainThreadBuffer_;
#endif

  Vector<JS::GCCellPtr, 0, SystemAllocPolicy> unmarkGrayStack;
  template <uint32_t markingOptions>
  friend class gc::UnmarkGrayTracer;

  /* Track the state of marking. */
  MainThreadOrGCTaskData<MarkingState> state;

 public:
  /*
   * Whether weakmaps can be marked incrementally.
   *
   * JSGC_INCREMENTAL_WEAKMAP_ENABLED
   * pref: javascript.options.mem.incremental_weakmap
   */

  MainThreadOrGCTaskData<bool> incrementalWeakMapMarkingEnabled;

  /* Random number generator state. */
  MainThreadOrGCTaskData<mozilla::non_crypto::XorShift128PlusRNG> random;

  /*
   * The zone of the object whose trace hook is currently being
   * called, if any. Set with AutoSetTracingSource.
   *
   * This is required so that MarkingTracerT::onEdge can keep the source zone's
   * atom-marking bitmap entry for Symbol edges in sync. It's also used in debug
   * builds to catch cross-compartment edges traced without
   * TraceCrossCompartmentEdge.
   */

  MainThreadOrGCTaskData<Zone*> tracingZone;

#ifdef DEBUG
 private:
  /* Assert that start and stop are called with correct ordering. */
  MainThreadOrGCTaskData<bool> started;

  /*
   * Whether to check that atoms traversed are present in atom marking
   * bitmap.
   */

  MainThreadOrGCTaskData<bool> checkAtomMarking;

  /*
   * If this is true, all marked objects must belong to a compartment being
   * GCed. This is used to look for compartment bugs.
   */

  MainThreadOrGCTaskData<bool> strictCompartmentChecking;

 public:
  /*
   * The compartment of the object whose trace hook is currently being called,
   * if any. Used to catch cross-compartment edges traced without use of
   * TraceCrossCompartmentEdge.
   */

  MainThreadOrGCTaskData<Compartment*> tracingCompartment;
#endif  // DEBUG
};

inline bool IsConcurrentMarkingTracer(JSTracer* trc) {
  return trc->isMarkingTracer() &&
         GCMarker::fromTracer(trc)->isConcurrentMarking();
}

namespace gc {

enum class AllowGrayMarkingBeforeEndOfBlackMarking : bool {
  No = false,
  Yes = true
};

/*
 * Temporarily change the mark color while this class is on the stack.
 *
 * For efficiency reasons we don't normally allow gray marking while there is
 * black marking work to do, since we might end up marking the same things
 * twice. If you really need this you can pass a parameter to allow it.
 */

class MOZ_RAII AutoSetMarkColor {
  GCMarker& marker_;
  MarkColor initialColor_;

 public:
  AutoSetMarkColor(GCMarker& marker, MarkColor newColor,
                   AllowGrayMarkingBeforeEndOfBlackMarking allowGrayMarking =
                       AllowGrayMarkingBeforeEndOfBlackMarking::No)
      : marker_(marker), initialColor_(marker.markColor()) {
    MOZ_ASSERT_IF(newColor == MarkColor::Gray && !bool(allowGrayMarking),
                  !marker.hasBlackEntries());
    marker.setMarkColor(newColor);
  }

  AutoSetMarkColor(GCMarker& marker, CellColor newColor)
      : AutoSetMarkColor(marker, AsMarkColor(newColor)) {}

  ~AutoSetMarkColor() { marker_.setMarkColor(initialColor_); }
};

inline AutoMarkingLock::AutoMarkingLock(JSTracer* trc,
                                        MarkingLock& markingLock) {
#ifdef JS_GC_CONCURRENT_MARKING
  if (IsConcurrentMarkingTracer(trc)) {
    lock = &markingLock;
    runtime = trc->runtime();
    lock->lock(runtime);
  }
#endif
}

MOZ_ALWAYS_INLINE void MemoryAcquireFence(JSTracer* trc) {
#ifdef JS_GC_CONCURRENT_MARKING
  if (trc->isMarkingTracer() &&
      GCMarker::fromTracer(trc)->isConcurrentMarking()) {
    std::atomic_thread_fence(std::memory_order_acquire);
#  ifdef MOZ_TSAN
    TSANMemoryAcquireFence(trc->runtime());
#  endif
  }
#endif
}

template <uint32_t markingOptions>
MOZ_ALWAYS_INLINE void MemoryAcquireFence(JSRuntime* runtime) {
#ifdef JS_GC_CONCURRENT_MARKING
  if (bool(markingOptions & MarkingOptions::ConcurrentMarking)) {
    std::atomic_thread_fence(std::memory_order_acquire);
#  ifdef MOZ_TSAN
    TSANMemoryAcquireFence(runtime);
#  endif
  }
#endif
}

/* namespace gc */

/* namespace js */

#endif /* gc_GCMarker_h */

Messung V0.5 in Prozent
C=89 H=100 G=94

¤ Dauer der Verarbeitung: 0.9 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.