Bug Summary

File:root/firefox-clang/js/src/gc/GCRuntime.h
Warning:line 283, column 7
Excessive padding in 'class js::gc::GCRuntime' (78 padding bytes, where 6 is optimal). Optimal fields order: rt, numActiveZoneIters, lastLastDitchTime, queuePos, systemZone, sharedAtomsZone_, delayedMarkingList, markLaterArenas, helperThreadRatio, maxHelperThreads, helperThreadCount, maxMarkingThreads, markingThreadCount, maxParallelThreads, dispatchedParallelTasks, atomsUsedByUncollectedZones, createBudgetCallback, permanentAtoms, permanentWellKnownSymbols, nextCellUniqueId_, verifyPreData, lastGCStartTime_, lastGCEndTime_, initialized, minorGCNumber, majorGCNumber, number, sliceNumber, reservedMarkingThreads, markSliceCount, initialMinorGCNumber, blackDeferredMaps, grayDeferredMaps, sweepGroups, currentSweepGroup, sweepActions, sweepZone, foregroundFinalizedZone, zonesCompacted, relocatedArenasToRelease, markingValidator, defaultTimeBudgetMS_, destroyZoneCallback, destroyCompartmentCallback, destroyRealmCallback, inPageLoadCount, lastAllocRateUpdateTime, collectorTimeSinceAllocRateUpdate, lastAnimationTime_, maybeMarkStackLimit, emptyChunks_, backgroundSweepZones, zonesToMaybeCompact, gcCallback, gcDoCycleCollectionCallback, tenuredCallback, hostCleanupFinalizationRegistryCallback, grayRootTracer, stringStats, heapSize, queuedParallelTasks, weakCachesToSweep, weakCaches_, markers, rootsHash, buffersToFreeAfterMinorGC, sweepingTracer, testMarkQueue, zones_, lock, sweepingLock, delayedMarkingLock, selectedForMarking, mainThreadContext, maybeAtomsToSweep, unmarkTask, sweepTask, freeTask, decommitTask, stringBuffersToReleaseAfterMinorGC, finalizeCallbacks, updateWeakPointerZonesCallbacks, updateWeakPointerCompartmentCallbacks, nurseryCollectionCallbacks, blackRootTracers, lifoBlocksToFree, lifoBlocksToFreeAfterFullMinorGC, lifoBlocksToFreeAfterNextMinorGC, allocTask, lightLockRuntime, markTask, atomReferences, bufferRuntime_, persistentRoots_, tunables, storeBuffer_, foregroundFinalizedArenas, nursery_, stats_, schedulingState, majorGCTriggerReason, haveAllImplicitEdges_, heapState_, minEmptyChunkCount_, initialReason, sliceReason, incrementalState, initialState, sweepGroupIndex, sweepMarkResult, gcCallbackDepth, zealModeBits, zealFrequency, nextScheduled, zealSliceBudget, maybeGcOptions, delayedMarkingWorkAdded, fullGCRequested, finishMarkingDuringSweeping, incrementalGCEnabled, perZoneGCEnabled, grayBitsValid, isIncremental, isFull, isCompacting, useParallelMarking, useConcurrentMarking, useZeal, didYieldAtEndOfMarkPhase, safeToYield, markOnBackgroundThreadDuringSweeping, useBackgroundThreads, hadShutdownGC, foundUnexpectedGrayCells, requestSliceAfterBackgroundTask, sweepAllocKind, abortSweepAfterCurrentGroup, disableBarriersForSweeping, foregroundFinalizedAllocKind, startedCompacting, compactingEnabled, nurseryEnabled, parallelMarkingEnabled, rootsRemoved, fullCompartmentChecks, alwaysPreserveCode, lowMemoryState, deterministicOnly, queueMarkColor, consider reordering the fields or adding explicit padding members

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_js_src_builtin_intl1.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src/builtin/intl -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src/builtin/intl -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D WASM_SUPPORTS_HUGE_MEMORY -D JS_CACHEIR_SPEW -D JS_STRUCTURED_SPEW -D JS_HAS_CTYPES -D FFI_BUILDING -D EXPORT_JS_API -D MOZ_HAS_MOZGLUE -D MOZ_SUPPORT_LEAKCHECKING -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src -I /root/firefox-clang/js/src -I /root/firefox-clang/intl/icu_capi/bindings/cpp -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c++ Unified_cpp_js_src_builtin_intl1.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#ifndef gc_GCRuntime_h
6#define gc_GCRuntime_h
7
8#include "mozilla/Atomics.h"
9#include "mozilla/EnumSet.h"
10#include "mozilla/HashTable.h"
11#include "mozilla/Maybe.h"
12#include "mozilla/TimeStamp.h"
13
14#include "gc/ArenaList.h"
15#include "gc/AtomMarking.h"
16#include "gc/ChunkPool.h"
17#include "gc/GCContext.h"
18#include "gc/GCMarker.h"
19#include "gc/GCParallelTask.h"
20#include "gc/IteratorUtils.h"
21#include "gc/LightLock.h"
22#include "gc/Memory.h"
23#include "gc/Nursery.h"
24#include "gc/Scheduling.h"
25#include "gc/Statistics.h"
26#include "gc/StoreBuffer.h"
27#include "js/friend/CycleCollector.h"
28#include "js/friend/PerformanceHint.h"
29#include "js/GCAnnotations.h"
30#include "js/Realm.h"
31#include "js/RootingAPI.h"
32#include "js/UniquePtr.h"
33#include "js/Zone.h"
34#include "vm/AtomsTable.h"
35
36namespace js {
37
38class AutoLockGC;
39class AutoLockGCBgAlloc;
40class AutoLockHelperThreadState;
41class FinalizationRegistryObject;
42class FinalizationRecordObject;
43class FinalizationQueueObject;
44class GlobalObject;
45class VerifyPreTracer;
46class WeakRefObject;
47
48namespace gc {
49
50using BlackGrayEdgeVector = Vector<TenuredCell*, 0, SystemAllocPolicy>;
51using ZoneVector = Vector<JS::Zone*, 4, SystemAllocPolicy>;
52
53class AutoCallGCCallbacks;
54class AutoUpdateBarriersForSweeping;
55class AutoGCSession;
56class AutoHeapSession;
57class AutoLockBufferAllocator;
58class AutoTraceSession;
59class BufferAllocator;
60class MarkingValidator;
61class MaybeLockBufferAllocator;
62struct MovingTracer;
63class ParallelMarkTask;
64enum class ShouldCheckThresholds;
65class SweepGroupsIter;
66
67// Interface to a sweep action.
68struct SweepAction {
69 // The arguments passed to each action.
70 struct Args {
71 GCRuntime* gc;
72 JS::GCContext* gcx;
73 JS::SliceBudget& budget;
74 };
75
76 virtual ~SweepAction() = default;
77 virtual IncrementalProgress run(Args& state) = 0;
78 virtual void assertFinished() const = 0;
79 virtual bool shouldSkip() { return false; }
80};
81
82class BackgroundMarkTask : public GCParallelTask {
83 public:
84 explicit BackgroundMarkTask(GCRuntime* gc);
85 void initialize(bool isConcurrent, const JS::SliceBudget& budget,
86 AutoLockHelperThreadState& lock);
87 void run(AutoLockHelperThreadState& lock) override;
88 void pause();
89 void unpause();
90 bool isOverBudget() { return budget.isOverBudget(); }
91
92 private:
93 bool isConcurrent = false;
94 JS::SliceBudget budget;
95 JS::SliceBudget::InterruptRequestFlag interruptRequest;
96 friend class GCRuntime;
97};
98
99class BackgroundUnmarkTask : public GCParallelTask {
100 public:
101 explicit BackgroundUnmarkTask(GCRuntime* gc);
102 void run(AutoLockHelperThreadState& lock) override;
103
104 private:
105 void unmark();
106};
107
108class BackgroundSweepTask : public GCParallelTask {
109 public:
110 explicit BackgroundSweepTask(GCRuntime* gc);
111 void run(AutoLockHelperThreadState& lock) override;
112};
113
114class BackgroundFreeTask : public GCParallelTask {
115 public:
116 explicit BackgroundFreeTask(GCRuntime* gc);
117 void run(AutoLockHelperThreadState& lock) override;
118};
119
120// Performs extra allocation off thread so that when memory is required on the
121// main thread it will already be available and waiting.
122class BackgroundAllocTask : public GCParallelTask {
123 // Guarded by the GC lock.
124 GCLockData<ChunkPool&> chunkPool_;
125
126 const bool enabled_;
127
128 public:
129 BackgroundAllocTask(GCRuntime* gc, ChunkPool& pool);
130 bool enabled() const { return enabled_; }
131
132 void run(AutoLockHelperThreadState& lock) override;
133};
134
135// Search the provided chunks for free arenas and decommit them.
136class BackgroundDecommitTask : public GCParallelTask {
137 public:
138 explicit BackgroundDecommitTask(GCRuntime* gc);
139 void run(AutoLockHelperThreadState& lock) override;
140};
141
142template <typename F>
143struct Callback {
144 F op;
145 void* data;
146
147 Callback() : op(nullptr), data(nullptr) {}
148 Callback(F op, void* data) : op(op), data(data) {}
149};
150
151template <typename F>
152using CallbackVector = Vector<Callback<F>, 4, SystemAllocPolicy>;
153
154using RootedValueMap =
155 HashMap<Value*, const char*, DefaultHasher<Value*>, SystemAllocPolicy>;
156
157using AllocKinds = mozilla::EnumSet<AllocKind, uint64_t>;
158
159// A singly linked list of zones.
160class ZoneList {
161 static Zone* const End;
162
163 Zone* head;
164 Zone* tail;
165
166 public:
167 ZoneList();
168 ~ZoneList();
169
170 bool isEmpty() const;
171 Zone* front() const;
172
173 void prepend(Zone* zone);
174 void append(Zone* zone);
175 void prependList(ZoneList&& other);
176 void appendList(ZoneList&& other);
177 Zone* removeFront();
178 void clear();
179
180 ZoneList(const ZoneList& other) = delete;
181 ZoneList& operator=(const ZoneList& other) = delete;
182
183 private:
184 explicit ZoneList(Zone* singleZone);
185 void check() const;
186};
187
188struct WeakCacheToSweep {
189 JS::detail::WeakCacheBase* cache;
190 JS::Zone* zone;
191};
192
193class WeakCacheSweepIterator {
194 using WeakCacheBase = JS::detail::WeakCacheBase;
195
196 JS::Zone* sweepZone;
197 WeakCacheBase* sweepCache;
198
199 public:
200 explicit WeakCacheSweepIterator(JS::Zone* sweepGroup);
201
202 bool done() const;
203 WeakCacheToSweep get() const;
204 void next();
205
206 private:
207 void settle();
208};
209
210struct SweepingTracer final : public GenericTracerImpl<SweepingTracer> {
211 explicit SweepingTracer(JSRuntime* rt);
212
213 void setAllowSweepingSymbolsEarly(bool value) {
214#ifdef DEBUG1
215 allowSweepingSymbolsEarly = value;
216#endif
217 }
218
219 private:
220 template <typename T>
221 bool onEdge(T** thingp, const char* name);
222 friend class GenericTracerImpl<SweepingTracer>;
223
224#ifdef DEBUG1
225 bool allowSweepingSymbolsEarly = false;
226#endif
227};
228
229class BufferAllocatorRuntime {
230 friend class BufferAllocator;
231
232 using LargeAllocMap =
233 mozilla::HashMap<void*, LargeBuffer*, PointerHasher<void*>>;
234
235 using MaybeLock = MaybeLockBufferAllocator;
236
237 // Lock used by buffer allocators to synchronise data passed back to the main
238 // thread by background sweeping.
239 Mutex lock MOZ_UNANNOTATED;
240 friend class AutoLockBufferAllocator;
241
242 // Map from allocation pointer to buffer metadata for large buffers. Access
243 // may require holding the buffer allocator mutex if we are currently
244 // sweeping.
245 MainThreadOrGCTaskData<LargeAllocMap> largeAllocMap;
246
247 // Atomic count of:
248 // - buffer allocators whose minor state is sweeping, plus
249 // - buffer allocators whose major state is sweeping, plus
250 // - number of concurrent marking threads (zero or one)
251 // Used to decide whether the mutex is required to access |largeAllocMap|.
252 mozilla::Atomic<size_t, mozilla::ReleaseAcquire> offThreadAccessCount;
253
254 // Totals of buffer allocator used/free/admin bytes for retained chunks after
255 // the last GC (so not an up-to-date total). Used for telemetry.
256 MainThreadData<size_t> usedBytesInRetainedChunks;
257 MainThreadData<size_t> freeBytesInRetainedChunks;
258 MainThreadData<size_t> adminBytesInRetainedChunks;
259
260 public:
261 BufferAllocatorRuntime();
262
263 void checkGCStateNotInUse();
264
265 void incOffThreadCount();
266 void decOffThreadCount();
267
268 // Report/reset the used/free/admin byte totals described above.
269 void getRetainedStats(size_t* usedBytesOut, size_t* freeBytesOut,
270 size_t* adminBytesOut);
271 void resetRetainedStats();
272
273 private:
274 void addRetainedStats(size_t usedBytes, size_t freeBytes, size_t adminBytes);
275
276 bool needLockToAccessBufferMap() const;
277
278 // Lookup a large buffer by pointer in the map.
279 LargeBuffer* lookupLargeBuffer(void* alloc);
280 LargeBuffer* lookupLargeBuffer(void* alloc, MaybeLock& lock);
281};
282
283class GCRuntime {
Excessive padding in 'class js::gc::GCRuntime' (78 padding bytes, where 6 is optimal). Optimal fields order: rt, numActiveZoneIters, lastLastDitchTime, queuePos, systemZone, sharedAtomsZone_, delayedMarkingList, markLaterArenas, helperThreadRatio, maxHelperThreads, helperThreadCount, maxMarkingThreads, markingThreadCount, maxParallelThreads, dispatchedParallelTasks, atomsUsedByUncollectedZones, createBudgetCallback, permanentAtoms, permanentWellKnownSymbols, nextCellUniqueId_, verifyPreData, lastGCStartTime_, lastGCEndTime_, initialized, minorGCNumber, majorGCNumber, number, sliceNumber, reservedMarkingThreads, markSliceCount, initialMinorGCNumber, blackDeferredMaps, grayDeferredMaps, sweepGroups, currentSweepGroup, sweepActions, sweepZone, foregroundFinalizedZone, zonesCompacted, relocatedArenasToRelease, markingValidator, defaultTimeBudgetMS_, destroyZoneCallback, destroyCompartmentCallback, destroyRealmCallback, inPageLoadCount, lastAllocRateUpdateTime, collectorTimeSinceAllocRateUpdate, lastAnimationTime_, maybeMarkStackLimit, emptyChunks_, backgroundSweepZones, zonesToMaybeCompact, gcCallback, gcDoCycleCollectionCallback, tenuredCallback, hostCleanupFinalizationRegistryCallback, grayRootTracer, stringStats, heapSize, queuedParallelTasks, weakCachesToSweep, weakCaches_, markers, rootsHash, buffersToFreeAfterMinorGC, sweepingTracer, testMarkQueue, zones_, lock, sweepingLock, delayedMarkingLock, selectedForMarking, mainThreadContext, maybeAtomsToSweep, unmarkTask, sweepTask, freeTask, decommitTask, stringBuffersToReleaseAfterMinorGC, finalizeCallbacks, updateWeakPointerZonesCallbacks, updateWeakPointerCompartmentCallbacks, nurseryCollectionCallbacks, blackRootTracers, lifoBlocksToFree, lifoBlocksToFreeAfterFullMinorGC, lifoBlocksToFreeAfterNextMinorGC, allocTask, lightLockRuntime, markTask, atomReferences, bufferRuntime_, persistentRoots_, tunables, storeBuffer_, foregroundFinalizedArenas, nursery_, stats_, schedulingState, majorGCTriggerReason, haveAllImplicitEdges_, heapState_, minEmptyChunkCount_, initialReason, sliceReason, incrementalState, initialState, sweepGroupIndex, sweepMarkResult, gcCallbackDepth, zealModeBits, zealFrequency, nextScheduled, zealSliceBudget, maybeGcOptions, delayedMarkingWorkAdded, fullGCRequested, finishMarkingDuringSweeping, incrementalGCEnabled, perZoneGCEnabled, grayBitsValid, isIncremental, isFull, isCompacting, useParallelMarking, useConcurrentMarking, useZeal, didYieldAtEndOfMarkPhase, safeToYield, markOnBackgroundThreadDuringSweeping, useBackgroundThreads, hadShutdownGC, foundUnexpectedGrayCells, requestSliceAfterBackgroundTask, sweepAllocKind, abortSweepAfterCurrentGroup, disableBarriersForSweeping, foregroundFinalizedAllocKind, startedCompacting, compactingEnabled, nurseryEnabled, parallelMarkingEnabled, rootsRemoved, fullCompartmentChecks, alwaysPreserveCode, lowMemoryState, deterministicOnly, queueMarkColor, consider reordering the fields or adding explicit padding members
284 public:
285 explicit GCRuntime(JSRuntime* rt);
286 [[nodiscard]] bool init(uint32_t maxbytes);
287 bool wasInitialized() const { return initialized; }
288 void finishRoots();
289 void finish();
290
291 Zone* atomsZone() {
292 Zone* zone = zones()[0];
293 MOZ_ASSERT(JS::shadow::Zone::from(zone)->isAtomsZone())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(JS::shadow::Zone::from(zone)->isAtomsZone())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(JS::shadow::Zone::from(zone)->isAtomsZone()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("JS::shadow::Zone::from(zone)->isAtomsZone()"
, "/root/firefox-clang/js/src/gc/GCRuntime.h", 293); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "JS::shadow::Zone::from(zone)->isAtomsZone()"
")"); do { MOZ_CrashSequence(__null, 293); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
294 return zone;
295 }
296 Zone* maybeSharedAtomsZone() { return sharedAtomsZone_; }
297
298 [[nodiscard]] bool freezeSharedAtomsZone();
299 void restoreSharedAtomsZone();
300
301 JS::HeapState heapState() const { return heapState_; }
302
303 bool hasZealMode(ZealMode mode) const;
304 bool hasAnyZealModeOf(mozilla::EnumSet<ZealMode> mode) const;
305 void clearZealMode(ZealMode mode);
306 bool needZealousGC();
307 bool zealModeControlsYieldPoint() const;
308
309 using PersistentRoots =
310 mozilla::EnumeratedArray<JS::RootKind,
311 mozilla::LinkedList<js::PersistentRootedBase>,
312 size_t(JS::RootKind::Limit)>;
313 PersistentRoots& persistentRoots() { return persistentRoots_.ref(); }
314 void tracePersistentRoots(JSTracer* trc);
315 void finishPersistentRoots();
316
317 [[nodiscard]] bool addRoot(Value* vp, const char* name);
318 void removeRoot(Value* vp);
319
320 [[nodiscard]] bool setParameter(JSContext* cx, JSGCParamKey key,
321 uint32_t value);
322 void resetParameter(JSContext* cx, JSGCParamKey key);
323 uint32_t getParameter(JSGCParamKey key);
324
325 const mozilla::TimeStamp& lastAnimationTime() const {
326 return lastAnimationTime_.ref();
327 }
328 void setLastAnimationTime(const mozilla::TimeStamp& time) {
329 lastAnimationTime_ = time;
330 }
331
332 void setPerformanceHint(PerformanceHint hint);
333 bool isInPageLoad() const { return inPageLoadCount != 0; }
334
335 [[nodiscard]] bool triggerGC(JS::GCReason reason);
336 // Check whether to trigger a zone GC after allocating GC cells.
337 void maybeTriggerGCAfterAlloc(Zone* zone);
338 // Check whether to trigger a zone GC after malloc memory.
339 void maybeTriggerGCAfterMalloc(Zone* zone);
340 bool maybeTriggerGCAfterMalloc(Zone* zone, const HeapSize& heap,
341 const HeapThreshold& threshold,
342 JS::GCReason reason);
343 // The return value indicates if we were able to do the GC.
344 bool triggerZoneGC(Zone* zone, JS::GCReason reason, size_t usedBytes,
345 size_t thresholdBytes);
346
347 void maybeGC();
348
349 // Return whether we want to run a major GC. If eagerOk is true, include eager
350 // triggers (eg EAGER_ALLOC_TRIGGER) in this determination, and schedule all
351 // zones that exceed the eager thresholds.
352 JS::GCReason wantMajorGC(bool eagerOk);
353 bool checkEagerAllocTrigger(const HeapSize& size,
354 const HeapThreshold& threshold);
355
356 // Do a minor GC if requested, followed by a major GC if requested. The return
357 // value indicates whether a major GC was performed.
358 bool gcIfRequested() { return gcIfRequestedImpl(false); }
359
360 // Internal function to do a GC if previously requested. But if not and
361 // eagerOk, do an eager GC for all Zones that have exceeded the eager
362 // thresholds.
363 //
364 // Return whether a major GC was performed or started.
365 bool gcIfRequestedImpl(bool eagerOk);
366
367 void gc(JS::GCOptions options, JS::GCReason reason);
368 void startGC(JS::GCOptions options, JS::GCReason reason,
369 const JS::SliceBudget& budget);
370 void gcSlice(JS::GCReason reason, const JS::SliceBudget& budget);
371 void finishGC(JS::GCReason reason);
372 void abortGC();
373 void startDebugGC(JS::GCOptions options, const JS::SliceBudget& budget);
374 void debugGCSlice(const JS::SliceBudget& budget);
375
376 void runDebugGC();
377 void notifyRootsRemoved();
378
379 enum TraceOrMarkRuntime { TraceRuntime, MarkRuntime };
380 void traceRuntime(JSTracer* trc, AutoHeapSession& session);
381 void traceRuntimeForMinorGC(JSTracer* trc, AutoGCSession& session);
382
383 void purgeRuntimeForMinorGC();
384
385 void shrinkBuffers();
386 void onOutOfMallocMemory();
387
388 Nursery& nursery() { return nursery_.ref(); }
389 gc::StoreBuffer& storeBuffer() { return storeBuffer_.ref(); }
390
391 void minorGC(JS::GCReason reason,
392 gcstats::PhaseKind phase = gcstats::PhaseKind::MINOR_GC)
393 JS_HAZ_GC_CALL;
394 void evictNursery(JS::GCReason reason = JS::GCReason::EVICT_NURSERY) {
395 minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY);
396 }
397
398 void* addressOfNurseryPosition() {
399 return nursery_.refNoCheck().addressOfPosition();
400 }
401
402 void* addressOfNurseryAllocatedSites() {
403 return nursery_.refNoCheck().addressOfNurseryAllocatedSites();
404 }
405
406 const void* addressOfLastBufferedWholeCell() {
407 return storeBuffer_.refNoCheck().addressOfLastBufferedWholeCell();
408 }
409
410#ifdef JS_GC_ZEAL1
411 const uint32_t* addressOfZealModeBits() { return &zealModeBits.refNoCheck(); }
412 void getZealBits(uint32_t* zealBits, uint32_t* frequency,
413 uint32_t* nextScheduled);
414 void setZeal(uint8_t zeal, uint32_t frequency);
415 void unsetZeal(uint8_t zeal);
416 // Note that currently, different modes cannot have different frequencies.
417 struct ZealSetting {
418 uint8_t mode;
419 uint32_t frequency;
420 };
421 using ZealSettings = js::Vector<ZealSetting, 0, SystemAllocPolicy>;
422 bool parseZeal(const char* str, size_t len, ZealSettings* zeal,
423 bool* invalid);
424 bool parseAndSetZeal(const char* str);
425 void setNextScheduled(uint32_t count);
426 void verifyPreBarriers();
427 void maybeVerifyPreBarriers(bool always);
428 void verifyPostBarriers();
429 bool selectForMarking(JSObject* object);
430 void clearSelectedForMarking();
431 void setDeterministic(bool enable);
432 void setMarkStackLimit(size_t limit, AutoLockGC& lock);
433#endif
434
435 uint64_t nextCellUniqueId() {
436 MOZ_ASSERT(nextCellUniqueId_ > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nextCellUniqueId_ > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nextCellUniqueId_ > 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("nextCellUniqueId_ > 0"
, "/root/firefox-clang/js/src/gc/GCRuntime.h", 436); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "nextCellUniqueId_ > 0" ")"); do { MOZ_CrashSequence
(__null, 436); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
437 uint64_t uid = ++nextCellUniqueId_;
438 return uid;
439 }
440
441 void setLowMemoryState(bool newState) { lowMemoryState = newState; }
442 bool systemHasLowMemory() const { return lowMemoryState; }
443
444 public:
445 // Internal public interface
446 ZoneVector& zones() { return zones_.ref(); }
447
448 gcstats::Statistics& stats() { return stats_.ref(); }
449 const gcstats::Statistics& stats() const { return stats_.ref(); }
450
451 BufferAllocatorRuntime& bufferRuntime() { return bufferRuntime_.ref(); }
452
453 State state() const { return incrementalState; }
454 bool isHeapCompacting() const { return state() == State::Compact; }
455 bool isForegroundSweeping() const { return state() == State::Sweep; }
456 bool isBackgroundSweeping() const { return sweepTask.wasStarted(); }
457 bool isBackgroundMarking() const { return markTask.wasStarted(); }
458 bool isBackgroundDecommitting() const { return decommitTask.wasStarted(); }
459 void waitBackgroundSweepEnd();
460 void waitBackgroundDecommitEnd();
461 void waitBackgroundAllocEnd() { allocTask.cancelAndWait(); }
462 void waitBackgroundFreeEnd();
463 void waitForBackgroundTasks();
464 bool isWaitingOnBackgroundTask() const;
465 bool pauseBackgroundMarking();
466 void resumeBackgroundMarking();
467
468 void lockGC() { lock.lock(); }
469 void unlockGC() { lock.unlock(); }
470
471 void lockSweepingLock() { sweepingLock.lock(); }
472 void unlockSweepingLock() { sweepingLock.unlock(); }
473
474#ifdef DEBUG1
475 void assertCurrentThreadHasLockedGC() const {
476 lock.assertOwnedByCurrentThread();
477 }
478 void assertCurrentThreadHasLockedSweepingLock() const {
479 sweepingLock.assertOwnedByCurrentThread();
480 }
481#endif // DEBUG
482
483 void setAlwaysPreserveCode() { alwaysPreserveCode = true; }
484
485 void setIncrementalGCEnabled(bool enabled);
486 void setNurseryEnabled(bool enabled);
487
488 bool isIncrementalGCEnabled() const { return incrementalGCEnabled; }
489 bool isPerZoneGCEnabled() const { return perZoneGCEnabled; }
490 bool isCompactingGCEnabled() const;
491 bool isParallelMarkingEnabled() const { return parallelMarkingEnabled; }
492
493 bool isIncrementalGCInProgress() const {
494 return state() != State::NotActive && !isVerifyPreBarriersEnabled();
495 }
496
497 bool isConcurrentMarkingEnabled() const {
498#ifndef JS_GC_CONCURRENT_MARKING
499 return false;
500#else
501 return concurrentMarkingEnabled;
502#endif
503 }
504
505 bool hasForegroundWork() const;
506
507 bool isNormalGC() const { return gcOptions() == JS::GCOptions::Normal; }
508 bool isShrinkingGC() const { return gcOptions() == JS::GCOptions::Shrink; }
509 bool isShutdownGC() const { return gcOptions() == JS::GCOptions::Shutdown; }
510
511#ifdef DEBUG1
512 bool isShuttingDown() const { return hadShutdownGC; }
513#endif
514
515 bool initSweepActions();
516
517 void setGrayRootsTracer(JSGrayRootsTracer traceOp, void* data);
518 [[nodiscard]] bool addBlackRootsTracer(JSTraceDataOp traceOp, void* data);
519 void removeBlackRootsTracer(JSTraceDataOp traceOp, void* data);
520 void clearBlackAndGrayRootTracers();
521
522 void setGCCallback(JSGCCallback callback, void* data);
523 void callGCCallback(JSGCStatus status, JS::GCReason reason) const;
524 void setObjectsTenuredCallback(JSObjectsTenuredCallback callback, void* data);
525 void callObjectsTenuredCallback();
526 [[nodiscard]] bool addFinalizeCallback(JSFinalizeCallback callback,
527 void* data);
528 void removeFinalizeCallback(JSFinalizeCallback callback);
529 void setHostCleanupFinalizationRegistryCallback(
530 JSHostCleanupFinalizationRegistryCallback callback, void* data);
531 void callHostCleanupFinalizationRegistryCallback(JSFunction* doCleanup,
532 JSObject* incumbentGlobal);
533 [[nodiscard]] bool addWeakPointerZonesCallback(
534 JSWeakPointerZonesCallback callback, void* data);
535 void removeWeakPointerZonesCallback(JSWeakPointerZonesCallback callback);
536 [[nodiscard]] bool addWeakPointerCompartmentCallback(
537 JSWeakPointerCompartmentCallback callback, void* data);
538 void removeWeakPointerCompartmentCallback(
539 JSWeakPointerCompartmentCallback callback);
540 JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
541 bool addNurseryCollectionCallback(JS::GCNurseryCollectionCallback callback,
542 void* data);
543 void removeNurseryCollectionCallback(JS::GCNurseryCollectionCallback callback,
544 void* data);
545 JS::DoCycleCollectionCallback setDoCycleCollectionCallback(
546 JS::DoCycleCollectionCallback callback);
547 void callNurseryCollectionCallbacks(JS::GCNurseryProgress progress,
548 JS::GCReason reason);
549
550 void setDestroyZoneCallback(JSDestroyZoneCallback callback);
551 void callDestroyZoneCallback(JS::GCContext* gcx, JS::Zone* zone) const;
552 void setDestroyCompartmentCallback(JSDestroyCompartmentCallback callback);
553 void callDestroyCompartmentCallback(JS::GCContext* gcx,
554 JS::Compartment* compartment) const;
555 void setDestroyRealmCallback(JS::DestroyRealmCallback callback);
556 void callDestroyRealmCallback(JS::GCContext* gcx, JS::Realm* realm) const;
557
558 bool addFinalizationRegistry(JSContext* cx,
559 Handle<FinalizationRegistryObject*> registry);
560 bool registerWithFinalizationRegistry(
561 JSContext* cx, HandleValue target,
562 Handle<FinalizationRecordObject*> record);
563 void queueFinalizationRegistryForCleanup(FinalizationQueueObject* queue);
564
565 mozilla::LinkedList<JS::detail::WeakCacheBase>& weakCaches() {
566 return weakCaches_.ref();
567 }
568 void registerWeakCache(JS::detail::WeakCacheBase* cache) {
569 weakCaches().insertBack(cache);
570 }
571
572 void setFullCompartmentChecks(bool enable);
573
574 // Get the marking tracer used on the main thread.
575 GCMarker& marker() { return *markers[0]; }
576 const GCMarker& marker() const { return *markers[0]; }
577
578 // Get the marking tracer used for concurrent marking.
579 GCMarker& concurrentMarker() {
580 MOZ_ASSERT(isConcurrentMarkingEnabled())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isConcurrentMarkingEnabled())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isConcurrentMarkingEnabled()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"isConcurrentMarkingEnabled()", "/root/firefox-clang/js/src/gc/GCRuntime.h"
, 580); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isConcurrentMarkingEnabled()"
")"); do { MOZ_CrashSequence(__null, 580); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
581 return *markers[1];
582 }
583
584 bool haveAllImplicitEdges() const { return haveAllImplicitEdges_; }
585 void clearHaveAllImplicitEdges() { haveAllImplicitEdges_ = false; }
586
587 JS::Zone* getCurrentSweepGroup() { return currentSweepGroup; }
588 unsigned getCurrentSweepGroupIndex() {
589 MOZ_ASSERT_IF(unsigned(state()) < unsigned(State::Sweep),do { if (unsigned(state()) < unsigned(State::Sweep)) { do {
static_assert( mozilla::detail::AssertionConditionType<decltype
(sweepGroupIndex == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sweepGroupIndex == 0))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("sweepGroupIndex == 0"
, "/root/firefox-clang/js/src/gc/GCRuntime.h", 590); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "sweepGroupIndex == 0" ")"); do { MOZ_CrashSequence
(__null, 590); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false); } } while (false)
590 sweepGroupIndex == 0)do { if (unsigned(state()) < unsigned(State::Sweep)) { do {
static_assert( mozilla::detail::AssertionConditionType<decltype
(sweepGroupIndex == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sweepGroupIndex == 0))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("sweepGroupIndex == 0"
, "/root/firefox-clang/js/src/gc/GCRuntime.h", 590); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "sweepGroupIndex == 0" ")"); do { MOZ_CrashSequence
(__null, 590); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false); } } while (false)
;
591 return sweepGroupIndex;
592 }
593
594 uint64_t gcNumber() const { return number; }
595 void incGcNumber() { ++number; }
596
597 uint64_t minorGCCount() const { return minorGCNumber; }
598 void incMinorGcNumber() { ++minorGCNumber; }
599
600 uint64_t majorGCCount() const { return majorGCNumber; }
601 void incMajorGcNumber() { ++majorGCNumber; }
602
603 uint64_t gcSliceCount() const { return sliceNumber; }
604 void incGcSliceNumber() { ++sliceNumber; }
605
606 int64_t defaultSliceBudgetMS() const { return defaultTimeBudgetMS_; }
607
608 bool isIncrementalGc() const { return isIncremental; }
609 bool isFullGc() const { return isFull; }
610 bool isCompactingGc() const { return isCompacting; }
611 bool didCompactZones() const { return isCompacting && zonesCompacted; }
612
613 bool areGrayBitsValid() const { return grayBitsValid; }
614 void setGrayBitsInvalid();
615
616 mozilla::TimeStamp lastGCStartTime() const { return lastGCStartTime_; }
617 mozilla::TimeStamp lastGCEndTime() const { return lastGCEndTime_; }
618
619 bool majorGCRequested() const {
620 return majorGCTriggerReason != JS::GCReason::NO_REASON;
621 }
622
623 double computeHeapGrowthFactor(size_t lastBytes);
624 size_t computeTriggerBytes(double growthFactor, size_t lastBytes);
625
626 ChunkPool& emptyChunks(const AutoLockGC& lock) { return emptyChunks_.ref(); }
627 const ChunkPool& emptyChunks(const AutoLockGC& lock) const {
628 return emptyChunks_.ref();
629 }
630 uint32_t countEmptyChunks(const AutoLockGC& lock) const;
631 uint32_t countTotalChunks(const AutoLockGC& lock) const;
632 uint32_t minEmptyChunkCount(const AutoLockGC& lock) const {
633 return minEmptyChunkCount_;
634 }
635
636 void setCurrentChunk(JS::Zone* zone, ArenaChunk* chunk,
637 const AutoLockGC& lock);
638 void clearCurrentChunk(JS::Zone* zone, const AutoLockGC& lock);
639
640 // Call a function for each non-empty chunk across all zones. Clears the
641 // current chunk for each zone first.
642 template <typename F>
643 void forEachNonEmptyChunk(const AutoLockGC& lock, F&& func);
644
645#ifdef DEBUG1
646 void verifyAllChunks();
647#endif
648
649 // Get or allocate a free chunk, removing it from the empty chunks pool.
650 ArenaChunk* getOrAllocChunk(JS::Zone* zone, StallAndRetry stallAndRetry,
651 AutoLockGCBgAlloc& lock);
652 ArenaChunk* getOrAllocChunk(StallAndRetry stallAndRetry,
653 AutoLockGCBgAlloc& lock);
654
655 void recycleChunk(ArenaChunk* chunk, const AutoLockGC& lock);
656 ArenaChunk* pickChunk(JS::Zone* zone, StallAndRetry stallAndRetry,
657 AutoLockGCBgAlloc& lock);
658
659#ifdef JS_GC_ZEAL1
660 void startVerifyPreBarriers();
661 void endVerifyPreBarriers();
662 void finishVerifier();
663 bool isVerifyPreBarriersEnabled() const { return verifyPreData.refNoCheck(); }
664 bool shouldYieldForZeal(ZealMode mode);
665 void verifyPostBarriers(AutoHeapSession& session);
666 void checkHeapBeforeMinorGC(AutoHeapSession& session);
667#else
668 bool isVerifyPreBarriersEnabled() const { return false; }
669#endif
670
671#ifdef JSGC_HASH_TABLE_CHECKS
672 void checkHashTablesAfterMovingGC();
673#endif
674
675 // Crawl the heap to check whether an arbitary pointer is within a cell of
676 // the given kind. (TraceKind::Null means to ignore the kind.)
677 bool isPointerWithinTenuredCell(
678 void* ptr, JS::TraceKind traceKind = JS::TraceKind::Null);
679 // Crawl the heap to check whether an arbitary pointer is within a buffer.
680 bool isPointerWithinBufferAlloc(void* ptr);
681
682#ifdef DEBUG1
683 bool hasZone(Zone* target);
684#endif
685
686 // Queue memory memory to be freed on a background thread if possible.
687 void queueUnusedLifoBlocksForFree(LifoAlloc* lifo);
688 void queueAllLifoBlocksForFreeAfterMinorGC(LifoAlloc* lifo);
689 void queueBuffersForFreeAfterMinorGC(
690 Nursery::BufferSet& buffers, Nursery::StringBufferVector& stringBuffers);
691
692 // Public here for ReleaseArenaLists and FinalizeTypedArenas.
693 void releaseArena(Arena* arena, const AutoLockGC& lock);
694 void releaseArenas(Arena* arena, const AutoLockGC& lock);
695 void releaseArenaList(ArenaList& arenaList, const AutoLockGC& lock);
696
697 Arena* releaseSomeEmptyArenas(Zone* zone, Arena* emptyArenas);
698
699 // Allocator internals.
700 static void* refillFreeListInGC(Zone* zone, AllocKind thingKind);
701
702 // Deferred WeakMap marking.
703 WeakMapList& deferredMapsList(MarkColor color) {
704 return (color == MarkColor::Black ? blackDeferredMaps : grayDeferredMaps)
705 .ref();
706 }
707 const WeakMapList& deferredMapsList(MarkColor color) const {
708 return (color == MarkColor::Black ? blackDeferredMaps : grayDeferredMaps)
709 .ref();
710 }
711 bool hasAnyDeferredWeakMaps() const {
712 return !blackDeferredMaps.ref().isEmpty() ||
713 !grayDeferredMaps.ref().isEmpty();
714 }
715 bool hasDeferredWeakMaps(MarkColor color) const {
716 return !deferredMapsList(color).isEmpty();
717 }
718 void resetDeferredWeakMaps();
719
720 // Delayed marking.
721 void delayMarkingChildren(gc::Cell* cell, MarkColor color);
722 bool hasDelayedMarking() const;
723 void markAllDelayedChildren(ShouldReportMarkTime reportTime);
724
725 // If we have yielded to the mutator while foreground finalizing arenas from
726 // zone |zone| with kind |kind| then return a list of the arenas finalized so
727 // far. These will have been removed from the main arena lists at this
728 // point. Otherwise return nullptr.
729 SortedArenaList* maybeGetForegroundFinalizedArenas(Zone* zone,
730 AllocKind kind);
731
732 /*
733 * Concurrent sweep infrastructure.
734 */
735 void startTask(GCParallelTask& task, AutoLockHelperThreadState& lock);
736 void joinTask(GCParallelTask& task, AutoLockHelperThreadState& lock);
737 void updateHelperThreadCount();
738 size_t parallelWorkerCount() const;
739 void maybeRequestGCAfterBackgroundTask(const AutoLockHelperThreadState& lock);
740
741 // GC parallel task dispatch infrastructure.
742 size_t getMaxParallelThreads() const;
743 void dispatchOrQueueParallelTask(GCParallelTask* task,
744 const AutoLockHelperThreadState& lock);
745 void maybeDispatchParallelTasks(const AutoLockHelperThreadState& lock);
746 void onParallelTaskEnd(bool wasDispatched,
747 const AutoLockHelperThreadState& lock);
748
749 // Parallel and concurrent marking.
750 bool setParallelMarkingEnabled(bool enabled);
751#ifdef JS_GC_CONCURRENT_MARKING
752 bool setConcurrentMarkingEnabled(bool enabled);
753#endif
754 bool initOrDisableMultiThreadedMarking();
755 [[nodiscard]] bool resizeMarkersVector();
756 size_t markingWorkerCount() const;
757
758 // WeakRefs
759 bool registerWeakRef(JSContext* cx, HandleValue target,
760 Handle<WeakRefObject*> weakRef);
761 void traceKeptObjects(JSTracer* trc);
762
763 void maybeClearWeakRefTargets(JS::ShouldClearWeakRefTargetCallback callback,
764 void* data);
765
766 static bool isFinalizationObserverTarget(const Value& target);
767
768 bool relocateFinalizationObserverTarget(const Value& oldTarget,
769 const Value& newTarget);
770
771 static void clearWeakRefTargets(JS::Compartment* source, const Value& target);
772 static void clearWeakRefTargets(const CompartmentFilter& sourceFilter,
773 JS::Realm* targetFilter);
774
775 JS::GCReason lastStartReason() const { return initialReason; }
776
777 void updateAllocationRates();
778
779 // Allocator internals
780 static void* refillFreeList(JS::Zone* zone, AllocKind thingKind);
781 void attemptLastDitchGC();
782
783 // Return whether |sym| is present in the atom reference state for uncollected
784 // zones.
785 bool isAtomReferencedByUncollectedZone(TenuredCell* atom);
786 template <typename T>
787 void maybeMarkWeaklyHeldAtom(T* atom);
788
789 // Test mark queue.
790#ifdef DEBUG1
791 const GCVector<HeapPtr<JS::Value>, 0, SystemAllocPolicy>& getTestMarkQueue()
792 const;
793 [[nodiscard]] bool appendTestMarkQueue(const JS::Value& value);
794 void clearTestMarkQueue();
795 size_t testMarkQueuePos() const;
796 size_t testMarkQueueRemaining() const;
797#endif
798
799 private:
800 enum class IncrementalResult { Reset = 0, Abort, Ok };
801
802 bool hasBuffersForBackgroundFree() const {
803 return !lifoBlocksToFree.ref().isEmpty() ||
804 !buffersToFreeAfterMinorGC.ref().empty() ||
805 !stringBuffersToReleaseAfterMinorGC.ref().empty();
806 }
807
808 // Returns false on failure without raising an exception.
809 [[nodiscard]] bool setParameter(JSGCParamKey key, uint32_t value,
810 AutoLockGC& lock);
811 void resetParameter(JSGCParamKey key, AutoLockGC& lock);
812 uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
813 // Returns false on failure without raising an exception.
814 bool setThreadParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock);
815 void resetThreadParameter(JSGCParamKey key, AutoLockGC& lock);
816 void updateThreadDataStructures(AutoLockGC& lock);
817
818 JS::GCOptions gcOptions() const { return maybeGcOptions.ref().ref(); }
819
820 TriggerResult checkHeapThreshold(Zone* zone, const HeapSize& heapSize,
821 const HeapThreshold& heapThreshold);
822
823 void updateSchedulingStateOnGCStart();
824 void updateSchedulingStateOnGCEnd(mozilla::TimeStamp currentTime);
825 void updateAllGCStartThresholds();
826
827 // For ArenaLists::allocateFromArena()
828 friend class ArenaLists;
829 Arena* allocateArena(ArenaChunk* chunk, Zone* zone, AllocKind kind,
830 ShouldCheckThresholds checkThresholds);
831
832 /*
833 * Return the list of chunks that can be released outside the GC lock.
834 * Must be called either during the GC or with the GC lock taken.
835 */
836 friend class BackgroundDecommitTask;
837 bool tooManyEmptyChunks(const AutoLockGC& lock);
838 ChunkPool expireEmptyChunkPool(const AutoLockGC& lock);
839 void freeEmptyChunks(const AutoLockGC& lock);
840 void prepareToFreeChunk(ArenaChunkInfo& info);
841 void setMinEmptyChunkCount(uint32_t value, const AutoLockGC& lock);
842
843 friend class BackgroundAllocTask;
844 bool wantBackgroundAllocation(const AutoLockGC& lock) const;
845 void startBackgroundAllocTaskIfIdle();
846
847 void requestMajorGC(JS::GCReason reason);
848 JS::SliceBudget defaultBudget(JS::GCReason reason, int64_t millis);
849 bool maybeIncreaseSliceBudget(JS::SliceBudget& budget,
850 mozilla::TimeStamp sliceStartTime,
851 mozilla::TimeStamp gcStartTime);
852 bool maybeIncreaseSliceBudgetForLongCollections(
853 JS::SliceBudget& budget, mozilla::TimeStamp sliceStartTime,
854 mozilla::TimeStamp gcStartTime);
855 bool maybeIncreaseSliceBudgetForUrgentCollections(JS::SliceBudget& budget);
856 IncrementalResult budgetIncrementalGC(bool nonincrementalByAPI,
857 JS::GCReason reason,
858 JS::SliceBudget& budget);
859 void checkZoneIsScheduled(Zone* zone, JS::GCReason reason,
860 const char* trigger);
861 IncrementalResult resetIncrementalGC(GCAbortReason reason);
862
863 // Assert if the system state is such that we should never
864 // receive a request to do GC work.
865 void checkCanCallAPI();
866
867 // Check if the system state is such that GC has been suppressed
868 // or otherwise delayed.
869 [[nodiscard]] bool checkIfGCAllowedInCurrentState(JS::GCReason reason);
870
871 gcstats::ZoneGCStats scanZonesBeforeGC();
872
873 void setGCOptions(JS::GCOptions options);
874
875 void collect(bool nonincrementalByAPI, const JS::SliceBudget& budget,
876 JS::GCReason reason) JS_HAZ_GC_CALL;
877
878 /*
879 * Run one GC "cycle" (either a slice of incremental GC or an entire
880 * non-incremental GC).
881 *
882 * Returns:
883 * * ResetIncremental if we "reset" an existing incremental GC, which would
884 * force us to run another cycle or
885 * * Ok otherwise.
886 */
887 [[nodiscard]] IncrementalResult gcCycle(bool nonincrementalByAPI,
888 const JS::SliceBudget& budgetArg,
889 JS::GCReason reason);
890 bool shouldRepeatForDeadZone(JS::GCReason reason);
891
892 void incrementalSlice(JS::SliceBudget& budget, JS::GCReason reason,
893 bool budgetWasIncreased);
894
895 bool shouldYieldAtEndOfMarkPhase() const;
896 bool shouldYieldBeforeSweep(const JS::SliceBudget& budget) const;
897
898 void collectNurseryFromMajorGC(JS::GCReason reason);
899 void collectNursery(JS::GCOptions options, JS::GCReason reason,
900 gcstats::PhaseKind phase);
901
902 friend class AutoCallGCCallbacks;
903 void maybeCallGCCallback(JSGCStatus status, JS::GCReason reason);
904
905 void startCollection();
906
907 void purgeRuntime();
908 [[nodiscard]] bool beginPreparePhase(AutoGCSession& session);
909 bool prepareZonesForCollection(bool* isFullOut);
910 void endPreparePhase();
911 void beginMarkPhase(AutoGCSession& session);
912 bool shouldRealmPreserveJitCode(JS::Realm* realm,
913 const mozilla::TimeStamp& currentTime);
914 void setRealmPreserveJitCodeFlags(JS::Zone* zone,
915 const mozilla::TimeStamp& currentTime,
916 bool canAllocateMoreCode);
917 void clearRealmPreserveJitCodeFlags(JS::Zone* zone);
918 void maybeDiscardJitCodeForGC();
919 void startBackgroundFreeAfterMinorGC();
920 void relazifyFunctionsForShrinkingGC();
921 void purgePropMapTablesForShrinkingGC();
922 void purgeSourceURLsForShrinkingGC();
923 void purgePendingWrapperPreservationBuffersForShrinkingGC();
924 void traceRuntimeForMajorGC(JSTracer* trc, AutoGCSession& session);
925 void traceRuntimeAtoms(JSTracer* trc);
926 void traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark);
927 void traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc,
928 EdgeSelector whichEdges);
929 void traceEmbeddingBlackRoots(JSTracer* trc);
930 void traceEmbeddingGrayRoots(JSTracer* trc);
931 IncrementalProgress traceEmbeddingGrayRoots(JSTracer* trc,
932 JS::SliceBudget& budget);
933 void checkNoRuntimeRoots(AutoGCSession& session);
934 void maybeDoCycleCollection();
935 void findDeadCompartments();
936
937 std::tuple<JS::SliceBudget, JS::SliceBudget> budgetConcurrentMarking(
938 const JS::SliceBudget& requestedBudget);
939 void maybeStartConcurrentMarking(JS::SliceBudget& budget);
940 bool finishAnyConcurrentMarking(JS::SliceBudget& budget);
941 friend class BackgroundMarkTask;
942 enum ParallelMarking : bool {
943 NoParallelMarking = false,
944 AllowParallelMarking = true
945 };
946 enum ConcurrentMarking : bool {
947 NoConcurrentMarking = false,
948 AllowConcurrentMarking = true
949 };
950 IncrementalProgress markPhase(JS::SliceBudget& sliceBudget);
951 IncrementalProgress markSynchronously(
952 JS::SliceBudget& sliceBudget,
953 ParallelMarking allowParallelMarking = NoParallelMarking,
954 ShouldReportMarkTime reportTime = ReportMarkTime);
955 bool canMarkInParallel() const;
956 bool canMarkConcurrently() const;
957 bool initMultiThreadedMarkers();
958
959 bool reserveMarkingThreads(size_t count);
960 void releaseMarkingThreads();
961
962 bool hasMarkingWork() const;
963
964 void drainMarkStack();
965
966#ifdef DEBUG1
967 void assertNoMarkingWork() const;
968#else
969 void assertNoMarkingWork() const {}
970#endif
971
972 void markDelayedChildren(gc::Arena* arena, MarkColor color);
973 void processDelayedMarkingList(gc::MarkColor color);
974 void rebuildDelayedMarkingList();
975 void appendToDelayedMarkingList(gc::Arena** listTail, gc::Arena* arena);
976 void resetDelayedMarking();
977 template <typename F>
978 void forEachDelayedMarkingArena(F&& f);
979
980 template <class ZoneIterT>
981 IncrementalProgress markWeakReferences(JS::SliceBudget& budget);
982 IncrementalProgress markWeakReferencesInCurrentGroup(JS::SliceBudget& budget);
983 IncrementalProgress markGrayRoots(JS::SliceBudget& budget,
984 gcstats::PhaseKind phase);
985 void markBufferedGrayRoots(JS::Zone* zone);
986 IncrementalProgress markAllWeakReferences();
987 void markAllGrayReferences(gcstats::PhaseKind phase);
988
989 // The mark queue is a testing-only feature for controlling mark ordering and
990 // yield timing.
991 enum MarkQueueProgress {
992 QueueYielded, // End this incremental GC slice, if possible
993 QueueComplete, // Done with the queue
994 QueueSuspended // Continue the GC without ending the slice
995 };
996 MarkQueueProgress processTestMarkQueue();
997
998 // GC Sweeping. Implemented in Sweeping.cpp.
999 void beginSweepPhase(AutoGCSession& session);
1000 void dropStringWrappers();
1001 void groupZonesForSweeping();
1002 [[nodiscard]] bool findSweepGroupEdges();
1003 [[nodiscard]] bool addEdgesForMarkQueue();
1004 void moveToNextSweepGroup();
1005 void resetGrayList(Compartment* comp);
1006 IncrementalProgress beginMarkingSweepGroup(JS::GCContext* gcx,
1007 JS::SliceBudget& budget);
1008 IncrementalProgress markGrayRootsInCurrentGroup(JS::GCContext* gcx,
1009 JS::SliceBudget& budget);
1010 IncrementalProgress markGray(JS::GCContext* gcx, JS::SliceBudget& budget);
1011 IncrementalProgress endMarkingSweepGroup(JS::GCContext* gcx,
1012 JS::SliceBudget& budget);
1013 void markIncomingGrayCrossCompartmentPointers();
1014 IncrementalProgress beginSweepingSweepGroup(JS::GCContext* gcx,
1015 JS::SliceBudget& budget);
1016 void initBackgroundSweep(Zone* zone, JS::GCContext* gcx,
1017 const AllocKinds& kinds);
1018 IncrementalProgress markDuringSweeping(JS::GCContext* gcx,
1019 JS::SliceBudget& budget);
1020 void updateAtomsBitmap();
1021 void sweepCCWrappers();
1022 void sweepRealmGlobals();
1023 void sweepWasmInstances();
1024 void sweepEmbeddingWeakPointers(JS::GCContext* gcx);
1025 void sweepMisc();
1026 void sweepCompressionTasks();
1027 void sweepWeakMaps();
1028 void sweepUniqueIds();
1029 void sweepObjectsWithWeakPointers();
1030 void sweepDebuggerOnMainThread(JS::GCContext* gcx);
1031 void sweepJitDataOnMainThread(JS::GCContext* gcx);
1032 void maybeWriteCoverageAndSpew();
1033 void sweepFinalizationObserversOnMainThread();
1034 void traceWeakFinalizationObserverEdges(JSTracer* trc, Zone* zone);
1035 void sweepWeakRefs();
1036 IncrementalProgress endSweepingSweepGroup(JS::GCContext* gcx,
1037 JS::SliceBudget& budget);
1038 IncrementalProgress sweepPhase(JS::SliceBudget& sliceBudget);
1039 void startSweepingAtomsTable();
1040 IncrementalProgress sweepAtomsTable(JS::GCContext* gcx,
1041 JS::SliceBudget& budget);
1042 IncrementalProgress sweepWeakCaches(JS::GCContext* gcx,
1043 JS::SliceBudget& budget);
1044 IncrementalProgress finalizeAllocKind(JS::GCContext* gcx,
1045 JS::SliceBudget& budget);
1046 IncrementalProgress sweepPropMapTree(JS::GCContext* gcx,
1047 JS::SliceBudget& budget);
1048 void endSweepPhase(bool destroyingRuntime);
1049 void queueZonesAndStartBackgroundSweep(ZoneList&& zones);
1050 void sweepFromBackgroundThread(AutoLockHelperThreadState& lock);
1051 void startBackgroundFree();
1052 void freeFromBackgroundThread(AutoLockHelperThreadState& lock);
1053 void sweepBackgroundThings(ZoneList& zones);
1054 void disableIncrementalBarriers();
1055 void enableIncrementalBarriers();
1056 void assertBackgroundSweepingFinished();
1057#ifdef DEBUG1
1058 bool zoneInCurrentSweepGroup(Zone* zone) const;
1059#endif
1060
1061 bool allCCVisibleZonesWereCollected();
1062 void sweepZones(JS::GCContext* gcx, bool destroyingRuntime);
1063 bool shouldDecommit() const;
1064 void startDecommit();
1065 void decommitEmptyChunks(const bool& cancel, AutoLockGC& lock);
1066 void decommitFreeArenas(const bool& cancel, AutoLockGC& lock);
1067 void decommitFreeArenasWithoutUnlocking(const AutoLockGC& lock);
1068
1069 // Compacting GC. Implemented in Compacting.cpp.
1070 bool shouldCompact();
1071 void beginCompactPhase();
1072 IncrementalProgress compactPhase(JS::SliceBudget& sliceBudget,
1073 AutoGCSession& session);
1074 void endCompactPhase();
1075 void sweepZoneAfterCompacting(MovingTracer* trc, Zone* zone);
1076 bool canRelocateZone(Zone* zone) const;
1077 [[nodiscard]] bool relocateArenas(Zone* zone, Arena*& relocatedListOut,
1078 JS::SliceBudget& sliceBudget);
1079 void updateCellPointers(Zone* zone, AllocKinds kinds);
1080 void updateAllCellPointers(MovingTracer* trc, Zone* zone);
1081 void updateZonePointersToRelocatedCells(Zone* zone);
1082 void updateRuntimePointersToRelocatedCells(AutoGCSession& session);
1083 void clearRelocatedArenas(Arena* arenaList);
1084 void releaseRelocatedArenas(Arena* arenaList);
1085 void releaseRelocatedArenasWithoutUnlocking(Arena* arenaList,
1086 const AutoLockGC& lock);
1087#ifdef DEBUG1
1088 void protectOrReleaseRelocatedArenas(Arena* arenaList);
1089 void protectAndHoldArenas(Arena* arenaList);
1090 void unprotectHeldRelocatedArenas(const AutoLockGC& lock);
1091 void releaseHeldRelocatedArenas();
1092 void releaseHeldRelocatedArenasWithoutUnlocking(const AutoLockGC& lock);
1093#endif
1094
1095 bool waitForBackgroundTasksOnAllocFailure();
1096 void onOutOfMallocMemory(const AutoLockGC& lock);
1097
1098 IncrementalProgress waitForBackgroundTask(GCParallelTask& task,
1099 const JS::SliceBudget& budget,
1100 bool shouldPauseMutator);
1101
1102 void cancelRequestedGCAfterBackgroundTask();
1103 void finishCollection();
1104 void maybeStopPretenuring();
1105 void checkGCStateNotInUse();
1106 IncrementalProgress joinBackgroundMarkTask();
1107
1108#ifdef JS_GC_ZEAL1
1109 void computeNonIncrementalMarkingForValidation(AutoGCSession& session);
1110 void validateIncrementalMarking();
1111 void finishMarkingValidation();
1112#endif
1113
1114#ifdef DEBUG1
1115 void checkForCompartmentMismatches();
1116#endif
1117
1118 void callFinalizeCallbacks(JS::GCContext* gcx, JSFinalizeStatus status) const;
1119 void callWeakPointerZonesCallbacks(JSTracer* trc) const;
1120 void callWeakPointerCompartmentCallbacks(JSTracer* trc,
1121 JS::Compartment* comp) const;
1122 void callDoCycleCollectionCallback(JSContext* cx);
1123
1124 public:
1125 JSRuntime* const rt;
1126
1127 // Embedders can use this zone however they wish.
1128 MainThreadData<JS::Zone*> systemZone;
1129
1130 MainThreadData<JS::GCContext> mainThreadContext;
1131
1132 LightLockRuntime lightLockRuntime;
1133
1134 private:
1135 // For parent runtimes, a zone containing atoms that is shared by child
1136 // runtimes.
1137 MainThreadData<Zone*> sharedAtomsZone_;
1138
1139 // All zones in the runtime. The first element is always the atoms zone.
1140 MainThreadOrGCTaskData<ZoneVector> zones_;
1141
1142 // Any activity affecting the heap.
1143 MainThreadOrGCTaskData<JS::HeapState> heapState_;
1144 friend class AutoHeapSession;
1145 friend class JS::AutoEnterCycleCollection;
1146
1147 UnprotectedData<gcstats::Statistics> stats_;
1148
1149 public:
1150 js::StringStats stringStats;
1151
1152 Vector<UniquePtr<GCMarker>, 1, SystemAllocPolicy> markers;
1153
1154 // Delayed marking support in case we OOM pushing work onto the mark stack.
1155 MainThreadOrGCTaskData<js::gc::Arena*> delayedMarkingList;
1156 MainThreadOrGCTaskData<bool> delayedMarkingWorkAdded;
1157#ifdef DEBUG1
1158 /* Count of arenas that are currently in the stack. */
1159 MainThreadOrGCTaskData<size_t> markLaterArenas;
1160#endif
1161
1162 SweepingTracer sweepingTracer;
1163
1164 /* Track total GC heap size for this runtime. */
1165 HeapSize heapSize;
1166
1167 /* GC scheduling state and parameters. */
1168 GCSchedulingTunables tunables;
1169 GCSchedulingState schedulingState;
1170 MainThreadData<bool> fullGCRequested;
1171 // If an enterWeakMarking slice takes too long, suppress yielding during the
1172 // next slice.
1173 MainThreadData<bool> finishMarkingDuringSweeping;
1174
1175 // Helper thread configuration.
1176 MainThreadData<double> helperThreadRatio;
1177 MainThreadData<size_t> maxHelperThreads;
1178 MainThreadOrGCTaskData<size_t> helperThreadCount;
1179 MainThreadData<size_t> maxMarkingThreads;
1180 MainThreadData<size_t> markingThreadCount;
1181
1182 // Per-runtime helper thread task queue. Can be accessed from helper threads
1183 // in maybeDispatchParallelTasks().
1184 HelperThreadLockData<size_t> maxParallelThreads;
1185 HelperThreadLockData<size_t> dispatchedParallelTasks;
1186 HelperThreadLockData<GCParallelTaskList> queuedParallelTasks;
1187
1188 // State used for managing atom reference bitmaps in each zone.
1189 AtomRefRuntime atomReferences;
1190 MainThreadOrGCTaskData<UniquePtr<DenseBitmap>> atomsUsedByUncollectedZones;
1191
1192 /*
1193 * Pointer to a callback that, if set, will be used to create a
1194 * budget for internally-triggered GCs.
1195 */
1196 MainThreadData<JS::CreateSliceBudgetCallback> createBudgetCallback;
1197
1198#ifdef MOZ_TSAN
1199 // TSAN doesn't understand use of atomic_thread_fence to synchronize relaxed
1200 // atomics so use reads/writes to this atomic instead.
1201 mozilla::Atomic<int, mozilla::ReleaseAcquire> tsanFenceAtomic;
1202#endif
1203
1204 private:
1205 // Arenas used for permanent things created at startup and shared by child
1206 // runtimes.
1207 MainThreadData<ArenaList> permanentAtoms;
1208 MainThreadData<ArenaList> permanentWellKnownSymbols;
1209
1210 // When chunks are empty, they reside in the emptyChunks pool and are
1211 // re-used as needed or eventually expired if not re-used. The emptyChunks
1212 // pool gets refilled from the background allocation task heuristically so
1213 // that empty chunks should always be available for immediate allocation
1214 // without syscalls.
1215 GCLockData<ChunkPool> emptyChunks_;
1216
1217 friend class ArenaChunk;
1218
1219 /*
1220 * JSGC_MIN_EMPTY_CHUNK_COUNT
1221 *
1222 * Controls the number of empty chunks reserved for future allocation.
1223 *
1224 * They can be read off main thread by the background allocation task and the
1225 * background decommit task.
1226 */
1227 GCLockData<uint32_t> minEmptyChunkCount_;
1228
1229 MainThreadData<PersistentRoots> persistentRoots_;
1230 MainThreadData<RootedValueMap> rootsHash;
1231
1232 // An incrementing id used to assign unique ids to cells that require one.
1233 MainThreadData<uint64_t> nextCellUniqueId_;
1234
1235 MainThreadData<VerifyPreTracer*> verifyPreData;
1236
1237 MainThreadData<mozilla::TimeStamp> lastGCStartTime_;
1238 MainThreadData<mozilla::TimeStamp> lastGCEndTime_;
1239
1240 WriteOnceData<bool> initialized;
1241 MainThreadData<bool> incrementalGCEnabled;
1242 MainThreadData<bool> perZoneGCEnabled;
1243
1244 mozilla::Atomic<size_t, mozilla::ReleaseAcquire> numActiveZoneIters;
1245
1246 /*
1247 * The gray bits can become invalid if UnmarkGray overflows the stack. A
1248 * full GC will reset this bit, since it fills in all the gray bits.
1249 */
1250 UnprotectedData<bool> grayBitsValid;
1251
1252 mozilla::Atomic<JS::GCReason, mozilla::ReleaseAcquire> majorGCTriggerReason;
1253
1254 /* Incremented at the start of every minor GC. */
1255 MainThreadData<uint64_t> minorGCNumber;
1256
1257 /* Incremented at the start of every major GC. */
1258 MainThreadData<uint64_t> majorGCNumber;
1259
1260 /* Incremented on every GC slice or minor collection. */
1261 MainThreadData<uint64_t> number;
1262
1263 /* Incremented on every GC slice. */
1264 MainThreadData<uint64_t> sliceNumber;
1265
1266 /*
1267 * This runtime's current contribution to the global number of helper threads
1268 * 'reserved' for parallel marking. Does not affect other uses of helper
1269 * threads.
1270 */
1271 MainThreadData<size_t> reservedMarkingThreads;
1272
1273 /* Whether the currently running GC can finish in multiple slices. */
1274 MainThreadOrGCTaskData<bool> isIncremental;
1275
1276 /* Whether all zones are being collected in first GC slice. */
1277 MainThreadData<bool> isFull;
1278
1279 /* Whether the heap will be compacted at the end of GC. */
1280 MainThreadData<bool> isCompacting;
1281
1282 /* Whether to use parallel marking. */
1283 MainThreadData<ParallelMarking> useParallelMarking;
1284
1285 /* Whether to use concurrent marking. */
1286 MainThreadData<ConcurrentMarking> useConcurrentMarking;
1287
1288 /* The invocation kind of the current GC, set at the start of collection. */
1289 MainThreadOrGCTaskData<mozilla::Maybe<JS::GCOptions>> maybeGcOptions;
1290
1291 /* The initial GC reason, taken from the first slice. */
1292 MainThreadData<JS::GCReason> initialReason;
1293
1294 /* The GC reason for the current slice. */
1295 MainThreadData<JS::GCReason> sliceReason;
1296
1297 /*
1298 * The current incremental GC phase. This is also used internally in
1299 * non-incremental GC.
1300 */
1301 MainThreadOrGCTaskData<State> incrementalState;
1302
1303 /* The incremental state at the start of this slice. */
1304 MainThreadOrGCTaskData<State> initialState;
1305
1306 /* Whether to pay attention the zeal settings in this incremental slice. */
1307#ifdef JS_GC_ZEAL1
1308 MainThreadData<bool> useZeal;
1309#else
1310 const bool useZeal;
1311#endif
1312
1313 /* Indicates that we previously yielded after finishing marking work. */
1314 MainThreadData<bool> didYieldAtEndOfMarkPhase;
1315
1316 // Whether it's currently safe to yield to the mutator in an incremental GC.
1317 MainThreadData<bool> safeToYield;
1318
1319 // Whether to do any marking caused by barriers on a background thread during
1320 // an incremental sweep slice, in parallel with sweeping zones which have
1321 // finished marking.
1322 MainThreadData<bool> markOnBackgroundThreadDuringSweeping;
1323
1324 // Whether any sweeping and decommitting will run on a separate GC helper
1325 // thread.
1326 MainThreadData<bool> useBackgroundThreads;
1327
1328 MainThreadData<size_t> markSliceCount;
1329
1330 /* Whether we successfully added all edges to the implicit edges table. */
1331 mozilla::Atomic<bool, mozilla::ReleaseAcquire> haveAllImplicitEdges_{false};
1332
1333#ifdef JS_GC_CONCURRENT_MARKING
1334 MainThreadData<size_t> concurrentMarkingFinishedCount;
1335#endif
1336
1337#ifdef DEBUG1
1338 /* Shutdown has started. Further collections must be shutdown collections. */
1339 MainThreadData<bool> hadShutdownGC;
1340
1341 /* Unexpected gray cells were found after marking was finished for zone. */
1342 MainThreadData<bool> foundUnexpectedGrayCells;
1343#endif
1344
1345 /* Singly linked list of zones to be swept in the background. */
1346 HelperThreadLockData<ZoneList> backgroundSweepZones;
1347
1348 /*
1349 * Whether to trigger a GC slice after a background task is complete, so that
1350 * the collector can continue or finsish collecting. This is only used for the
1351 * tasks that run concurrently with the mutator, which are background
1352 * finalization and background decommit.
1353 */
1354 HelperThreadLockData<bool> requestSliceAfterBackgroundTask;
1355
1356 /*
1357 * Free LIFO blocks are transferred to these allocators before being freed on
1358 * a background thread.
1359 */
1360 HelperThreadLockData<LifoAlloc> lifoBlocksToFree;
1361 MainThreadData<LifoAlloc> lifoBlocksToFreeAfterFullMinorGC;
1362 MainThreadData<LifoAlloc> lifoBlocksToFreeAfterNextMinorGC;
1363 HelperThreadLockData<Nursery::BufferSet> buffersToFreeAfterMinorGC;
1364 HelperThreadLockData<Nursery::StringBufferVector>
1365 stringBuffersToReleaseAfterMinorGC;
1366
1367 /* The number of the minor GC peformed at the start of major GC. */
1368 MainThreadData<uint64_t> initialMinorGCNumber;
1369
1370 /* Index of current sweep group (for stats). */
1371 MainThreadData<unsigned> sweepGroupIndex;
1372
1373 // WeakMaps whose children have been deferred until the mark stack is empty
1374 // (everything reachable without going through a WeakMap entry has been
1375 // marked).
1376 MainThreadOrGCTaskData<WeakMapList> blackDeferredMaps;
1377 MainThreadOrGCTaskData<WeakMapList> grayDeferredMaps;
1378
1379 /*
1380 * Incremental sweep state.
1381 */
1382 MainThreadData<JS::Zone*> sweepGroups;
1383 MainThreadOrGCTaskData<JS::Zone*> currentSweepGroup;
1384 MainThreadData<UniquePtr<SweepAction>> sweepActions;
1385 MainThreadOrGCTaskData<JS::Zone*> sweepZone;
1386 MainThreadOrGCTaskData<AllocKind> sweepAllocKind;
1387 MainThreadData<mozilla::Maybe<AtomsTable::SweepIterator>> maybeAtomsToSweep;
1388 MainThreadOrGCTaskData<mozilla::Maybe<WeakCacheSweepIterator>>
1389 weakCachesToSweep;
1390 MainThreadData<bool> abortSweepAfterCurrentGroup;
1391 MainThreadOrGCTaskData<IncrementalProgress> sweepMarkResult;
1392 MainThreadData<bool> disableBarriersForSweeping;
1393 friend class AutoUpdateBarriersForSweeping;
1394
1395 /*
1396 * During incremental foreground finalization, we may have a list of arenas of
1397 * the current AllocKind and Zone whose contents have been finalized but which
1398 * have not yet been merged back into the main arena lists.
1399 */
1400 MainThreadOrGCTaskData<JS::Zone*> foregroundFinalizedZone;
1401 MainThreadOrGCTaskData<AllocKind> foregroundFinalizedAllocKind;
1402 MainThreadData<mozilla::Maybe<SortedArenaList>> foregroundFinalizedArenas;
1403
1404 friend class SweepGroupsIter;
1405
1406 /*
1407 * Incremental compacting state.
1408 */
1409 MainThreadData<bool> startedCompacting;
1410 MainThreadData<ZoneList> zonesToMaybeCompact;
1411 MainThreadData<size_t> zonesCompacted;
1412#ifdef DEBUG1
1413 GCLockData<Arena*> relocatedArenasToRelease;
1414#endif
1415
1416#ifdef JS_GC_ZEAL1
1417 MainThreadData<MarkingValidator*> markingValidator;
1418#endif
1419
1420 /*
1421 * Default budget for incremental GC slice. See js/SliceBudget.h.
1422 *
1423 * JSGC_SLICE_TIME_BUDGET_MS
1424 * pref: javascript.options.mem.gc_incremental_slice_ms,
1425 */
1426 MainThreadData<int64_t> defaultTimeBudgetMS_;
1427
1428 /*
1429 * Whether compacting GC is enabled globally.
1430 *
1431 * JSGC_COMPACTING_ENABLED
1432 * pref: javascript.options.mem.gc_compacting
1433 */
1434 MainThreadData<bool> compactingEnabled;
1435
1436 /*
1437 * Whether generational GC is enabled globally.
1438 *
1439 * JSGC_NURSERY_ENABLED
1440 * pref: javascript.options.mem.gc_generational
1441 */
1442 MainThreadData<bool> nurseryEnabled;
1443
1444 /*
1445 * Whether parallel marking is enabled globally.
1446 *
1447 * JSGC_PARALLEL_MARKING_ENABLED
1448 * pref: javascript.options.mem.gc_parallel_marking
1449 */
1450 MainThreadData<bool> parallelMarkingEnabled;
1451
1452#ifdef JS_GC_CONCURRENT_MARKING
1453 /*
1454 * Whether concurrent marking is enabled globally.
1455 *
1456 * JSGC_CONCURRENT_MARKING_ENABLED
1457 */
1458 MainThreadOrGCTaskData<bool> concurrentMarkingEnabled;
1459#endif
1460
1461 MainThreadData<bool> rootsRemoved;
1462
1463 MainThreadData<bool> fullCompartmentChecks;
1464
1465 MainThreadData<uint32_t> gcCallbackDepth;
1466
1467 MainThreadData<Callback<JSGCCallback>> gcCallback;
1468 MainThreadData<Callback<JS::DoCycleCollectionCallback>>
1469 gcDoCycleCollectionCallback;
1470 MainThreadData<Callback<JSObjectsTenuredCallback>> tenuredCallback;
1471 MainThreadData<CallbackVector<JSFinalizeCallback>> finalizeCallbacks;
1472 MainThreadOrGCTaskData<Callback<JSHostCleanupFinalizationRegistryCallback>>
1473 hostCleanupFinalizationRegistryCallback;
1474 MainThreadData<CallbackVector<JSWeakPointerZonesCallback>>
1475 updateWeakPointerZonesCallbacks;
1476 MainThreadData<CallbackVector<JSWeakPointerCompartmentCallback>>
1477 updateWeakPointerCompartmentCallbacks;
1478 MainThreadData<CallbackVector<JS::GCNurseryCollectionCallback>>
1479 nurseryCollectionCallbacks;
1480
1481 /* Zone compartment and realm destroy callbacks. */
1482 MainThreadData<JSDestroyZoneCallback> destroyZoneCallback;
1483 MainThreadData<JSDestroyCompartmentCallback> destroyCompartmentCallback;
1484 MainThreadData<JS::DestroyRealmCallback> destroyRealmCallback;
1485
1486 /*
1487 * The trace operations to trace embedding-specific GC roots. One is for
1488 * tracing through black roots and the other is for tracing through gray
1489 * roots. The black/gray distinction is only relevant to the cycle
1490 * collector.
1491 */
1492 MainThreadData<CallbackVector<JSTraceDataOp>> blackRootTracers;
1493 MainThreadOrGCTaskData<Callback<JSGrayRootsTracer>> grayRootTracer;
1494
1495 /* Always preserve JIT code during GCs, for testing. */
1496 MainThreadData<bool> alwaysPreserveCode;
1497
1498 /* Count of the number of zones that are currently in page load. */
1499 MainThreadData<size_t> inPageLoadCount;
1500
1501 MainThreadData<bool> lowMemoryState;
1502
1503 /*
1504 * General purpose GC lock, used for synchronising operations on
1505 * arenas and during parallel marking.
1506 */
1507 friend class js::AutoLockGC;
1508 friend class js::AutoLockGCBgAlloc;
1509 Mutex lock MOZ_UNANNOTATED;
1510
1511 /*
1512 * Lock used to synchronise access to resources that would normally only be
1513 * accessed on the main thread during parallel sweeping.
1514 */
1515 Mutex sweepingLock MOZ_UNANNOTATED;
1516
1517 /* Lock used to synchronise access to delayed marking state. */
1518 Mutex delayedMarkingLock MOZ_UNANNOTATED;
1519
1520 friend class BackgroundSweepTask;
1521 friend class BackgroundFreeTask;
1522
1523 BackgroundAllocTask allocTask;
1524 BackgroundUnmarkTask unmarkTask;
1525 BackgroundMarkTask markTask;
1526 BackgroundSweepTask sweepTask;
1527 BackgroundFreeTask freeTask;
1528 BackgroundDecommitTask decommitTask;
1529
1530 MainThreadData<Nursery> nursery_;
1531
1532 // The store buffer used to track tenured to nursery edges for generational
1533 // GC. This is accessed off main thread when sweeping WeakCaches.
1534 MainThreadOrGCTaskData<gc::StoreBuffer> storeBuffer_;
1535
1536 // List of non-ephemeron weak containers to sweep during
1537 // beginSweepingSweepGroup. Must come before testMarkQueue.
1538 MainThreadOrGCTaskData<mozilla::LinkedList<JS::detail::WeakCacheBase>>
1539 weakCaches_;
1540
1541 // Per-runtime buffer allocator data.
1542 MainThreadOrGCTaskData<BufferAllocatorRuntime> bufferRuntime_;
1543 friend class AutoLockBufferAllocator;
1544 friend class BufferAllocator;
1545
1546 mozilla::TimeStamp lastLastDitchTime;
1547
1548 // The last time per-zone allocation rates were updated.
1549 MainThreadData<mozilla::TimeStamp> lastAllocRateUpdateTime;
1550
1551 // Total collector time since per-zone allocation rates were last updated.
1552 MainThreadData<mozilla::TimeDuration> collectorTimeSinceAllocRateUpdate;
1553
1554 // Last time at which an animation was played for this runtime.
1555 MainThreadData<mozilla::TimeStamp> lastAnimationTime_;
1556
1557#ifdef JS_GC_ZEAL1
1558 /*
1559 * These options control the zealousness of the GC. At every allocation,
1560 * nextScheduled is decremented. When it reaches zero we do a full GC.
1561 *
1562 * At this point, if zeal_ is one of the types that trigger periodic
1563 * collection, then nextScheduled is reset to the value of zealFrequency.
1564 * Otherwise, no additional GCs take place.
1565 *
1566 * You can control these values in several ways:
1567 * - Set the JS_GC_ZEAL environment variable
1568 * - Call gczeal() or schedulegc() from inside shell-executed JS code
1569 * (see the help for details)
1570 *
1571 * See gc::ZealModeHelpText in GC.cpp for details of what the modes do.
1572 */
1573 static_assert(size_t(ZealMode::Count) <= 32,
1574 "Too many zeal modes to store in a uint32_t");
1575 MainThreadData<uint32_t> zealModeBits;
1576 MainThreadData<int> zealFrequency;
1577 MainThreadData<int> nextScheduled;
1578 MainThreadData<bool> deterministicOnly;
1579 MainThreadData<int> zealSliceBudget;
1580 MainThreadData<size_t> maybeMarkStackLimit;
1581 MainThreadData<PersistentRooted<GCVector<JSObject*, 0, SystemAllocPolicy>>>
1582 selectedForMarking;
1583#endif
1584
1585#ifdef DEBUG1
1586 /*
1587 * List of objects to mark at the beginning of a GC for testing purposes. May
1588 * also contain string directives to change mark color or wait until different
1589 * phases of the GC.
1590 *
1591 * This is a WeakCache because not everything in this list is guaranteed to
1592 * end up marked (eg if you insert an object from an already-processed sweep
1593 * group in the middle of an incremental GC). Also, the mark queue is not
1594 * used during shutdown GCs. In either case, unmarked objects may need to be
1595 * discarded.
1596 */
1597 JS::WeakCache<GCVector<HeapPtr<JS::Value>, 0, SystemAllocPolicy>>
1598 testMarkQueue;
1599
1600 /* Position within the test mark queue. */
1601 size_t queuePos = 0;
1602
1603 /* The test marking queue might want to be marking a particular color. */
1604 mozilla::Maybe<js::gc::MarkColor> queueMarkColor;
1605#endif
1606
1607 friend class MarkingValidator;
1608 friend class AutoEnterIteration;
1609};
1610
1611#ifndef JS_GC_ZEAL1
1612inline bool GCRuntime::hasZealMode(ZealMode mode) const { return false; }
1613inline void GCRuntime::clearZealMode(ZealMode mode) {}
1614inline bool GCRuntime::needZealousGC() { return false; }
1615inline bool GCRuntime::zealModeControlsYieldPoint() const { return false; }
1616#endif
1617
1618/* Prevent compartments and zones from being collected during iteration. */
1619class MOZ_RAII AutoEnterIteration {
1620 GCRuntime* gc;
1621
1622 public:
1623 explicit AutoEnterIteration(GCRuntime* gc_) : gc(gc_) {
1624 ++gc->numActiveZoneIters;
1625 }
1626
1627 ~AutoEnterIteration() {
1628 MOZ_ASSERT(gc->numActiveZoneIters)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gc->numActiveZoneIters)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gc->numActiveZoneIters)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("gc->numActiveZoneIters"
, "/root/firefox-clang/js/src/gc/GCRuntime.h", 1628); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "gc->numActiveZoneIters" ")"); do { MOZ_CrashSequence
(__null, 1628); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1629 --gc->numActiveZoneIters;
1630 }
1631};
1632
1633bool IsCurrentlyAnimating(const mozilla::TimeStamp& lastAnimationTime,
1634 const mozilla::TimeStamp& currentTime);
1635
1636} /* namespace gc */
1637} /* namespace js */
1638
1639#endif