LCOV - code coverage report
Current view: top level - js/src/gc - Zone.h (source / functions) Hit Total Coverage
Test: output.info Lines: 64 167 38.3 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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_Zone_h
       8             : #define gc_Zone_h
       9             : 
      10             : #include "mozilla/Atomics.h"
      11             : #include "mozilla/HashFunctions.h"
      12             : 
      13             : #include "gc/FindSCCs.h"
      14             : #include "gc/GCRuntime.h"
      15             : #include "js/GCHashTable.h"
      16             : #include "vm/MallocProvider.h"
      17             : #include "vm/RegExpShared.h"
      18             : #include "vm/Runtime.h"
      19             : 
      20             : namespace js {
      21             : 
      22             : class Debugger;
      23             : 
      24             : namespace jit {
      25             : class JitZone;
      26             : } // namespace jit
      27             : 
      28             : namespace gc {
      29             : 
      30           0 : struct ZoneComponentFinder : public ComponentFinder<JS::Zone, ZoneComponentFinder>
      31             : {
      32             :     ZoneComponentFinder(uintptr_t sl, JS::Zone* maybeAtomsZone)
      33           0 :       : ComponentFinder<JS::Zone, ZoneComponentFinder>(sl), maybeAtomsZone(maybeAtomsZone)
      34             :     {}
      35             : 
      36             :     JS::Zone* maybeAtomsZone;
      37             : };
      38             : 
      39             : struct UniqueIdGCPolicy {
      40             :     static bool needsSweep(Cell** cell, uint64_t* value);
      41             : };
      42             : 
      43             : // Maps a Cell* to a unique, 64bit id.
      44             : using UniqueIdMap = GCHashMap<Cell*,
      45             :                               uint64_t,
      46             :                               PointerHasher<Cell*>,
      47             :                               SystemAllocPolicy,
      48             :                               UniqueIdGCPolicy>;
      49             : 
      50             : extern uint64_t NextCellUniqueId(JSRuntime* rt);
      51             : 
      52             : template <typename T>
      53             : class ZoneCellIter;
      54             : 
      55             : } // namespace gc
      56             : 
      57             : class MOZ_NON_TEMPORARY_CLASS ExternalStringCache
      58             : {
      59             :     static const size_t NumEntries = 4;
      60             :     mozilla::Array<JSString*, NumEntries> entries_;
      61             : 
      62             :     ExternalStringCache(const ExternalStringCache&) = delete;
      63             :     void operator=(const ExternalStringCache&) = delete;
      64             : 
      65             :   public:
      66           0 :     ExternalStringCache() { purge(); }
      67           0 :     void purge() { mozilla::PodArrayZero(entries_); }
      68             : 
      69             :     MOZ_ALWAYS_INLINE JSString* lookup(const char16_t* chars, size_t len) const;
      70             :     MOZ_ALWAYS_INLINE void put(JSString* s);
      71             : };
      72             : 
      73             : class MOZ_NON_TEMPORARY_CLASS FunctionToStringCache
      74             : {
      75             :     struct Entry {
      76             :         JSScript* script;
      77             :         JSString* string;
      78             : 
      79             :         void set(JSScript* scriptArg, JSString* stringArg) {
      80           0 :             script = scriptArg;
      81           0 :             string = stringArg;
      82             :         }
      83             :     };
      84             :     static const size_t NumEntries = 2;
      85             :     mozilla::Array<Entry, NumEntries> entries_;
      86             : 
      87             :     FunctionToStringCache(const FunctionToStringCache&) = delete;
      88             :     void operator=(const FunctionToStringCache&) = delete;
      89             : 
      90             :   public:
      91           0 :     FunctionToStringCache() { purge(); }
      92           0 :     void purge() { mozilla::PodArrayZero(entries_); }
      93             : 
      94             :     MOZ_ALWAYS_INLINE JSString* lookup(JSScript* script) const;
      95             :     MOZ_ALWAYS_INLINE void put(JSScript* script, JSString* string);
      96             : };
      97             : 
      98             : } // namespace js
      99             : 
     100             : namespace JS {
     101             : 
     102             : // A zone is a collection of compartments. Every compartment belongs to exactly
     103             : // one zone. In Firefox, there is roughly one zone per tab along with a system
     104             : // zone for everything else. Zones mainly serve as boundaries for garbage
     105             : // collection. Unlike compartments, they have no special security properties.
     106             : //
     107             : // Every GC thing belongs to exactly one zone. GC things from the same zone but
     108             : // different compartments can share an arena (4k page). GC things from different
     109             : // zones cannot be stored in the same arena. The garbage collector is capable of
     110             : // collecting one zone at a time; it cannot collect at the granularity of
     111             : // compartments.
     112             : //
     113             : // GC things are tied to zones and compartments as follows:
     114             : //
     115             : // - JSObjects belong to a compartment and cannot be shared between
     116             : //   compartments. If an object needs to point to a JSObject in a different
     117             : //   compartment, regardless of zone, it must go through a cross-compartment
     118             : //   wrapper. Each compartment keeps track of its outgoing wrappers in a table.
     119             : //   JSObjects find their compartment via their ObjectGroup.
     120             : //
     121             : // - JSStrings do not belong to any particular compartment, but they do belong
     122             : //   to a zone. Thus, two different compartments in the same zone can point to a
     123             : //   JSString. When a string needs to be wrapped, we copy it if it's in a
     124             : //   different zone and do nothing if it's in the same zone. Thus, transferring
     125             : //   strings within a zone is very efficient.
     126             : //
     127             : // - Shapes and base shapes belong to a zone and are shared between compartments
     128             : //   in that zone where possible. Accessor shapes store getter and setter
     129             : //   JSObjects which belong to a single compartment, so these shapes and all
     130             : //   their descendants can't be shared with other compartments.
     131             : //
     132             : // - Scripts are also compartment-local and cannot be shared. A script points to
     133             : //   its compartment.
     134             : //
     135             : // - ObjectGroup and JitCode objects belong to a compartment and cannot be
     136             : //   shared. There is no mechanism to obtain the compartment from a JitCode
     137             : //   object.
     138             : //
     139             : // A zone remains alive as long as any GC things in the zone are alive. A
     140             : // compartment remains alive as long as any JSObjects, scripts, shapes, or base
     141             : // shapes within it are alive.
     142             : //
     143             : // We always guarantee that a zone has at least one live compartment by refusing
     144             : // to delete the last compartment in a live zone.
     145             : class Zone : public JS::shadow::Zone,
     146             :              public js::gc::GraphNodeBase<JS::Zone>,
     147             :              public js::MallocProvider<JS::Zone>
     148             : {
     149             :   public:
     150             :     explicit Zone(JSRuntime* rt);
     151             :     ~Zone();
     152             :     MOZ_MUST_USE bool init(bool isSystem);
     153             :     void destroy(js::FreeOp *fop);
     154             : 
     155             :   private:
     156             :     enum class HelperThreadUse : uint32_t {
     157             :         None,
     158             :         Pending,
     159             :         Active
     160             :     };
     161             :     mozilla::Atomic<HelperThreadUse> helperThreadUse_;
     162             : 
     163             :     // The helper thread context with exclusive access to this zone, if
     164             :     // usedByHelperThread(), or nullptr when on the main thread.
     165             :     js::UnprotectedData<JSContext*> helperThreadOwnerContext_;
     166             : 
     167             :   public:
     168             :     bool ownedByCurrentHelperThread();
     169             :     void setHelperThreadOwnerContext(JSContext* cx);
     170             : 
     171             :     // Whether this zone was created for use by a helper thread.
     172             :     bool createdForHelperThread() const {
     173        1500 :         return helperThreadUse_ != HelperThreadUse::None;
     174             :     }
     175             :     // Whether this zone is currently in use by a helper thread.
     176           0 :     bool usedByHelperThread() {
     177           0 :         MOZ_ASSERT_IF(isAtomsZone(), helperThreadUse_ == HelperThreadUse::None);
     178    21530294 :         return helperThreadUse_ == HelperThreadUse::Active;
     179             :     }
     180           0 :     void setCreatedForHelperThread() {
     181           0 :         MOZ_ASSERT(helperThreadUse_ == HelperThreadUse::None);
     182           0 :         helperThreadUse_ = HelperThreadUse::Pending;
     183           0 :     }
     184           0 :     void setUsedByHelperThread() {
     185           0 :         MOZ_ASSERT(helperThreadUse_ == HelperThreadUse::Pending);
     186           0 :         helperThreadUse_ = HelperThreadUse::Active;
     187           0 :     }
     188           0 :     void clearUsedByHelperThread() {
     189           0 :         MOZ_ASSERT(helperThreadUse_ != HelperThreadUse::None);
     190           0 :         helperThreadUse_ = HelperThreadUse::None;
     191           5 :     }
     192             : 
     193             :     void findOutgoingEdges(js::gc::ZoneComponentFinder& finder);
     194             : 
     195             :     void discardJitCode(js::FreeOp* fop, bool discardBaselineCode = true);
     196             : 
     197             :     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
     198             :                                 size_t* typePool,
     199             :                                 size_t* regexpZone,
     200             :                                 size_t* jitZone,
     201             :                                 size_t* baselineStubsOptimized,
     202             :                                 size_t* cachedCFG,
     203             :                                 size_t* uniqueIdMap,
     204             :                                 size_t* shapeTables,
     205             :                                 size_t* atomsMarkBitmaps,
     206             :                                 size_t* compartmentObjects,
     207             :                                 size_t* crossCompartmentWrappersTables,
     208             :                                 size_t* compartmentsPrivateData);
     209             : 
     210             :     // Iterate over all cells in the zone. See the definition of ZoneCellIter
     211             :     // in gc/GC-inl.h for the possible arguments and documentation.
     212             :     template <typename T, typename... Args>
     213             :     js::gc::ZoneCellIter<T> cellIter(Args&&... args) {
     214          11 :         return js::gc::ZoneCellIter<T>(const_cast<Zone*>(this), std::forward<Args>(args)...);
     215             :     }
     216             : 
     217           0 :     MOZ_MUST_USE void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes,
     218             :                                      void* reallocPtr = nullptr) {
     219           0 :         if (!js::CurrentThreadCanAccessRuntime(runtime_))
     220             :             return nullptr;
     221           0 :         return runtimeFromMainThread()->onOutOfMemory(allocFunc, nbytes, reallocPtr);
     222             :     }
     223           0 :     void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); }
     224             : 
     225             :     void beginSweepTypes(bool releaseTypes);
     226             : 
     227             :     bool hasMarkedRealms();
     228             : 
     229           0 :     void scheduleGC() { MOZ_ASSERT(!RuntimeHeapIsBusy()); gcScheduled_ = true; }
     230           0 :     void unscheduleGC() { gcScheduled_ = false; }
     231           0 :     bool isGCScheduled() { return gcScheduled_; }
     232             : 
     233           0 :     void setPreservingCode(bool preserving) { gcPreserveCode_ = preserving; }
     234           0 :     bool isPreservingCode() const { return gcPreserveCode_; }
     235             : 
     236             :     // Whether this zone can currently be collected. This doesn't take account
     237             :     // of AutoKeepAtoms for the atoms zone.
     238             :     bool canCollect();
     239             : 
     240           0 :     void changeGCState(GCState prev, GCState next) {
     241           0 :         MOZ_ASSERT(RuntimeHeapIsBusy());
     242           0 :         MOZ_ASSERT(gcState() == prev);
     243           0 :         MOZ_ASSERT_IF(next != NoGC, canCollect());
     244           0 :         gcState_ = next;
     245           0 :     }
     246             : 
     247           0 :     bool isCollecting() const {
     248           0 :         MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtimeFromMainThread()));
     249           0 :         return isCollectingFromAnyThread();
     250             :     }
     251             : 
     252           0 :     bool isCollectingFromAnyThread() const {
     253           0 :         if (RuntimeHeapIsCollecting())
     254           0 :             return gcState_ != NoGC;
     255             :         else
     256           0 :             return needsIncrementalBarrier();
     257             :     }
     258             : 
     259             :     // If this returns true, all object tracing must be done with a GC marking
     260             :     // tracer.
     261          72 :     bool requireGCTracer() const {
     262          72 :         JSRuntime* rt = runtimeFromAnyThread();
     263           0 :         return RuntimeHeapIsMajorCollecting() && !rt->gc.isHeapCompacting() && gcState_ != NoGC;
     264             :     }
     265             : 
     266             :     bool shouldMarkInZone() const {
     267           0 :         return needsIncrementalBarrier() || isGCMarking();
     268             :     }
     269             : 
     270             :     // Get a number that is incremented whenever this zone is collected, and
     271             :     // possibly at other times too.
     272             :     uint64_t gcNumber();
     273             : 
     274             :     bool compileBarriers() const { return compileBarriers(needsIncrementalBarrier()); }
     275             :     bool compileBarriers(bool needsIncrementalBarrier) const {
     276             :         return needsIncrementalBarrier ||
     277             :                runtimeFromMainThread()->hasZealMode(js::gc::ZealMode::VerifierPre);
     278             :     }
     279             : 
     280             :     void setNeedsIncrementalBarrier(bool needs);
     281         943 :     const uint32_t* addressOfNeedsIncrementalBarrier() const { return &needsIncrementalBarrier_; }
     282             : 
     283           0 :     js::jit::JitZone* getJitZone(JSContext* cx) { return jitZone_ ? jitZone_ : createJitZone(cx); }
     284       74282 :     js::jit::JitZone* jitZone() { return jitZone_; }
     285             : 
     286    40082838 :     bool isAtomsZone() const { return runtimeFromAnyThread()->isAtomsZone(this); }
     287           0 :     bool isSelfHostingZone() const { return runtimeFromAnyThread()->isSelfHostingZone(this); }
     288             : 
     289             :     void prepareForCompacting();
     290             : 
     291             : #ifdef DEBUG
     292             :     // For testing purposes, return the index of the sweep group which this zone
     293             :     // was swept in in the last GC.
     294             :     unsigned lastSweepGroupIndex() { return gcLastSweepGroupIndex; }
     295             : #endif
     296             : 
     297             :     void sweepBreakpoints(js::FreeOp* fop);
     298             :     void sweepUniqueIds();
     299             :     void sweepWeakMaps();
     300             :     void sweepCompartments(js::FreeOp* fop, bool keepAtleastOne, bool lastGC);
     301             : 
     302             :     using DebuggerVector = js::Vector<js::Debugger*, 0, js::SystemAllocPolicy>;
     303             : 
     304             :   private:
     305             :     js::ZoneData<DebuggerVector*> debuggers;
     306             : 
     307             :     js::jit::JitZone* createJitZone(JSContext* cx);
     308             : 
     309             :     bool isQueuedForBackgroundSweep() {
     310           0 :         return isOnList();
     311             :     }
     312             : 
     313             :     // Side map for storing a unique ids for cells, independent of address.
     314             :     js::ZoneOrGCTaskData<js::gc::UniqueIdMap> uniqueIds_;
     315             : 
     316           0 :     js::gc::UniqueIdMap& uniqueIds() { return uniqueIds_.ref(); }
     317             : 
     318             :   public:
     319             :     bool hasDebuggers() const { return debuggers && debuggers->length(); }
     320           0 :     DebuggerVector* getDebuggers() const { return debuggers; }
     321             :     DebuggerVector* getOrCreateDebuggers(JSContext* cx);
     322             : 
     323             :     void notifyObservingDebuggers();
     324             : 
     325             :     void clearTables();
     326             : 
     327             :     /*
     328             :      * When true, skip calling the metadata callback. We use this:
     329             :      * - to avoid invoking the callback recursively;
     330             :      * - to avoid observing lazy prototype setup (which confuses callbacks that
     331             :      *   want to use the types being set up!);
     332             :      * - to avoid attaching allocation stacks to allocation stack nodes, which
     333             :      *   is silly
     334             :      * And so on.
     335             :      */
     336             :     js::ZoneData<bool> suppressAllocationMetadataBuilder;
     337             : 
     338             :     js::gc::ArenaLists arenas;
     339             : 
     340             :     js::TypeZone types;
     341             : 
     342             :   private:
     343             :     /* Live weakmaps in this zone. */
     344             :     js::ZoneOrGCTaskData<mozilla::LinkedList<js::WeakMapBase>> gcWeakMapList_;
     345             :   public:
     346          34 :     mozilla::LinkedList<js::WeakMapBase>& gcWeakMapList() { return gcWeakMapList_.ref(); }
     347             : 
     348             :     typedef js::Vector<JS::Compartment*, 1, js::SystemAllocPolicy> CompartmentVector;
     349             : 
     350             :   private:
     351             :     // The set of compartments in this zone.
     352             :     js::MainThreadOrGCTaskData<CompartmentVector> compartments_;
     353             :   public:
     354        5991 :     CompartmentVector& compartments() { return compartments_.ref(); }
     355             : 
     356             :     // This zone's gray roots.
     357             :     typedef js::Vector<js::gc::Cell*, 0, js::SystemAllocPolicy> GrayRootVector;
     358             :   private:
     359             :     js::ZoneOrGCTaskData<GrayRootVector> gcGrayRoots_;
     360             :   public:
     361           0 :     GrayRootVector& gcGrayRoots() { return gcGrayRoots_.ref(); }
     362             : 
     363             :     // This zone's weak edges found via graph traversal during marking,
     364             :     // preserved for re-scanning during sweeping.
     365             :     using WeakEdges = js::Vector<js::gc::TenuredCell**, 0, js::SystemAllocPolicy>;
     366             :   private:
     367             :     js::ZoneOrGCTaskData<WeakEdges> gcWeakRefs_;
     368             :   public:
     369           0 :     WeakEdges& gcWeakRefs() { return gcWeakRefs_.ref(); }
     370             : 
     371             :   private:
     372             :     // List of non-ephemeron weak containers to sweep during beginSweepingSweepGroup.
     373             :     js::ZoneOrGCTaskData<mozilla::LinkedList<detail::WeakCacheBase>> weakCaches_;
     374             :   public:
     375         249 :     mozilla::LinkedList<detail::WeakCacheBase>& weakCaches() { return weakCaches_.ref(); }
     376             :     void registerWeakCache(detail::WeakCacheBase* cachep) {
     377         498 :         weakCaches().insertBack(cachep);
     378             :     }
     379             : 
     380             :   private:
     381             :     /*
     382             :      * Mapping from not yet marked keys to a vector of all values that the key
     383             :      * maps to in any live weak map.
     384             :      */
     385             :     js::ZoneOrGCTaskData<js::gc::WeakKeyTable> gcWeakKeys_;
     386             :   public:
     387          21 :     js::gc::WeakKeyTable& gcWeakKeys() { return gcWeakKeys_.ref(); }
     388             : 
     389             :   private:
     390             :     // A set of edges from this zone to other zones.
     391             :     //
     392             :     // This is used during GC while calculating sweep groups to record edges
     393             :     // that can't be determined by examining this zone by itself.
     394             :     js::MainThreadData<ZoneSet> gcSweepGroupEdges_;
     395             : 
     396             :   public:
     397          21 :     ZoneSet& gcSweepGroupEdges() { return gcSweepGroupEdges_.ref(); }
     398             : 
     399             :     // Keep track of all TypeDescr and related objects in this compartment.
     400             :     // This is used by the GC to trace them all first when compacting, since the
     401             :     // TypedObject trace hook may access these objects.
     402             :     //
     403             :     // There are no barriers here - the set contains only tenured objects so no
     404             :     // post-barrier is required, and these are weak references so no pre-barrier
     405             :     // is required.
     406             :     using TypeDescrObjectSet = js::GCHashSet<JSObject*,
     407             :                                              js::MovableCellHasher<JSObject*>,
     408             :                                              js::SystemAllocPolicy>;
     409             :   private:
     410             :     js::ZoneData<JS::WeakCache<TypeDescrObjectSet>> typeDescrObjects_;
     411             : 
     412             :     // Malloc counter to measure memory pressure for GC scheduling. This
     413             :     // counter should be used only when it's not possible to know the size of
     414             :     // a free.
     415             :     js::gc::MemoryCounter gcMallocCounter;
     416             : 
     417             :     // Counter of JIT code executable memory for GC scheduling. Also imprecise,
     418             :     // since wasm can generate code that outlives a zone.
     419             :     js::gc::MemoryCounter jitCodeCounter;
     420             : 
     421           0 :     void updateMemoryCounter(js::gc::MemoryCounter& counter, size_t nbytes) {
     422           0 :         JSRuntime* rt = runtimeFromAnyThread();
     423             : 
     424      143485 :         counter.update(nbytes);
     425           0 :         auto trigger = counter.shouldTriggerGC(rt->gc.tunables);
     426      143487 :         if (MOZ_LIKELY(trigger == js::gc::NoTrigger) || trigger <= counter.triggered())
     427             :             return;
     428             : 
     429           0 :         if (!js::CurrentThreadCanAccessRuntime(rt))
     430             :             return;
     431             : 
     432           0 :         bool wouldInterruptGC = rt->gc.isIncrementalGCInProgress() && !isCollecting();
     433           0 :         if (wouldInterruptGC && !counter.shouldResetIncrementalGC(rt->gc.tunables))
     434             :             return;
     435             : 
     436           0 :         if (!rt->gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC,
     437             :                                   counter.bytes(), counter.maxBytes()))
     438             :         {
     439             :             return;
     440             :         }
     441             : 
     442           0 :         counter.recordTrigger(trigger);
     443             :     }
     444             : 
     445             :   public:
     446             :     js::RegExpZone regExps;
     447             : 
     448         105 :     JS::WeakCache<TypeDescrObjectSet>& typeDescrObjects() { return typeDescrObjects_.ref(); }
     449             : 
     450             :     bool addTypeDescrObject(JSContext* cx, HandleObject obj);
     451             : 
     452             :     void setGCMaxMallocBytes(size_t value, const js::AutoLockGC& lock) {
     453          33 :         gcMallocCounter.setMax(value, lock);
     454             :     }
     455             :     void updateMallocCounter(size_t nbytes) {
     456      140676 :         updateMemoryCounter(gcMallocCounter, nbytes);
     457             :     }
     458             :     void adoptMallocBytes(Zone* other) {
     459           5 :         gcMallocCounter.adopt(other->gcMallocCounter);
     460             :     }
     461           0 :     size_t GCMaxMallocBytes() const { return gcMallocCounter.maxBytes(); }
     462           0 :     size_t GCMallocBytes() const { return gcMallocCounter.bytes(); }
     463             : 
     464             :     void updateJitCodeMallocBytes(size_t nbytes) {
     465           0 :         updateMemoryCounter(jitCodeCounter, nbytes);
     466             :     }
     467             : 
     468             :     void updateAllGCMallocCountersOnGCStart() {
     469           0 :         gcMallocCounter.updateOnGCStart();
     470           0 :         jitCodeCounter.updateOnGCStart();
     471             :     }
     472           0 :     void updateAllGCMallocCountersOnGCEnd(const js::AutoLockGC& lock) {
     473           0 :         auto& gc = runtimeFromAnyThread()->gc;
     474           0 :         gcMallocCounter.updateOnGCEnd(gc.tunables, lock);
     475           0 :         jitCodeCounter.updateOnGCEnd(gc.tunables, lock);
     476           0 :     }
     477           0 :     js::gc::TriggerKind shouldTriggerGCForTooMuchMalloc() {
     478           0 :         auto& gc = runtimeFromAnyThread()->gc;
     479           0 :         return std::max(gcMallocCounter.shouldTriggerGC(gc.tunables),
     480           0 :                         jitCodeCounter.shouldTriggerGC(gc.tunables));
     481             :     }
     482             : 
     483             :     void keepAtoms() {
     484        4884 :         keepAtomsCount++;
     485             :     }
     486             :     void releaseAtoms();
     487             :     bool hasKeptAtoms() const {
     488      125563 :         return keepAtomsCount;
     489             :     }
     490             : 
     491             :   private:
     492             :     // Bitmap of atoms marked by this zone.
     493             :     js::ZoneOrGCTaskData<js::SparseBitmap> markedAtoms_;
     494             : 
     495             :     // Set of atoms recently used by this Zone. Purged on GC unless
     496             :     // keepAtomsCount is non-zero.
     497             :     js::ZoneOrGCTaskData<js::AtomSet> atomCache_;
     498             : 
     499             :     // Cache storing allocated external strings. Purged on GC.
     500             :     js::ZoneOrGCTaskData<js::ExternalStringCache> externalStringCache_;
     501             : 
     502             :     // Cache for Function.prototype.toString. Purged on GC.
     503             :     js::ZoneOrGCTaskData<js::FunctionToStringCache> functionToStringCache_;
     504             : 
     505             :     // Count of AutoKeepAtoms instances for this zone. When any instances exist,
     506             :     // atoms in the runtime will be marked from this zone's atom mark bitmap,
     507             :     // rather than when traced in the normal way. Threads parsing off the main
     508             :     // thread do not increment this value, but the presence of any such threads
     509             :     // also inhibits collection of atoms. We don't scan the stacks of exclusive
     510             :     // threads, so we need to avoid collecting their objects in another way. The
     511             :     // only GC thing pointers they have are to their exclusive compartment
     512             :     // (which is not collected) or to the atoms compartment. Therefore, we avoid
     513             :     // collecting the atoms zone when exclusive threads are running.
     514             :     js::ZoneOrGCTaskData<unsigned> keepAtomsCount;
     515             : 
     516             :     // Whether purging atoms was deferred due to keepAtoms being set. If this
     517             :     // happen then the cache will be purged when keepAtoms drops to zero.
     518             :     js::ZoneOrGCTaskData<bool> purgeAtomsDeferred;
     519             : 
     520             :   public:
     521      476641 :     js::SparseBitmap& markedAtoms() { return markedAtoms_.ref(); }
     522             : 
     523      406317 :     js::AtomSet& atomCache() { return atomCache_.ref(); }
     524             : 
     525             :     void traceAtomCache(JSTracer* trc);
     526             :     void purgeAtomCacheOrDefer();
     527             : 
     528        2396 :     js::ExternalStringCache& externalStringCache() { return externalStringCache_.ref(); };
     529             : 
     530          19 :     js::FunctionToStringCache& functionToStringCache() { return functionToStringCache_.ref(); }
     531             : 
     532             :     // Track heap usage under this Zone.
     533             :     js::gc::HeapUsage usage;
     534             : 
     535             :     // Thresholds used to trigger GC.
     536             :     js::gc::ZoneHeapThreshold threshold;
     537             : 
     538             :     // Amount of data to allocate before triggering a new incremental slice for
     539             :     // the current GC.
     540             :     js::UnprotectedData<size_t> gcDelayBytes;
     541             : 
     542             :     js::ZoneData<uint32_t> tenuredStrings;
     543             :     js::ZoneData<bool> allocNurseryStrings;
     544             : 
     545             :   private:
     546             :     // Shared Shape property tree.
     547             :     js::ZoneData<js::PropertyTree> propertyTree_;
     548             :   public:
     549      103975 :     js::PropertyTree& propertyTree() { return propertyTree_.ref(); }
     550             : 
     551             :   private:
     552             :     // Set of all unowned base shapes in the Zone.
     553             :     js::ZoneData<js::BaseShapeSet> baseShapes_;
     554             :   public:
     555       13343 :     js::BaseShapeSet& baseShapes() { return baseShapes_.ref(); }
     556             : 
     557             :   private:
     558             :     // Set of initial shapes in the Zone. For certain prototypes -- namely,
     559             :     // those of various builtin classes -- there are two entries: one for a
     560             :     // lookup via TaggedProto, and one for a lookup via JSProtoKey. See
     561             :     // InitialShapeProto.
     562             :     js::ZoneData<js::InitialShapeSet> initialShapes_;
     563             :   public:
     564       95972 :     js::InitialShapeSet& initialShapes() { return initialShapes_.ref(); }
     565             : 
     566             :   private:
     567             :     // List of shapes that may contain nursery pointers.
     568             :     using NurseryShapeVector = js::Vector<js::AccessorShape*, 0, js::SystemAllocPolicy>;
     569             :     js::ZoneData<NurseryShapeVector> nurseryShapes_;
     570             :   public:
     571        2654 :     NurseryShapeVector& nurseryShapes() { return nurseryShapes_.ref(); }
     572             : 
     573             : #ifdef JSGC_HASH_TABLE_CHECKS
     574             :     void checkInitialShapesTableAfterMovingGC();
     575             :     void checkBaseShapeTableAfterMovingGC();
     576             : #endif
     577             :     void fixupInitialShapeTable();
     578             :     void fixupAfterMovingGC();
     579             : 
     580             :     // Per-zone data for use by an embedder.
     581             :     js::ZoneData<void*> data;
     582             : 
     583             :     js::ZoneData<bool> isSystem;
     584             : 
     585             : #ifdef DEBUG
     586             :     js::ZoneData<unsigned> gcLastSweepGroupIndex;
     587             : #endif
     588             : 
     589             :     static js::HashNumber UniqueIdToHash(uint64_t uid) {
     590      288817 :         return mozilla::HashGeneric(uid);
     591             :     }
     592             : 
     593             :     // Creates a HashNumber based on getUniqueId. Returns false on OOM.
     594             :     MOZ_MUST_USE bool getHashCode(js::gc::Cell* cell, js::HashNumber* hashp) {
     595             :         uint64_t uid;
     596             :         if (!getOrCreateUniqueId(cell, &uid))
     597             :             return false;
     598             :         *hashp = UniqueIdToHash(uid);
     599             :         return true;
     600             :     }
     601             : 
     602             :     // Gets an existing UID in |uidp| if one exists.
     603      253569 :     MOZ_MUST_USE bool maybeGetUniqueId(js::gc::Cell* cell, uint64_t* uidp) {
     604      253569 :         MOZ_ASSERT(uidp);
     605      253569 :         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
     606             : 
     607             :         // Get an existing uid, if one has been set.
     608           0 :         auto p = uniqueIds().lookup(cell);
     609      253572 :         if (p)
     610           0 :             *uidp = p->value();
     611             : 
     612      253562 :         return p.found();
     613             :     }
     614             : 
     615             :     // Puts an existing UID in |uidp|, or creates a new UID for this Cell and
     616             :     // puts that into |uidp|. Returns false on OOM.
     617      621024 :     MOZ_MUST_USE bool getOrCreateUniqueId(js::gc::Cell* cell, uint64_t* uidp) {
     618           0 :         MOZ_ASSERT(uidp);
     619      621024 :         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this) || js::CurrentThreadIsPerformingGC());
     620             : 
     621             :         // Get an existing uid, if one has been set.
     622     1242166 :         auto p = uniqueIds().lookupForAdd(cell);
     623           0 :         if (p) {
     624           0 :             *uidp = p->value();
     625           1 :             return true;
     626             :         }
     627             : 
     628       11671 :         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
     629             : 
     630             :         // Set a new uid on the cell.
     631           0 :         *uidp = js::gc::NextCellUniqueId(runtimeFromAnyThread());
     632           0 :         if (!uniqueIds().add(p, cell, *uidp))
     633             :             return false;
     634             : 
     635             :         // If the cell was in the nursery, hopefully unlikely, then we need to
     636             :         // tell the nursery about it so that it can sweep the uid if the thing
     637             :         // does not get tenured.
     638           0 :         if (IsInsideNursery(cell) &&
     639           0 :             !runtimeFromMainThread()->gc.nursery().addedUniqueIdToCell(cell))
     640             :         {
     641           0 :             uniqueIds().remove(cell);
     642           0 :             return false;
     643             :         }
     644             : 
     645             :         return true;
     646             :     }
     647             : 
     648             :     js::HashNumber getHashCodeInfallible(js::gc::Cell* cell) {
     649           0 :         return UniqueIdToHash(getUniqueIdInfallible(cell));
     650             :     }
     651             : 
     652      542295 :     uint64_t getUniqueIdInfallible(js::gc::Cell* cell) {
     653             :         uint64_t uid;
     654           0 :         js::AutoEnterOOMUnsafeRegion oomUnsafe;
     655           0 :         if (!getOrCreateUniqueId(cell, &uid))
     656           0 :             oomUnsafe.crash("failed to allocate uid");
     657           0 :         return uid;
     658             :     }
     659             : 
     660             :     // Return true if this cell has a UID associated with it.
     661           0 :     MOZ_MUST_USE bool hasUniqueId(js::gc::Cell* cell) {
     662           0 :         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this) || js::CurrentThreadIsPerformingGC());
     663      617563 :         return uniqueIds().has(cell);
     664             :     }
     665             : 
     666             :     // Transfer an id from another cell. This must only be called on behalf of a
     667             :     // moving GC. This method is infallible.
     668        5292 :     void transferUniqueId(js::gc::Cell* tgt, js::gc::Cell* src) {
     669        5292 :         MOZ_ASSERT(src != tgt);
     670           0 :         MOZ_ASSERT(!IsInsideNursery(tgt));
     671        5292 :         MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtimeFromMainThread()));
     672        5292 :         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
     673           0 :         MOZ_ASSERT(!uniqueIds().has(tgt));
     674       10584 :         uniqueIds().rekeyIfMoved(src, tgt);
     675        5292 :     }
     676             : 
     677             :     // Remove any unique id associated with this Cell.
     678         149 :     void removeUniqueId(js::gc::Cell* cell) {
     679         149 :         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
     680         149 :         uniqueIds().remove(cell);
     681         149 :     }
     682             : 
     683             :     // When finished parsing off-thread, transfer any UIDs we created in the
     684             :     // off-thread zone into the target zone.
     685           0 :     void adoptUniqueIds(JS::Zone* source) {
     686           0 :         js::AutoEnterOOMUnsafeRegion oomUnsafe;
     687          44 :         for (js::gc::UniqueIdMap::Enum e(source->uniqueIds()); !e.empty(); e.popFront()) {
     688          51 :             MOZ_ASSERT(!uniqueIds().has(e.front().key()));
     689           1 :             if (!uniqueIds().put(e.front().key(), e.front().value()))
     690           0 :                 oomUnsafe.crash("failed to transfer unique ids from off-thread");
     691             :         }
     692          10 :         source->uniqueIds().clear();
     693           1 :     }
     694             : 
     695             : #ifdef JSGC_HASH_TABLE_CHECKS
     696             :     // Assert that the UniqueId table has been redirected successfully.
     697             :     void checkUniqueIdTableAfterMovingGC();
     698             : #endif
     699             : 
     700             :     bool keepShapeTables() const {
     701      200221 :         return keepShapeTables_;
     702             :     }
     703             :     void setKeepShapeTables(bool b) {
     704      400440 :         keepShapeTables_ = b;
     705             :     }
     706             : 
     707             :     // Delete an empty compartment after its contents have been merged.
     708             :     void deleteEmptyCompartment(JS::Compartment* comp);
     709             : 
     710             :     /*
     711             :      * This variation of calloc will call the large-allocation-failure callback
     712             :      * on OOM and retry the allocation.
     713             :      */
     714             :     template <typename T>
     715           8 :     T* pod_callocCanGC(size_t numElems) {
     716           8 :         T* p = pod_calloc<T>(numElems);
     717           8 :         if (MOZ_LIKELY(!!p))
     718             :             return p;
     719             :         size_t bytes;
     720           0 :         if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
     721             :             reportAllocationOverflow();
     722             :             return nullptr;
     723             :         }
     724           0 :         JSRuntime* rt = runtimeFromMainThread();
     725           0 :         p = static_cast<T*>(rt->onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes));
     726           0 :         if (!p)
     727             :             return nullptr;
     728           0 :         updateMallocCounter(bytes);
     729           0 :         return p;
     730             :     }
     731             : 
     732             :     // Non-zero if the storage underlying any typed object in this zone might
     733             :     // be detached. This is stored in Zone because IC stubs bake in a pointer
     734             :     // to this field and Baseline IC code is shared across realms within a
     735             :     // Zone. Furthermore, it's not entirely clear if this flag is ever set to
     736             :     // a non-zero value since bug 1458011.
     737             :     uint32_t detachedTypedObjects = 0;
     738             : 
     739             :   private:
     740             :     js::ZoneData<js::jit::JitZone*> jitZone_;
     741             : 
     742             :     js::MainThreadData<bool> gcScheduled_;
     743             :     js::MainThreadData<bool> gcScheduledSaved_;
     744             :     js::ZoneData<bool> gcPreserveCode_;
     745             :     js::ZoneData<bool> keepShapeTables_;
     746             : 
     747             :     // Allow zones to be linked into a list
     748             :     friend class js::gc::ZoneList;
     749             :     static Zone * const NotOnList;
     750             :     js::MainThreadOrGCTaskData<Zone*> listNext_;
     751             :     bool isOnList() const;
     752             :     Zone* nextZone() const;
     753             : 
     754             :     friend bool js::CurrentThreadCanAccessZone(Zone* zone);
     755             :     friend class js::gc::GCRuntime;
     756             : };
     757             : 
     758             : } // namespace JS
     759             : 
     760             : namespace js {
     761             : 
     762             : template <typename T>
     763             : inline T*
     764             : ZoneAllocPolicy::maybe_pod_malloc(size_t numElems)
     765             : {
     766             :     return zone->maybe_pod_malloc<T>(numElems);
     767             : }
     768             : 
     769             : template <typename T>
     770             : inline T*
     771             : ZoneAllocPolicy::maybe_pod_calloc(size_t numElems)
     772             : {
     773             :     return zone->maybe_pod_calloc<T>(numElems);
     774             : }
     775             : 
     776             : template <typename T>
     777             : inline T*
     778             : ZoneAllocPolicy::maybe_pod_realloc(T* p, size_t oldSize, size_t newSize)
     779             : {
     780             :     return zone->maybe_pod_realloc<T>(p, oldSize, newSize);
     781             : }
     782             : 
     783             : template <typename T>
     784             : inline T*
     785             : ZoneAllocPolicy::pod_malloc(size_t numElems)
     786             : {
     787             :     return zone->pod_malloc<T>(numElems);
     788             : }
     789             : 
     790             : template <typename T>
     791             : inline T*
     792             : ZoneAllocPolicy::pod_calloc(size_t numElems)
     793             : {
     794             :     return zone->pod_calloc<T>(numElems);
     795             : }
     796             : 
     797             : template <typename T>
     798             : inline T*
     799             : ZoneAllocPolicy::pod_realloc(T* p, size_t oldSize, size_t newSize)
     800             : {
     801             :     return zone->pod_realloc<T>(p, oldSize, newSize);
     802             : }
     803             : 
     804             : } // namespace js
     805             : 
     806             : #endif // gc_Zone_h

Generated by: LCOV version 1.13-14-ga5dd952