summaryrefslogtreecommitdiffstats
path: root/js/src/gc/Zone.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/gc/Zone.h711
1 files changed, 711 insertions, 0 deletions
diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h
new file mode 100644
index 0000000000..5c93270a14
--- /dev/null
+++ b/js/src/gc/Zone.h
@@ -0,0 +1,711 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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_Zone_h
+#define gc_Zone_h
+
+#include "mozilla/Atomics.h"
+#include "mozilla/HashFunctions.h"
+#include "mozilla/SegmentedVector.h"
+
+#include "ds/Bitmap.h"
+#include "gc/ArenaList.h"
+#include "gc/Barrier.h"
+#include "gc/FindSCCs.h"
+#include "gc/GCMarker.h"
+#include "gc/NurseryAwareHashMap.h"
+#include "gc/Statistics.h"
+#include "gc/ZoneAllocator.h"
+#include "js/GCHashTable.h"
+#include "vm/AtomsTable.h"
+#include "vm/JSFunction.h"
+
+namespace js {
+
+class RegExpZone;
+class WeakRefObject;
+
+namespace jit {
+class JitZone;
+} // namespace jit
+
+namespace gc {
+
+class ZoneList;
+
+using ZoneComponentFinder = ComponentFinder<JS::Zone>;
+
+struct UniqueIdGCPolicy {
+ static bool needsSweep(Cell** cell, uint64_t* value);
+};
+
+// Maps a Cell* to a unique, 64bit id.
+using UniqueIdMap = GCHashMap<Cell*, uint64_t, PointerHasher<Cell*>,
+ SystemAllocPolicy, UniqueIdGCPolicy>;
+
+extern uint64_t NextCellUniqueId(JSRuntime* rt);
+
+template <typename T>
+class ZoneAllCellIter;
+
+template <typename T>
+class ZoneCellIter;
+
+// A vector of FinalizationRecord objects, or CCWs to them.
+using FinalizationRecordVector = GCVector<HeapPtrObject, 1, ZoneAllocPolicy>;
+
+} // namespace gc
+
+// If two different nursery strings are wrapped into the same zone, and have
+// the same contents, then deduplication may make them duplicates.
+// `DuplicatesPossible` will allow this and map both wrappers to the same (now
+// tenured) source string.
+using StringWrapperMap =
+ NurseryAwareHashMap<JSString*, JSString*, DefaultHasher<JSString*>,
+ ZoneAllocPolicy, DuplicatesPossible>;
+
+class MOZ_NON_TEMPORARY_CLASS ExternalStringCache {
+ static const size_t NumEntries = 4;
+ mozilla::Array<JSString*, NumEntries> entries_;
+
+ ExternalStringCache(const ExternalStringCache&) = delete;
+ void operator=(const ExternalStringCache&) = delete;
+
+ public:
+ ExternalStringCache() { purge(); }
+ void purge() { mozilla::PodArrayZero(entries_); }
+
+ MOZ_ALWAYS_INLINE JSString* lookup(const char16_t* chars, size_t len) const;
+ MOZ_ALWAYS_INLINE void put(JSString* s);
+};
+
+class MOZ_NON_TEMPORARY_CLASS FunctionToStringCache {
+ struct Entry {
+ BaseScript* script;
+ JSString* string;
+
+ void set(BaseScript* scriptArg, JSString* stringArg) {
+ script = scriptArg;
+ string = stringArg;
+ }
+ };
+ static const size_t NumEntries = 2;
+ mozilla::Array<Entry, NumEntries> entries_;
+
+ FunctionToStringCache(const FunctionToStringCache&) = delete;
+ void operator=(const FunctionToStringCache&) = delete;
+
+ public:
+ FunctionToStringCache() { purge(); }
+ void purge() { mozilla::PodArrayZero(entries_); }
+
+ MOZ_ALWAYS_INLINE JSString* lookup(BaseScript* script) const;
+ MOZ_ALWAYS_INLINE void put(BaseScript* script, JSString* string);
+};
+
+// WeakRefHeapPtrVector is a GCVector of WeakRefObjects.
+class WeakRefHeapPtrVector
+ : public GCVector<js::HeapPtrObject, 1, js::ZoneAllocPolicy> {
+ public:
+ using GCVector::GCVector;
+
+ // call in compacting, to update the target in each WeakRefObject.
+ void sweep(js::HeapPtrObject& target);
+};
+
+// WeakRefMap is a per-zone GCHashMap, which maps from the target of the JS
+// WeakRef to the list of JS WeakRefs.
+class WeakRefMap
+ : public GCHashMap<HeapPtrObject, WeakRefHeapPtrVector,
+ MovableCellHasher<HeapPtrObject>, ZoneAllocPolicy> {
+ public:
+ using GCHashMap::GCHashMap;
+ using Base = GCHashMap<HeapPtrObject, WeakRefHeapPtrVector,
+ MovableCellHasher<HeapPtrObject>, ZoneAllocPolicy>;
+ void sweep(gc::StoreBuffer* sbToLock);
+};
+
+} // namespace js
+
+namespace JS {
+
+// [SMDOC] GC Zones
+//
+// A zone is a collection of compartments. Every compartment belongs to exactly
+// one zone. In Firefox, there is roughly one zone per tab along with a system
+// zone for everything else. Zones mainly serve as boundaries for garbage
+// collection. Unlike compartments, they have no special security properties.
+//
+// Every GC thing belongs to exactly one zone. GC things from the same zone but
+// different compartments can share an arena (4k page). GC things from different
+// zones cannot be stored in the same arena. The garbage collector is capable of
+// collecting one zone at a time; it cannot collect at the granularity of
+// compartments.
+//
+// GC things are tied to zones and compartments as follows:
+//
+// - JSObjects belong to a compartment and cannot be shared between
+// compartments. If an object needs to point to a JSObject in a different
+// compartment, regardless of zone, it must go through a cross-compartment
+// wrapper. Each compartment keeps track of its outgoing wrappers in a table.
+// JSObjects find their compartment via their ObjectGroup.
+//
+// - JSStrings do not belong to any particular compartment, but they do belong
+// to a zone. Thus, two different compartments in the same zone can point to a
+// JSString. When a string needs to be wrapped, we copy it if it's in a
+// different zone and do nothing if it's in the same zone. Thus, transferring
+// strings within a zone is very efficient.
+//
+// - Shapes and base shapes belong to a zone and are shared between compartments
+// in that zone where possible. Accessor shapes store getter and setter
+// JSObjects which belong to a single compartment, so these shapes and all
+// their descendants can't be shared with other compartments.
+//
+// - Scripts are also compartment-local and cannot be shared. A script points to
+// its compartment.
+//
+// - ObjectGroup and JitCode objects belong to a compartment and cannot be
+// shared. There is no mechanism to obtain the compartment from a JitCode
+// object.
+//
+// A zone remains alive as long as any GC things in the zone are alive. A
+// compartment remains alive as long as any JSObjects, scripts, shapes, or base
+// shapes within it are alive.
+//
+// We always guarantee that a zone has at least one live compartment by refusing
+// to delete the last compartment in a live zone.
+class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase<JS::Zone> {
+ private:
+ enum class HelperThreadUse : uint32_t { None, Pending, Active };
+ mozilla::Atomic<HelperThreadUse, mozilla::SequentiallyConsistent>
+ helperThreadUse_;
+
+ // The helper thread context with exclusive access to this zone, if
+ // usedByHelperThread(), or nullptr when on the main thread.
+ js::UnprotectedData<JSContext*> helperThreadOwnerContext_;
+
+ public:
+ js::gc::ArenaLists arenas;
+
+ // Per-zone data for use by an embedder.
+ js::ZoneData<void*> data;
+
+ js::ZoneData<uint32_t> tenuredBigInts;
+
+ js::ZoneOrIonCompileData<uint64_t> nurseryAllocatedStrings;
+
+ // Number of marked/finalzied JSString/JSFatInlineString during major GC.
+ js::ZoneOrGCTaskData<size_t> markedStrings;
+ js::ZoneOrGCTaskData<size_t> finalizedStrings;
+
+ js::ZoneData<bool> allocNurseryStrings;
+ js::ZoneData<bool> allocNurseryBigInts;
+
+ // When true, skip calling the metadata callback. We use this:
+ // - to avoid invoking the callback recursively;
+ // - to avoid observing lazy prototype setup (which confuses callbacks that
+ // want to use the types being set up!);
+ // - to avoid attaching allocation stacks to allocation stack nodes, which
+ // is silly
+ // And so on.
+ js::ZoneData<bool> suppressAllocationMetadataBuilder;
+
+ // Script side-tables. These used to be held by Realm, but are now placed
+ // here in order to allow JSScript to access them during finalize (see bug
+ // 1568245; this change in 1575350). The tables are initialized lazily by
+ // JSScript.
+ js::UniquePtr<js::ScriptCountsMap> scriptCountsMap;
+ js::UniquePtr<js::ScriptLCovMap> scriptLCovMap;
+ js::UniquePtr<js::DebugScriptMap> debugScriptMap;
+#ifdef MOZ_VTUNE
+ js::UniquePtr<js::ScriptVTuneIdMap> scriptVTuneIdMap;
+#endif
+#ifdef JS_CACHEIR_SPEW
+ js::UniquePtr<js::ScriptFinalWarmUpCountMap> scriptFinalWarmUpCountMap;
+#endif
+
+ js::ZoneData<js::StringStats> previousGCStringStats;
+ js::ZoneData<js::StringStats> stringStats;
+
+#ifdef DEBUG
+ js::MainThreadData<unsigned> gcSweepGroupIndex;
+#endif
+
+ private:
+ // Side map for storing unique ids for cells, independent of address.
+ js::ZoneOrGCTaskData<js::gc::UniqueIdMap> uniqueIds_;
+
+ // Number of allocations since the most recent minor GC for this thread.
+ mozilla::Atomic<uint32_t, mozilla::Relaxed> tenuredAllocsSinceMinorGC_;
+
+ // Live weakmaps in this zone.
+ js::ZoneOrGCTaskData<mozilla::LinkedList<js::WeakMapBase>> gcWeakMapList_;
+
+ // The set of compartments in this zone.
+ using CompartmentVector =
+ js::Vector<JS::Compartment*, 1, js::SystemAllocPolicy>;
+ js::MainThreadOrGCTaskData<CompartmentVector> compartments_;
+
+ // All cross-zone string wrappers in the zone.
+ js::MainThreadOrGCTaskData<js::StringWrapperMap> crossZoneStringWrappers_;
+
+ // This zone's gray roots.
+ using GrayRootVector =
+ mozilla::SegmentedVector<js::gc::Cell*, 1024 * sizeof(js::gc::Cell*),
+ js::SystemAllocPolicy>;
+ js::ZoneOrGCTaskData<GrayRootVector> gcGrayRoots_;
+
+ // List of non-ephemeron weak containers to sweep during
+ // beginSweepingSweepGroup.
+ js::ZoneOrGCTaskData<mozilla::LinkedList<detail::WeakCacheBase>> weakCaches_;
+
+ // Mapping from not yet marked keys to a vector of all values that the key
+ // maps to in any live weak map. Separate tables for nursery and tenured
+ // keys.
+ js::ZoneOrGCTaskData<js::gc::WeakKeyTable> gcWeakKeys_;
+ js::ZoneOrGCTaskData<js::gc::WeakKeyTable> gcNurseryWeakKeys_;
+
+ // Keep track of all TypeDescr and related objects in this compartment.
+ // This is used by the GC to trace them all first when compacting, since the
+ // TypedObject trace hook may access these objects.
+ //
+ // There are no barriers here - the set contains only tenured objects so no
+ // post-barrier is required, and these are weak references so no pre-barrier
+ // is required.
+ using TypeDescrObjectSet =
+ js::GCHashSet<JSObject*, js::MovableCellHasher<JSObject*>,
+ js::SystemAllocPolicy>;
+
+ js::ZoneData<JS::WeakCache<TypeDescrObjectSet>> typeDescrObjects_;
+
+ js::MainThreadData<js::UniquePtr<js::RegExpZone>> regExps_;
+
+ // Bitmap of atoms marked by this zone.
+ js::ZoneOrGCTaskData<js::SparseBitmap> markedAtoms_;
+
+ // Set of atoms recently used by this Zone. Purged on GC.
+ js::ZoneOrGCTaskData<js::AtomSet> atomCache_;
+
+ // Cache storing allocated external strings. Purged on GC.
+ js::ZoneOrGCTaskData<js::ExternalStringCache> externalStringCache_;
+
+ // Cache for Function.prototype.toString. Purged on GC.
+ js::ZoneOrGCTaskData<js::FunctionToStringCache> functionToStringCache_;
+
+ // Shared Shape property tree.
+ js::ZoneData<js::PropertyTree> propertyTree_;
+
+ // Set of all unowned base shapes in the Zone.
+ js::ZoneData<js::BaseShapeSet> baseShapes_;
+
+ // Set of initial shapes in the Zone. For certain prototypes -- namely,
+ // those of various builtin classes -- there are two entries: one for a
+ // lookup via TaggedProto, and one for a lookup via JSProtoKey. See
+ // InitialShapeProto.
+ js::ZoneData<js::InitialShapeSet> initialShapes_;
+
+ // List of shapes that may contain nursery pointers.
+ using NurseryShapeVector =
+ js::Vector<js::AccessorShape*, 0, js::SystemAllocPolicy>;
+ js::ZoneData<NurseryShapeVector> nurseryShapes_;
+
+ // The set of all finalization registries in this zone.
+ using FinalizationRegistrySet =
+ GCHashSet<js::HeapPtrObject, js::MovableCellHasher<js::HeapPtrObject>,
+ js::ZoneAllocPolicy>;
+ js::ZoneOrGCTaskData<FinalizationRegistrySet> finalizationRegistries_;
+
+ // A map from finalization registry targets to a list of finalization records
+ // representing registries that the target is registered with and their
+ // associated held values.
+ using FinalizationRecordMap =
+ GCHashMap<js::HeapPtrObject, js::gc::FinalizationRecordVector,
+ js::MovableCellHasher<js::HeapPtrObject>, js::ZoneAllocPolicy>;
+ js::ZoneOrGCTaskData<FinalizationRecordMap> finalizationRecordMap_;
+
+ js::ZoneOrGCTaskData<js::jit::JitZone*> jitZone_;
+
+ js::MainThreadData<bool> gcScheduled_;
+ js::MainThreadData<bool> gcScheduledSaved_;
+ js::MainThreadData<bool> gcPreserveCode_;
+ js::ZoneData<bool> keepShapeCaches_;
+ js::MainThreadData<bool> wasCollected_;
+
+ // Allow zones to be linked into a list
+ js::MainThreadOrGCTaskData<Zone*> listNext_;
+ static Zone* const NotOnList;
+ friend class js::gc::ZoneList;
+
+ js::ZoneOrGCTaskData<js::WeakRefMap> weakRefMap_;
+
+ using KeptAliveSet =
+ JS::GCHashSet<js::HeapPtrObject, js::MovableCellHasher<js::HeapPtrObject>,
+ js::ZoneAllocPolicy>;
+ friend class js::WeakRefObject;
+ js::ZoneOrGCTaskData<KeptAliveSet> keptObjects;
+
+ public:
+ static JS::Zone* from(ZoneAllocator* zoneAlloc) {
+ return static_cast<Zone*>(zoneAlloc);
+ }
+
+ explicit Zone(JSRuntime* rt, Kind kind = NormalZone);
+ ~Zone();
+
+ MOZ_MUST_USE bool init();
+
+ void destroy(JSFreeOp* fop);
+
+ bool ownedByCurrentHelperThread();
+ void setHelperThreadOwnerContext(JSContext* cx);
+
+ // Whether this zone was created for use by a helper thread.
+ bool createdForHelperThread() const {
+ return helperThreadUse_ != HelperThreadUse::None;
+ }
+ // Whether this zone is currently in use by a helper thread.
+ bool usedByHelperThread() {
+ MOZ_ASSERT_IF(isAtomsZone(), helperThreadUse_ == HelperThreadUse::None);
+ return helperThreadUse_ == HelperThreadUse::Active;
+ }
+ void setCreatedForHelperThread() {
+ MOZ_ASSERT(helperThreadUse_ == HelperThreadUse::None);
+ helperThreadUse_ = HelperThreadUse::Pending;
+ }
+ void setUsedByHelperThread() {
+ MOZ_ASSERT(helperThreadUse_ == HelperThreadUse::Pending);
+ helperThreadUse_ = HelperThreadUse::Active;
+ }
+ void clearUsedByHelperThread() {
+ MOZ_ASSERT(helperThreadUse_ != HelperThreadUse::None);
+ helperThreadUse_ = HelperThreadUse::None;
+ }
+
+ MOZ_MUST_USE bool findSweepGroupEdges(Zone* atomsZone);
+
+ enum ShouldDiscardBaselineCode : bool {
+ KeepBaselineCode = false,
+ DiscardBaselineCode
+ };
+
+ enum ShouldDiscardJitScripts : bool {
+ KeepJitScripts = false,
+ DiscardJitScripts
+ };
+
+ void discardJitCode(
+ JSFreeOp* fop,
+ ShouldDiscardBaselineCode discardBaselineCode = DiscardBaselineCode,
+ ShouldDiscardJitScripts discardJitScripts = KeepJitScripts);
+
+ void addSizeOfIncludingThis(
+ mozilla::MallocSizeOf mallocSizeOf, JS::CodeSizes* code,
+ size_t* regexpZone, size_t* jitZone, size_t* baselineStubsOptimized,
+ size_t* uniqueIdMap, size_t* shapeCaches, size_t* atomsMarkBitmaps,
+ size_t* compartmentObjects, size_t* crossCompartmentWrappersTables,
+ size_t* compartmentsPrivateData, size_t* scriptCountsMapArg);
+
+ // Iterate over all cells in the zone. See the definition of ZoneCellIter
+ // in gc/GC-inl.h for the possible arguments and documentation.
+ template <typename T, typename... Args>
+ js::gc::ZoneCellIter<T> cellIter(Args&&... args) {
+ return js::gc::ZoneCellIter<T>(const_cast<Zone*>(this),
+ std::forward<Args>(args)...);
+ }
+
+ // As above, but can return about-to-be-finalised things.
+ template <typename T, typename... Args>
+ js::gc::ZoneAllCellIter<T> cellIterUnsafe(Args&&... args) {
+ return js::gc::ZoneAllCellIter<T>(const_cast<Zone*>(this),
+ std::forward<Args>(args)...);
+ }
+
+ bool hasMarkedRealms();
+
+ void scheduleGC() {
+ MOZ_ASSERT(!RuntimeHeapIsBusy());
+ gcScheduled_ = true;
+ }
+ void unscheduleGC() { gcScheduled_ = false; }
+ bool isGCScheduled() { return gcScheduled_; }
+
+ void setPreservingCode(bool preserving) { gcPreserveCode_ = preserving; }
+ bool isPreservingCode() const { return gcPreserveCode_; }
+
+ // Whether this zone can currently be collected.
+ bool canCollect();
+
+ void changeGCState(GCState prev, GCState next);
+
+ bool isCollecting() const {
+ MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtimeFromMainThread()));
+ return isCollectingFromAnyThread();
+ }
+
+ bool isCollectingFromAnyThread() const {
+ if (RuntimeHeapIsCollecting()) {
+ return gcState_ != NoGC;
+ } else {
+ return needsIncrementalBarrier();
+ }
+ }
+
+ bool shouldMarkInZone() const {
+ // We only need to check needsIncrementalBarrier() for the pre-barrier
+ // verifier. During marking isGCMarking() will always be true.
+ return needsIncrementalBarrier() || isGCMarking();
+ }
+
+ // Was this zone collected in the last GC.
+ bool wasCollected() const { return wasCollected_; }
+ void setWasCollected(bool v) { wasCollected_ = v; }
+
+ // Get a number that is incremented whenever this zone is collected, and
+ // possibly at other times too.
+ uint64_t gcNumber();
+
+ void setNeedsIncrementalBarrier(bool needs);
+ const uint32_t* addressOfNeedsIncrementalBarrier() const {
+ return &needsIncrementalBarrier_;
+ }
+
+ static constexpr size_t offsetOfNeedsIncrementalBarrier() {
+ return offsetof(Zone, needsIncrementalBarrier_);
+ }
+
+ js::jit::JitZone* getJitZone(JSContext* cx) {
+ return jitZone_ ? jitZone_ : createJitZone(cx);
+ }
+ js::jit::JitZone* jitZone() { return jitZone_; }
+
+ void prepareForCompacting();
+
+ void sweepAfterMinorGC(JSTracer* trc);
+ void sweepUniqueIds();
+ void sweepWeakMaps();
+ void sweepCompartments(JSFreeOp* fop, bool keepAtleastOne, bool lastGC);
+
+ js::gc::UniqueIdMap& uniqueIds() { return uniqueIds_.ref(); }
+
+ void notifyObservingDebuggers();
+
+ void clearTables();
+
+ void addTenuredAllocsSinceMinorGC(uint32_t allocs) {
+ tenuredAllocsSinceMinorGC_ += allocs;
+ }
+
+ uint32_t getAndResetTenuredAllocsSinceMinorGC() {
+ return tenuredAllocsSinceMinorGC_.exchange(0);
+ }
+
+ mozilla::LinkedList<js::WeakMapBase>& gcWeakMapList() {
+ return gcWeakMapList_.ref();
+ }
+
+ CompartmentVector& compartments() { return compartments_.ref(); }
+
+ js::StringWrapperMap& crossZoneStringWrappers() {
+ return crossZoneStringWrappers_.ref();
+ }
+ const js::StringWrapperMap& crossZoneStringWrappers() const {
+ return crossZoneStringWrappers_.ref();
+ }
+
+ void dropStringWrappersOnGC();
+
+ void sweepAllCrossCompartmentWrappers();
+ static void fixupAllCrossCompartmentWrappersAfterMovingGC(JSTracer* trc);
+
+ GrayRootVector& gcGrayRoots() { return gcGrayRoots_.ref(); }
+
+ mozilla::LinkedList<detail::WeakCacheBase>& weakCaches() {
+ return weakCaches_.ref();
+ }
+ void registerWeakCache(detail::WeakCacheBase* cachep) {
+ weakCaches().insertBack(cachep);
+ }
+
+ void beforeClearDelegate(JSObject* wrapper, JSObject* delegate) {
+ if (needsIncrementalBarrier()) {
+ beforeClearDelegateInternal(wrapper, delegate);
+ }
+ }
+
+ void afterAddDelegate(JSObject* wrapper) {
+ if (needsIncrementalBarrier()) {
+ afterAddDelegateInternal(wrapper);
+ }
+ }
+
+ void beforeClearDelegateInternal(JSObject* wrapper, JSObject* delegate);
+ void afterAddDelegateInternal(JSObject* wrapper);
+ js::gc::WeakKeyTable& gcWeakKeys() { return gcWeakKeys_.ref(); }
+ js::gc::WeakKeyTable& gcNurseryWeakKeys() { return gcNurseryWeakKeys_.ref(); }
+
+ js::gc::WeakKeyTable& gcWeakKeys(const js::gc::Cell* cell) {
+ return cell->isTenured() ? gcWeakKeys() : gcNurseryWeakKeys();
+ }
+
+ // Perform all pending weakmap entry marking for this zone after
+ // transitioning to weak marking mode.
+ js::gc::IncrementalProgress enterWeakMarkingMode(js::GCMarker* marker,
+ js::SliceBudget& budget);
+ void checkWeakMarkingMode();
+
+ // A set of edges from this zone to other zones used during GC to calculate
+ // sweep groups.
+ NodeSet& gcSweepGroupEdges() {
+ return gcGraphEdges; // Defined in GraphNodeBase base class.
+ }
+ bool hasSweepGroupEdgeTo(Zone* otherZone) const {
+ return gcGraphEdges.has(otherZone);
+ }
+ MOZ_MUST_USE bool addSweepGroupEdgeTo(Zone* otherZone) {
+ MOZ_ASSERT(otherZone->isGCMarking());
+ return gcSweepGroupEdges().put(otherZone);
+ }
+ void clearSweepGroupEdges() { gcSweepGroupEdges().clear(); }
+
+ js::RegExpZone& regExps() { return *regExps_.ref(); }
+
+ JS::WeakCache<TypeDescrObjectSet>& typeDescrObjects() {
+ return typeDescrObjects_.ref();
+ }
+
+ bool addTypeDescrObject(JSContext* cx, HandleObject obj);
+
+ js::SparseBitmap& markedAtoms() { return markedAtoms_.ref(); }
+
+ js::AtomSet& atomCache() { return atomCache_.ref(); }
+
+ void purgeAtomCache();
+
+ js::ExternalStringCache& externalStringCache() {
+ return externalStringCache_.ref();
+ };
+
+ js::FunctionToStringCache& functionToStringCache() {
+ return functionToStringCache_.ref();
+ }
+
+ js::PropertyTree& propertyTree() { return propertyTree_.ref(); }
+
+ js::BaseShapeSet& baseShapes() { return baseShapes_.ref(); }
+
+ js::InitialShapeSet& initialShapes() { return initialShapes_.ref(); }
+
+ NurseryShapeVector& nurseryShapes() { return nurseryShapes_.ref(); }
+
+ void fixupInitialShapeTable();
+ void fixupAfterMovingGC();
+ void fixupScriptMapsAfterMovingGC(JSTracer* trc);
+
+ static js::HashNumber UniqueIdToHash(uint64_t uid);
+
+ // Creates a HashNumber based on getUniqueId. Returns false on OOM.
+ MOZ_MUST_USE bool getHashCode(js::gc::Cell* cell, js::HashNumber* hashp);
+
+ // Gets an existing UID in |uidp| if one exists.
+ MOZ_MUST_USE bool maybeGetUniqueId(js::gc::Cell* cell, uint64_t* uidp);
+
+ // Puts an existing UID in |uidp|, or creates a new UID for this Cell and
+ // puts that into |uidp|. Returns false on OOM.
+ MOZ_MUST_USE bool getOrCreateUniqueId(js::gc::Cell* cell, uint64_t* uidp);
+
+ js::HashNumber getHashCodeInfallible(js::gc::Cell* cell);
+ uint64_t getUniqueIdInfallible(js::gc::Cell* cell);
+
+ // Return true if this cell has a UID associated with it.
+ MOZ_MUST_USE bool hasUniqueId(js::gc::Cell* cell);
+
+ // Transfer an id from another cell. This must only be called on behalf of a
+ // moving GC. This method is infallible.
+ void transferUniqueId(js::gc::Cell* tgt, js::gc::Cell* src);
+
+ // Remove any unique id associated with this Cell.
+ void removeUniqueId(js::gc::Cell* cell);
+
+ // When finished parsing off-thread, transfer any UIDs we created in the
+ // off-thread zone into the target zone.
+ void adoptUniqueIds(JS::Zone* source);
+
+ bool keepShapeCaches() const { return keepShapeCaches_; }
+ void setKeepShapeCaches(bool b) { keepShapeCaches_ = b; }
+
+ // Delete an empty compartment after its contents have been merged.
+ void deleteEmptyCompartment(JS::Compartment* comp);
+
+ void clearRootsForShutdownGC();
+ void finishRoots();
+
+ void traceScriptTableRoots(JSTracer* trc);
+
+ void clearScriptCounts(Realm* realm);
+ void clearScriptLCov(Realm* realm);
+
+ // Add the target of JS WeakRef to a kept-alive set maintained by GC.
+ // See: https://tc39.es/proposal-weakrefs/#sec-keepduringjob
+ bool keepDuringJob(HandleObject target);
+
+ void traceKeptObjects(JSTracer* trc);
+
+ // Clear the kept-alive set.
+ // See: https://tc39.es/proposal-weakrefs/#sec-clear-kept-objects
+ void clearKeptObjects();
+
+#ifdef JSGC_HASH_TABLE_CHECKS
+ void checkAllCrossCompartmentWrappersAfterMovingGC();
+ void checkStringWrappersAfterMovingGC();
+
+ void checkInitialShapesTableAfterMovingGC();
+ void checkBaseShapeTableAfterMovingGC();
+
+ // Assert that the UniqueId table has been redirected successfully.
+ void checkUniqueIdTableAfterMovingGC();
+
+ void checkScriptMapsAfterMovingGC();
+#endif
+
+#ifdef DEBUG
+ // For testing purposes, return the index of the sweep group which this zone
+ // was swept in in the last GC.
+ unsigned lastSweepGroupIndex() { return gcSweepGroupIndex; }
+#endif
+
+ private:
+ js::jit::JitZone* createJitZone(JSContext* cx);
+
+ bool isQueuedForBackgroundSweep() { return isOnList(); }
+
+ void sweepWeakKeysAfterMinorGC();
+
+ FinalizationRegistrySet& finalizationRegistries() {
+ return finalizationRegistries_.ref();
+ }
+
+ FinalizationRecordMap& finalizationRecordMap() {
+ return finalizationRecordMap_.ref();
+ }
+
+ bool isOnList() const;
+ Zone* nextZone() const;
+
+ js::WeakRefMap& weakRefMap() { return weakRefMap_.ref(); }
+
+ friend bool js::CurrentThreadCanAccessZone(Zone* zone);
+ friend class js::gc::GCRuntime;
+};
+
+} // namespace JS
+
+namespace js {
+namespace gc {
+const char* StateName(JS::Zone::GCState state);
+} // namespace gc
+} // namespace js
+
+#endif // gc_Zone_h