Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/js/src/gc/GCRuntime.h
Warning:line 267, column 7
Excessive padding in 'class js::gc::GCRuntime' (82 padding bytes, where 2 is optimal). Optimal fields order: rt, numActiveZoneIters, queuePos, lastLastDitchTime, systemZone, sharedAtomsZone_, delayedMarkingList, markLaterArenas, helperThreadRatio, maxHelperThreads, helperThreadCount, maxMarkingThreads, markingThreadCount, maxParallelThreads, dispatchedParallelTasks, createBudgetCallback, nextCellUniqueId_, verifyPreData, lastGCStartTime_, lastGCEndTime_, initialized, minorGCNumber, majorGCNumber, number, sliceNumber, reservedMarkingThreads, sweepGroups, currentSweepGroup, sweepActions, sweepZone, foregroundFinalizedZone, zonesCompacted, relocatedArenasToRelease, markingValidator, defaultTimeBudgetMS_, maybeMarkStackLimit, inPageLoadCount, lastAllocRateUpdateTime, collectorTimeSinceAllocRateUpdate, permanentAtoms, permanentWellKnownSymbols, emptyChunks_, availableChunks_, fullChunks_, backgroundSweepZones, zonesToMaybeCompact, gcCallback, gcDoCycleCollectionCallback, tenuredCallback, hostCleanupFinalizationRegistryCallback, grayRootTracer, stringStats, heapSize, queuedParallelTasks, weakCachesToSweep, markers, sweepingTracer, rootsHash, buffersToFreeAfterMinorGC, cellsToAssertNotGray, atomMarking, testMarkQueue, mainThreadContext, zones_, selectedForMarking, lock, storeBufferLock, delayedMarkingLock, sweepTask, freeTask, decommitTask, maybeAtomsToSweep, lifoBlocksToFree, lifoBlocksToFreeAfterFullMinorGC, lifoBlocksToFreeAfterNextMinorGC, finalizeCallbacks, updateWeakPointerZonesCallbacks, updateWeakPointerCompartmentCallbacks, nurseryCollectionCallbacks, blackRootTracers, allocTask, markTask, unmarkTask, tunables, storeBuffer_, foregroundFinalizedArenas, nursery_, stats_, schedulingState, numArenasFreeCommitted, majorGCTriggerReason, heapState_, minEmptyChunkCount_, maxEmptyChunkCount_, initialReason, incrementalState, initialState, sweepGroupIndex, sweepMarkResult, zealModeBits, zealFrequency, nextScheduled, zealSliceBudget, gcCallbackDepth, maybeGcOptions, delayedMarkingWorkAdded, fullGCRequested, incrementalGCEnabled, perZoneGCEnabled, cleanUpEverything, grayBitsValid, isIncremental, isFull, isCompacting, useParallelMarking, useZeal, lastMarkSlice, safeToYield, markOnBackgroundThreadDuringSweeping, useBackgroundThreads, haveDiscardedJITCodeThisSlice, hadShutdownGC, requestSliceAfterBackgroundTask, sweepAllocKind, abortSweepAfterCurrentGroup, foregroundFinalizedAllocKind, queueMarkColor, startedCompacting, incrementalAllowed, compactingEnabled, parallelMarkingEnabled, rootsRemoved, deterministicOnly, fullCompartmentChecks, alwaysPreserveCode, lowMemoryState, 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 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Utility.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=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/util -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/util -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/js-confdefs.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/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 -I /var/lib/jenkins/workspace/firefox-scan-build/js/src/util -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/util -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src -I /var/lib/jenkins/workspace/firefox-scan-build/js/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -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-deprecated-this-capture -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 -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-16-034744-15991-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/js/src/util/Utility.cpp
1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#ifndef gc_GCRuntime_h
8#define gc_GCRuntime_h
9
10#include "mozilla/Atomics.h"
11#include "mozilla/DoublyLinkedList.h"
12#include "mozilla/EnumSet.h"
13#include "mozilla/Maybe.h"
14#include "mozilla/TimeStamp.h"
15
16#include "gc/ArenaList.h"
17#include "gc/AtomMarking.h"
18#include "gc/GCContext.h"
19#include "gc/GCMarker.h"
20#include "gc/GCParallelTask.h"
21#include "gc/IteratorUtils.h"
22#include "gc/Nursery.h"
23#include "gc/Scheduling.h"
24#include "gc/Statistics.h"
25#include "gc/StoreBuffer.h"
26#include "gc/SweepingAPI.h"
27#include "js/friend/PerformanceHint.h"
28#include "js/GCAnnotations.h"
29#include "js/UniquePtr.h"
30#include "vm/AtomsTable.h"
31
32namespace js {
33
34class AutoLockGC;
35class AutoLockGCBgAlloc;
36class AutoLockHelperThreadState;
37class FinalizationRegistryObject;
38class FinalizationRecordObject;
39class FinalizationQueueObject;
40class GlobalObject;
41class VerifyPreTracer;
42class WeakRefObject;
43
44namespace gc {
45
46using BlackGrayEdgeVector = Vector<TenuredCell*, 0, SystemAllocPolicy>;
47using ZoneVector = Vector<JS::Zone*, 4, SystemAllocPolicy>;
48
49class AutoCallGCCallbacks;
50class AutoGCSession;
51class AutoHeapSession;
52class AutoTraceSession;
53struct FinalizePhase;
54class MarkingValidator;
55struct MovingTracer;
56class ParallelMarkTask;
57enum class ShouldCheckThresholds;
58class SweepGroupsIter;
59
60// Interface to a sweep action.
61struct SweepAction {
62 // The arguments passed to each action.
63 struct Args {
64 GCRuntime* gc;
65 JS::GCContext* gcx;
66 SliceBudget& budget;
67 };
68
69 virtual ~SweepAction() = default;
70 virtual IncrementalProgress run(Args& state) = 0;
71 virtual void assertFinished() const = 0;
72 virtual bool shouldSkip() { return false; }
73};
74
75class ChunkPool {
76 TenuredChunk* head_;
77 size_t count_;
78
79 public:
80 ChunkPool() : head_(nullptr), count_(0) {}
81 ChunkPool(const ChunkPool& other) = delete;
82 ChunkPool(ChunkPool&& other) { *this = std::move(other); }
83
84 ~ChunkPool() {
85 MOZ_ASSERT(!head_)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!head_)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!head_))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!head_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/gc/GCRuntime.h"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!head_" ")");
do { *((volatile int*)__null) = 85; __attribute__((nomerge))
::abort(); } while (false); } } while (false)
;
86 MOZ_ASSERT(count_ == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(count_ == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(count_ == 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("count_ == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/gc/GCRuntime.h"
, 86); AnnotateMozCrashReason("MOZ_ASSERT" "(" "count_ == 0" ")"
); do { *((volatile int*)__null) = 86; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
87 }
88
89 ChunkPool& operator=(const ChunkPool& other) = delete;
90 ChunkPool& operator=(ChunkPool&& other) {
91 head_ = other.head_;
92 other.head_ = nullptr;
93 count_ = other.count_;
94 other.count_ = 0;
95 return *this;
96 }
97
98 bool empty() const { return !head_; }
99 size_t count() const { return count_; }
100
101 TenuredChunk* head() {
102 MOZ_ASSERT(head_)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(head_)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(head_))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("head_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/gc/GCRuntime.h"
, 102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "head_" ")");
do { *((volatile int*)__null) = 102; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
103 return head_;
104 }
105 TenuredChunk* pop();
106 void push(TenuredChunk* chunk);
107 TenuredChunk* remove(TenuredChunk* chunk);
108
109 void sort();
110
111 private:
112 TenuredChunk* mergeSort(TenuredChunk* list, size_t count);
113 bool isSorted() const;
114
115#ifdef DEBUG1
116 public:
117 bool contains(TenuredChunk* chunk) const;
118 bool verify() const;
119 void verifyChunks() const;
120#endif
121
122 public:
123 // Pool mutation does not invalidate an Iter unless the mutation
124 // is of the TenuredChunk currently being visited by the Iter.
125 class Iter {
126 public:
127 explicit Iter(ChunkPool& pool) : current_(pool.head_) {}
128 bool done() const { return !current_; }
129 void next();
130 TenuredChunk* get() const { return current_; }
131 operator TenuredChunk*() const { return get(); }
132 TenuredChunk* operator->() const { return get(); }
133
134 private:
135 TenuredChunk* current_;
136 };
137};
138
139class BackgroundMarkTask : public GCParallelTask {
140 public:
141 explicit BackgroundMarkTask(GCRuntime* gc);
142 void setBudget(const SliceBudget& budget) { this->budget = budget; }
143 void run(AutoLockHelperThreadState& lock) override;
144
145 private:
146 SliceBudget budget;
147};
148
149class BackgroundUnmarkTask : public GCParallelTask {
150 public:
151 explicit BackgroundUnmarkTask(GCRuntime* gc);
152 void initZones();
153 void run(AutoLockHelperThreadState& lock) override;
154
155 ZoneVector zones;
156};
157
158class BackgroundSweepTask : public GCParallelTask {
159 public:
160 explicit BackgroundSweepTask(GCRuntime* gc);
161 void run(AutoLockHelperThreadState& lock) override;
162};
163
164class BackgroundFreeTask : public GCParallelTask {
165 public:
166 explicit BackgroundFreeTask(GCRuntime* gc);
167 void run(AutoLockHelperThreadState& lock) override;
168};
169
170// Performs extra allocation off thread so that when memory is required on the
171// main thread it will already be available and waiting.
172class BackgroundAllocTask : public GCParallelTask {
173 // Guarded by the GC lock.
174 GCLockData<ChunkPool&> chunkPool_;
175
176 const bool enabled_;
177
178 public:
179 BackgroundAllocTask(GCRuntime* gc, ChunkPool& pool);
180 bool enabled() const { return enabled_; }
181
182 void run(AutoLockHelperThreadState& lock) override;
183};
184
185// Search the provided chunks for free arenas and decommit them.
186class BackgroundDecommitTask : public GCParallelTask {
187 public:
188 explicit BackgroundDecommitTask(GCRuntime* gc);
189 void run(AutoLockHelperThreadState& lock) override;
190};
191
192template <typename F>
193struct Callback {
194 F op;
195 void* data;
196
197 Callback() : op(nullptr), data(nullptr) {}
198 Callback(F op, void* data) : op(op), data(data) {}
199};
200
201template <typename F>
202using CallbackVector = Vector<Callback<F>, 4, SystemAllocPolicy>;
203
204using RootedValueMap =
205 HashMap<Value*, const char*, DefaultHasher<Value*>, SystemAllocPolicy>;
206
207using AllocKinds = mozilla::EnumSet<AllocKind, uint64_t>;
208
209// A singly linked list of zones.
210class ZoneList {
211 static Zone* const End;
212
213 Zone* head;
214 Zone* tail;
215
216 public:
217 ZoneList();
218 ~ZoneList();
219
220 bool isEmpty() const;
221 Zone* front() const;
222
223 void prepend(Zone* zone);
224 void append(Zone* zone);
225 void prependList(ZoneList&& other);
226 void appendList(ZoneList&& other);
227 Zone* removeFront();
228 void clear();
229
230 private:
231 explicit ZoneList(Zone* singleZone);
232 void check() const;
233
234 ZoneList(const ZoneList& other) = delete;
235 ZoneList& operator=(const ZoneList& other) = delete;
236};
237
238struct WeakCacheToSweep {
239 WeakCacheBase* cache;
240 JS::Zone* zone;
241};
242
243class WeakCacheSweepIterator {
244 JS::Zone* sweepZone;
245 WeakCacheBase* sweepCache;
246
247 public:
248 explicit WeakCacheSweepIterator(JS::Zone* sweepGroup);
249
250 bool done() const;
251 WeakCacheToSweep get() const;
252 void next();
253
254 private:
255 void settle();
256};
257
258struct SweepingTracer final : public GenericTracerImpl<SweepingTracer> {
259 explicit SweepingTracer(JSRuntime* rt);
260
261 private:
262 template <typename T>
263 void onEdge(T** thingp, const char* name);
264 friend class GenericTracerImpl<SweepingTracer>;
265};
266
267class GCRuntime {
Excessive padding in 'class js::gc::GCRuntime' (82 padding bytes, where 2 is optimal). Optimal fields order: rt, numActiveZoneIters, queuePos, lastLastDitchTime, systemZone, sharedAtomsZone_, delayedMarkingList, markLaterArenas, helperThreadRatio, maxHelperThreads, helperThreadCount, maxMarkingThreads, markingThreadCount, maxParallelThreads, dispatchedParallelTasks, createBudgetCallback, nextCellUniqueId_, verifyPreData, lastGCStartTime_, lastGCEndTime_, initialized, minorGCNumber, majorGCNumber, number, sliceNumber, reservedMarkingThreads, sweepGroups, currentSweepGroup, sweepActions, sweepZone, foregroundFinalizedZone, zonesCompacted, relocatedArenasToRelease, markingValidator, defaultTimeBudgetMS_, maybeMarkStackLimit, inPageLoadCount, lastAllocRateUpdateTime, collectorTimeSinceAllocRateUpdate, permanentAtoms, permanentWellKnownSymbols, emptyChunks_, availableChunks_, fullChunks_, backgroundSweepZones, zonesToMaybeCompact, gcCallback, gcDoCycleCollectionCallback, tenuredCallback, hostCleanupFinalizationRegistryCallback, grayRootTracer, stringStats, heapSize, queuedParallelTasks, weakCachesToSweep, markers, sweepingTracer, rootsHash, buffersToFreeAfterMinorGC, cellsToAssertNotGray, atomMarking, testMarkQueue, mainThreadContext, zones_, selectedForMarking, lock, storeBufferLock, delayedMarkingLock, sweepTask, freeTask, decommitTask, maybeAtomsToSweep, lifoBlocksToFree, lifoBlocksToFreeAfterFullMinorGC, lifoBlocksToFreeAfterNextMinorGC, finalizeCallbacks, updateWeakPointerZonesCallbacks, updateWeakPointerCompartmentCallbacks, nurseryCollectionCallbacks, blackRootTracers, allocTask, markTask, unmarkTask, tunables, storeBuffer_, foregroundFinalizedArenas, nursery_, stats_, schedulingState, numArenasFreeCommitted, majorGCTriggerReason, heapState_, minEmptyChunkCount_, maxEmptyChunkCount_, initialReason, incrementalState, initialState, sweepGroupIndex, sweepMarkResult, zealModeBits, zealFrequency, nextScheduled, zealSliceBudget, gcCallbackDepth, maybeGcOptions, delayedMarkingWorkAdded, fullGCRequested, incrementalGCEnabled, perZoneGCEnabled, cleanUpEverything, grayBitsValid, isIncremental, isFull, isCompacting, useParallelMarking, useZeal, lastMarkSlice, safeToYield, markOnBackgroundThreadDuringSweeping, useBackgroundThreads, haveDiscardedJITCodeThisSlice, hadShutdownGC, requestSliceAfterBackgroundTask, sweepAllocKind, abortSweepAfterCurrentGroup, foregroundFinalizedAllocKind, queueMarkColor, startedCompacting, incrementalAllowed, compactingEnabled, parallelMarkingEnabled, rootsRemoved, deterministicOnly, fullCompartmentChecks, alwaysPreserveCode, lowMemoryState, consider reordering the fields or adding explicit padding members
268 public:
269 explicit GCRuntime(JSRuntime* rt);
270 [[nodiscard]] bool init(uint32_t maxbytes);
271 bool wasInitialized() const { return initialized; }
272 void finishRoots();
273 void finish();
274
275 Zone* atomsZone() {
276 Zone* zone = zones()[0];
277 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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/gc/GCRuntime.h"
, 277); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JS::shadow::Zone::from(zone)->isAtomsZone()"
")"); do { *((volatile int*)__null) = 277; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
278 return zone;
279 }
280 Zone* maybeSharedAtomsZone() { return sharedAtomsZone_; }
281
282 [[nodiscard]] bool freezeSharedAtomsZone();
283 void restoreSharedAtomsZone();
284
285 JS::HeapState heapState() const { return heapState_; }
286
287 inline bool hasZealMode(ZealMode mode);
288 inline void clearZealMode(ZealMode mode);
289 inline bool needZealousGC();
290 inline bool hasIncrementalTwoSliceZealMode();
291
292 [[nodiscard]] bool addRoot(Value* vp, const char* name);
293 void removeRoot(Value* vp);
294
295 [[nodiscard]] bool setParameter(JSContext* cx, JSGCParamKey key,
296 uint32_t value);
297 void resetParameter(JSContext* cx, JSGCParamKey key);
298 uint32_t getParameter(JSGCParamKey key);
299
300 void setPerformanceHint(PerformanceHint hint);
301 bool isInPageLoad() const { return inPageLoadCount != 0; }
302
303 [[nodiscard]] bool triggerGC(JS::GCReason reason);
304 // Check whether to trigger a zone GC after allocating GC cells.
305 void maybeTriggerGCAfterAlloc(Zone* zone);
306 // Check whether to trigger a zone GC after malloc memory.
307 void maybeTriggerGCAfterMalloc(Zone* zone);
308 bool maybeTriggerGCAfterMalloc(Zone* zone, const HeapSize& heap,
309 const HeapThreshold& threshold,
310 JS::GCReason reason);
311 // The return value indicates if we were able to do the GC.
312 bool triggerZoneGC(Zone* zone, JS::GCReason reason, size_t usedBytes,
313 size_t thresholdBytes);
314
315 void maybeGC();
316
317 // Return whether we want to run a major GC. If eagerOk is true, include eager
318 // triggers (eg EAGER_ALLOC_TRIGGER) in this determination, and schedule all
319 // zones that exceed the eager thresholds.
320 JS::GCReason wantMajorGC(bool eagerOk);
321 bool checkEagerAllocTrigger(const HeapSize& size,
322 const HeapThreshold& threshold);
323
324 // Do a minor GC if requested, followed by a major GC if requested. The return
325 // value indicates whether a major GC was performed.
326 bool gcIfRequested() { return gcIfRequestedImpl(false); }
327
328 // Internal function to do a GC if previously requested. But if not and
329 // eagerOk, do an eager GC for all Zones that have exceeded the eager
330 // thresholds.
331 //
332 // Return whether a major GC was performed or started.
333 bool gcIfRequestedImpl(bool eagerOk);
334
335 void gc(JS::GCOptions options, JS::GCReason reason);
336 void startGC(JS::GCOptions options, JS::GCReason reason,
337 const SliceBudget& budget);
338 void gcSlice(JS::GCReason reason, const SliceBudget& budget);
339 void finishGC(JS::GCReason reason);
340 void abortGC();
341 void startDebugGC(JS::GCOptions options, const SliceBudget& budget);
342 void debugGCSlice(const SliceBudget& budget);
343
344 void runDebugGC();
345 void notifyRootsRemoved();
346
347 enum TraceOrMarkRuntime { TraceRuntime, MarkRuntime };
348 void traceRuntime(JSTracer* trc, AutoTraceSession& session);
349 void traceRuntimeForMinorGC(JSTracer* trc, AutoGCSession& session);
350
351 void purgeRuntimeForMinorGC();
352
353 void shrinkBuffers();
354 void onOutOfMallocMemory();
355 void onOutOfMallocMemory(const AutoLockGC& lock);
356
357 Nursery& nursery() { return nursery_.ref(); }
358 gc::StoreBuffer& storeBuffer() { return storeBuffer_.ref(); }
359
360 void minorGC(JS::GCReason reason,
361 gcstats::PhaseKind phase = gcstats::PhaseKind::MINOR_GC)
362 JS_HAZ_GC_CALL;
363 void evictNursery(JS::GCReason reason = JS::GCReason::EVICT_NURSERY) {
364 minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY);
365 }
366
367 void* addressOfNurseryPosition() {
368 return nursery_.refNoCheck().addressOfPosition();
369 }
370
371 const void* addressOfLastBufferedWholeCell() {
372 return storeBuffer_.refNoCheck().addressOfLastBufferedWholeCell();
373 }
374
375#ifdef JS_GC_ZEAL1
376 const uint32_t* addressOfZealModeBits() { return &zealModeBits.refNoCheck(); }
377 void getZealBits(uint32_t* zealBits, uint32_t* frequency,
378 uint32_t* nextScheduled);
379 void setZeal(uint8_t zeal, uint32_t frequency);
380 void unsetZeal(uint8_t zeal);
381 bool parseAndSetZeal(const char* str);
382 void setNextScheduled(uint32_t count);
383 void verifyPreBarriers();
384 void maybeVerifyPreBarriers(bool always);
385 bool selectForMarking(JSObject* object);
386 void clearSelectedForMarking();
387 void setDeterministic(bool enable);
388 void setMarkStackLimit(size_t limit, AutoLockGC& lock);
389#endif
390
391 uint64_t nextCellUniqueId() {
392 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"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/gc/GCRuntime.h"
, 392); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nextCellUniqueId_ > 0"
")"); do { *((volatile int*)__null) = 392; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
393 uint64_t uid = ++nextCellUniqueId_;
394 return uid;
395 }
396
397 void setLowMemoryState(bool newState) { lowMemoryState = newState; }
398 bool systemHasLowMemory() const { return lowMemoryState; }
399
400 public:
401 // Internal public interface
402 ZoneVector& zones() { return zones_.ref(); }
403 gcstats::Statistics& stats() { return stats_.ref(); }
404 const gcstats::Statistics& stats() const { return stats_.ref(); }
405 State state() const { return incrementalState; }
406 bool isHeapCompacting() const { return state() == State::Compact; }
407 bool isForegroundSweeping() const { return state() == State::Sweep; }
408 bool isBackgroundSweeping() const { return sweepTask.wasStarted(); }
409 bool isBackgroundMarking() const { return markTask.wasStarted(); }
410 void waitBackgroundSweepEnd();
411 void waitBackgroundAllocEnd() { allocTask.cancelAndWait(); }
412 void waitBackgroundFreeEnd();
413 void waitForBackgroundTasks();
414 bool isWaitingOnBackgroundTask() const;
415
416 void lockGC() { lock.lock(); }
417 void unlockGC() { lock.unlock(); }
418
419 void lockStoreBuffer() { storeBufferLock.lock(); }
420 void unlockStoreBuffer() { storeBufferLock.unlock(); }
421
422#ifdef DEBUG1
423 void assertCurrentThreadHasLockedGC() const {
424 lock.assertOwnedByCurrentThread();
425 }
426 void assertCurrentThreadHasLockedStoreBuffer() const {
427 storeBufferLock.assertOwnedByCurrentThread();
428 }
429#endif // DEBUG
430
431 void setAlwaysPreserveCode() { alwaysPreserveCode = true; }
432
433 bool isIncrementalGCAllowed() const { return incrementalAllowed; }
434 void disallowIncrementalGC() { incrementalAllowed = false; }
435
436 void setIncrementalGCEnabled(bool enabled);
437
438 bool isIncrementalGCEnabled() const { return incrementalGCEnabled; }
439 bool isPerZoneGCEnabled() const { return perZoneGCEnabled; }
440 bool isCompactingGCEnabled() const;
441 bool isParallelMarkingEnabled() const { return parallelMarkingEnabled; }
442
443 bool isIncrementalGCInProgress() const {
444 return state() != State::NotActive && !isVerifyPreBarriersEnabled();
445 }
446
447 bool hasForegroundWork() const;
448
449 bool isShrinkingGC() const { return gcOptions() == JS::GCOptions::Shrink; }
450
451 bool isShutdownGC() const { return gcOptions() == JS::GCOptions::Shutdown; }
452
453#ifdef DEBUG1
454 bool isShuttingDown() const { return hadShutdownGC; }
455#endif
456
457 bool initSweepActions();
458
459 void setGrayRootsTracer(JSGrayRootsTracer traceOp, void* data);
460 [[nodiscard]] bool addBlackRootsTracer(JSTraceDataOp traceOp, void* data);
461 void removeBlackRootsTracer(JSTraceDataOp traceOp, void* data);
462 void clearBlackAndGrayRootTracers();
463
464 void setGCCallback(JSGCCallback callback, void* data);
465 void callGCCallback(JSGCStatus status, JS::GCReason reason) const;
466 void setObjectsTenuredCallback(JSObjectsTenuredCallback callback, void* data);
467 void callObjectsTenuredCallback();
468 [[nodiscard]] bool addFinalizeCallback(JSFinalizeCallback callback,
469 void* data);
470 void removeFinalizeCallback(JSFinalizeCallback callback);
471 void setHostCleanupFinalizationRegistryCallback(
472 JSHostCleanupFinalizationRegistryCallback callback, void* data);
473 void callHostCleanupFinalizationRegistryCallback(
474 JSFunction* doCleanup, GlobalObject* incumbentGlobal);
475 [[nodiscard]] bool addWeakPointerZonesCallback(
476 JSWeakPointerZonesCallback callback, void* data);
477 void removeWeakPointerZonesCallback(JSWeakPointerZonesCallback callback);
478 [[nodiscard]] bool addWeakPointerCompartmentCallback(
479 JSWeakPointerCompartmentCallback callback, void* data);
480 void removeWeakPointerCompartmentCallback(
481 JSWeakPointerCompartmentCallback callback);
482 JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
483 bool addNurseryCollectionCallback(JS::GCNurseryCollectionCallback callback,
484 void* data);
485 void removeNurseryCollectionCallback(JS::GCNurseryCollectionCallback callback,
486 void* data);
487 JS::DoCycleCollectionCallback setDoCycleCollectionCallback(
488 JS::DoCycleCollectionCallback callback);
489 void callNurseryCollectionCallbacks(JS::GCNurseryProgress progress,
490 JS::GCReason reason);
491
492 bool addFinalizationRegistry(JSContext* cx,
493 Handle<FinalizationRegistryObject*> registry);
494 bool registerWithFinalizationRegistry(JSContext* cx, HandleObject target,
495 HandleObject record);
496 void queueFinalizationRegistryForCleanup(FinalizationQueueObject* queue);
497
498 void nukeFinalizationRecordWrapper(JSObject* wrapper,
499 FinalizationRecordObject* record);
500 void nukeWeakRefWrapper(JSObject* wrapper, WeakRefObject* weakRef);
501
502 void setFullCompartmentChecks(bool enable);
503
504 // Get the main marking tracer.
505 GCMarker& marker() { return *markers[0]; }
506
507 JS::Zone* getCurrentSweepGroup() { return currentSweepGroup; }
508 unsigned getCurrentSweepGroupIndex() {
509 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"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/gc/GCRuntime.h"
, 510); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sweepGroupIndex == 0"
")"); do { *((volatile int*)__null) = 510; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
510 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"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/gc/GCRuntime.h"
, 510); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sweepGroupIndex == 0"
")"); do { *((volatile int*)__null) = 510; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
511 return sweepGroupIndex;
512 }
513
514 uint64_t gcNumber() const { return number; }
515 void incGcNumber() { ++number; }
516
517 uint64_t minorGCCount() const { return minorGCNumber; }
518 void incMinorGcNumber() { ++minorGCNumber; }
519
520 uint64_t majorGCCount() const { return majorGCNumber; }
521 void incMajorGcNumber() { ++majorGCNumber; }
522
523 uint64_t gcSliceCount() const { return sliceNumber; }
524 void incGcSliceNumber() { ++sliceNumber; }
525
526 int64_t defaultSliceBudgetMS() const { return defaultTimeBudgetMS_; }
527
528 bool isIncrementalGc() const { return isIncremental; }
529 bool isFullGc() const { return isFull; }
530 bool isCompactingGc() const { return isCompacting; }
531 bool didCompactZones() const { return isCompacting && zonesCompacted; }
532
533 bool areGrayBitsValid() const { return grayBitsValid; }
534 void setGrayBitsInvalid() { grayBitsValid = false; }
535
536 mozilla::TimeStamp lastGCStartTime() const { return lastGCStartTime_; }
537 mozilla::TimeStamp lastGCEndTime() const { return lastGCEndTime_; }
538
539 bool majorGCRequested() const {
540 return majorGCTriggerReason != JS::GCReason::NO_REASON;
541 }
542
543 double computeHeapGrowthFactor(size_t lastBytes);
544 size_t computeTriggerBytes(double growthFactor, size_t lastBytes);
545
546 inline void updateOnFreeArenaAlloc(const TenuredChunkInfo& info);
547 void updateOnArenaFree() { ++numArenasFreeCommitted; }
548
549 ChunkPool& fullChunks(const AutoLockGC& lock) { return fullChunks_.ref(); }
550 ChunkPool& availableChunks(const AutoLockGC& lock) {
551 return availableChunks_.ref();
552 }
553 ChunkPool& emptyChunks(const AutoLockGC& lock) { return emptyChunks_.ref(); }
554 const ChunkPool& fullChunks(const AutoLockGC& lock) const {
555 return fullChunks_.ref();
556 }
557 const ChunkPool& availableChunks(const AutoLockGC& lock) const {
558 return availableChunks_.ref();
559 }
560 const ChunkPool& emptyChunks(const AutoLockGC& lock) const {
561 return emptyChunks_.ref();
562 }
563 using NonEmptyChunksIter = ChainedIterator<ChunkPool::Iter, 2>;
564 NonEmptyChunksIter allNonEmptyChunks(const AutoLockGC& lock) {
565 return NonEmptyChunksIter(availableChunks(lock), fullChunks(lock));
566 }
567 uint32_t minEmptyChunkCount(const AutoLockGC& lock) const {
568 return minEmptyChunkCount_;
569 }
570 uint32_t maxEmptyChunkCount(const AutoLockGC& lock) const {
571 return maxEmptyChunkCount_;
572 }
573#ifdef DEBUG1
574 void verifyAllChunks();
575#endif
576
577 TenuredChunk* getOrAllocChunk(AutoLockGCBgAlloc& lock);
578 void recycleChunk(TenuredChunk* chunk, const AutoLockGC& lock);
579
580#ifdef JS_GC_ZEAL1
581 void startVerifyPreBarriers();
582 void endVerifyPreBarriers();
583 void finishVerifier();
584 bool isVerifyPreBarriersEnabled() const { return verifyPreData.refNoCheck(); }
585 bool shouldYieldForZeal(ZealMode mode);
586#else
587 bool isVerifyPreBarriersEnabled() const { return false; }
588#endif
589
590#ifdef JSGC_HASH_TABLE_CHECKS
591 void checkHashTablesAfterMovingGC();
592#endif
593
594 // Crawl the heap to check whether an arbitary pointer is within a cell of
595 // the given kind. (TraceKind::Null means to ignore the kind.)
596 bool isPointerWithinTenuredCell(
597 void* ptr, JS::TraceKind traceKind = JS::TraceKind::Null);
598
599#ifdef DEBUG1
600 bool hasZone(Zone* target);
601#endif
602
603 // Queue memory memory to be freed on a background thread if possible.
604 void queueUnusedLifoBlocksForFree(LifoAlloc* lifo);
605 void queueAllLifoBlocksForFreeAfterMinorGC(LifoAlloc* lifo);
606 void queueBuffersForFreeAfterMinorGC(Nursery::BufferSet& buffers);
607
608 // Public here for ReleaseArenaLists and FinalizeTypedArenas.
609 void releaseArena(Arena* arena, const AutoLockGC& lock);
610
611 // Allocator internals.
612 static void* refillFreeListInGC(Zone* zone, AllocKind thingKind);
613
614 // Delayed marking.
615 void delayMarkingChildren(gc::Cell* cell, MarkColor color);
616 bool hasDelayedMarking() const;
617 void markAllDelayedChildren(ShouldReportMarkTime reportTime);
618
619 // If we have yielded to the mutator while foreground finalizing arenas from
620 // zone |zone| with kind |kind| then return a list of the arenas finalized so
621 // far. These will have been removed from the main arena lists at this
622 // point. Otherwise return nullptr.
623 SortedArenaList* maybeGetForegroundFinalizedArenas(Zone* zone,
624 AllocKind kind);
625
626 /*
627 * Concurrent sweep infrastructure.
628 */
629 void startTask(GCParallelTask& task, AutoLockHelperThreadState& lock);
630 void joinTask(GCParallelTask& task, AutoLockHelperThreadState& lock);
631 void updateHelperThreadCount();
632 size_t parallelWorkerCount() const;
633
634 // GC parallel task dispatch infrastructure.
635 size_t getMaxParallelThreads() const;
636 void dispatchOrQueueParallelTask(GCParallelTask* task,
637 const AutoLockHelperThreadState& lock);
638 void maybeDispatchParallelTasks(const AutoLockHelperThreadState& lock);
639 void onParallelTaskEnd(bool wasDispatched,
640 const AutoLockHelperThreadState& lock);
641
642 // Parallel marking.
643 bool setParallelMarkingEnabled(bool enabled);
644 bool initOrDisableParallelMarking();
645 [[nodiscard]] bool updateMarkersVector();
646 size_t markingWorkerCount() const;
647
648 // WeakRefs
649 bool registerWeakRef(HandleObject target, HandleObject weakRef);
650 void traceKeptObjects(JSTracer* trc);
651
652 JS::GCReason lastStartReason() const { return initialReason; }
653
654 void updateAllocationRates();
655
656 // Allocator internals
657 static void* refillFreeList(JSContext* cx, AllocKind thingKind);
658 void attemptLastDitchGC(JSContext* cx);
659
660 // Test mark queue.
661#ifdef DEBUG1
662 const GCVector<HeapPtr<JS::Value>, 0, SystemAllocPolicy>& getTestMarkQueue()
663 const;
664 [[nodiscard]] bool appendTestMarkQueue(const JS::Value& value);
665 void clearTestMarkQueue();
666 size_t testMarkQueuePos() const;
667#endif
668
669 private:
670 enum IncrementalResult { ResetIncremental = 0, Ok };
671
672 [[nodiscard]] bool setParameter(JSGCParamKey key, uint32_t value,
673 AutoLockGC& lock);
674 void resetParameter(JSGCParamKey key, AutoLockGC& lock);
675 uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
676 bool setThreadParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock);
677 void resetThreadParameter(JSGCParamKey key, AutoLockGC& lock);
678 void updateThreadDataStructures(AutoLockGC& lock);
679
680 JS::GCOptions gcOptions() const { return maybeGcOptions.ref().ref(); }
681
682 TriggerResult checkHeapThreshold(Zone* zone, const HeapSize& heapSize,
683 const HeapThreshold& heapThreshold);
684
685 void updateSchedulingStateOnGCStart();
686 void updateSchedulingStateAfterCollection(mozilla::TimeStamp currentTime);
687 void updateAllGCStartThresholds();
688
689 // For ArenaLists::allocateFromArena()
690 friend class ArenaLists;
691 TenuredChunk* pickChunk(AutoLockGCBgAlloc& lock);
692 Arena* allocateArena(TenuredChunk* chunk, Zone* zone, AllocKind kind,
693 ShouldCheckThresholds checkThresholds,
694 const AutoLockGC& lock);
695
696 /*
697 * Return the list of chunks that can be released outside the GC lock.
698 * Must be called either during the GC or with the GC lock taken.
699 */
700 friend class BackgroundDecommitTask;
701 bool tooManyEmptyChunks(const AutoLockGC& lock);
702 ChunkPool expireEmptyChunkPool(const AutoLockGC& lock);
703 void freeEmptyChunks(const AutoLockGC& lock);
704 void prepareToFreeChunk(TenuredChunkInfo& info);
705 void setMinEmptyChunkCount(uint32_t value, const AutoLockGC& lock);
706 void setMaxEmptyChunkCount(uint32_t value, const AutoLockGC& lock);
707
708 friend class BackgroundAllocTask;
709 bool wantBackgroundAllocation(const AutoLockGC& lock) const;
710 void startBackgroundAllocTaskIfIdle();
711
712 void requestMajorGC(JS::GCReason reason);
713 SliceBudget defaultBudget(JS::GCReason reason, int64_t millis);
714 bool maybeIncreaseSliceBudget(SliceBudget& budget);
715 bool maybeIncreaseSliceBudgetForLongCollections(SliceBudget& budget);
716 bool maybeIncreaseSliceBudgetForUrgentCollections(SliceBudget& budget);
717 IncrementalResult budgetIncrementalGC(bool nonincrementalByAPI,
718 JS::GCReason reason,
719 SliceBudget& budget);
720 void checkZoneIsScheduled(Zone* zone, JS::GCReason reason,
721 const char* trigger);
722 IncrementalResult resetIncrementalGC(GCAbortReason reason);
723
724 // Assert if the system state is such that we should never
725 // receive a request to do GC work.
726 void checkCanCallAPI();
727
728 // Check if the system state is such that GC has been supressed
729 // or otherwise delayed.
730 [[nodiscard]] bool checkIfGCAllowedInCurrentState(JS::GCReason reason);
731
732 gcstats::ZoneGCStats scanZonesBeforeGC();
733
734 void setGCOptions(JS::GCOptions options);
735
736 void collect(bool nonincrementalByAPI, const SliceBudget& budget,
737 JS::GCReason reason) JS_HAZ_GC_CALL;
738
739 /*
740 * Run one GC "cycle" (either a slice of incremental GC or an entire
741 * non-incremental GC).
742 *
743 * Returns:
744 * * ResetIncremental if we "reset" an existing incremental GC, which would
745 * force us to run another cycle or
746 * * Ok otherwise.
747 */
748 [[nodiscard]] IncrementalResult gcCycle(bool nonincrementalByAPI,
749 const SliceBudget& budgetArg,
750 JS::GCReason reason);
751 bool shouldRepeatForDeadZone(JS::GCReason reason);
752
753 void incrementalSlice(SliceBudget& budget, JS::GCReason reason,
754 bool budgetWasIncreased);
755
756 bool mightSweepInThisSlice(bool nonIncremental);
757 void collectNurseryFromMajorGC(JS::GCReason reason);
758 void collectNursery(JS::GCOptions options, JS::GCReason reason,
759 gcstats::PhaseKind phase);
760
761 friend class AutoCallGCCallbacks;
762 void maybeCallGCCallback(JSGCStatus status, JS::GCReason reason);
763
764 void startCollection(JS::GCReason reason);
765
766 void purgeRuntime();
767 [[nodiscard]] bool beginPreparePhase(JS::GCReason reason,
768 AutoGCSession& session);
769 bool prepareZonesForCollection(JS::GCReason reason, bool* isFullOut);
770 void unmarkWeakMaps();
771 void endPreparePhase(JS::GCReason reason);
772 void beginMarkPhase(AutoGCSession& session);
773 bool shouldPreserveJITCode(JS::Realm* realm,
774 const mozilla::TimeStamp& currentTime,
775 JS::GCReason reason, bool canAllocateMoreCode,
776 bool isActiveCompartment);
777 void discardJITCodeForGC();
778 void startBackgroundFreeAfterMinorGC();
779 void relazifyFunctionsForShrinkingGC();
780 void purgePropMapTablesForShrinkingGC();
781 void purgeSourceURLsForShrinkingGC();
782 void traceRuntimeForMajorGC(JSTracer* trc, AutoGCSession& session);
783 void traceRuntimeAtoms(JSTracer* trc);
784 void traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark);
785 void traceEmbeddingBlackRoots(JSTracer* trc);
786 void traceEmbeddingGrayRoots(JSTracer* trc);
787 IncrementalProgress traceEmbeddingGrayRoots(JSTracer* trc,
788 SliceBudget& budget);
789 void checkNoRuntimeRoots(AutoGCSession& session);
790 void maybeDoCycleCollection();
791 void findDeadCompartments();
792
793 friend class BackgroundMarkTask;
794 enum ParallelMarking : bool {
795 SingleThreadedMarking = false,
796 AllowParallelMarking = true
797 };
798 IncrementalProgress markUntilBudgetExhausted(
799 SliceBudget& sliceBudget,
800 ParallelMarking allowParallelMarking = SingleThreadedMarking,
801 ShouldReportMarkTime reportTime = ReportMarkTime);
802 bool canMarkInParallel() const;
803 bool initParallelMarking();
804 void finishParallelMarkers();
805
806 bool reserveMarkingThreads(size_t count);
807 void releaseMarkingThreads();
808
809 bool hasMarkingWork(MarkColor color) const;
810
811 void drainMarkStack();
812
813#ifdef DEBUG1
814 void assertNoMarkingWork() const;
815#else
816 void assertNoMarkingWork() const {}
817#endif
818
819 void markDelayedChildren(gc::Arena* arena, MarkColor color);
820 void processDelayedMarkingList(gc::MarkColor color);
821 void rebuildDelayedMarkingList();
822 void appendToDelayedMarkingList(gc::Arena** listTail, gc::Arena* arena);
823 void resetDelayedMarking();
824 template <typename F>
825 void forEachDelayedMarkingArena(F&& f);
826
827 template <class ZoneIterT>
828 IncrementalProgress markWeakReferences(SliceBudget& budget);
829 IncrementalProgress markWeakReferencesInCurrentGroup(SliceBudget& budget);
830 template <class ZoneIterT>
831 IncrementalProgress markGrayRoots(SliceBudget& budget,
832 gcstats::PhaseKind phase);
833 void markBufferedGrayRoots(JS::Zone* zone);
834 IncrementalProgress markAllWeakReferences();
835 void markAllGrayReferences(gcstats::PhaseKind phase);
836
837 // The mark queue is a testing-only feature for controlling mark ordering and
838 // yield timing.
839 enum MarkQueueProgress {
840 QueueYielded, // End this incremental GC slice, if possible
841 QueueComplete, // Done with the queue
842 QueueSuspended // Continue the GC without ending the slice
843 };
844 MarkQueueProgress processTestMarkQueue();
845
846 // GC Sweeping. Implemented in Sweeping.cpp.
847 void beginSweepPhase(JS::GCReason reason, AutoGCSession& session);
848 void dropStringWrappers();
849 void groupZonesForSweeping(JS::GCReason reason);
850 [[nodiscard]] bool findSweepGroupEdges();
851 [[nodiscard]] bool addEdgesForMarkQueue();
852 void getNextSweepGroup();
853 void resetGrayList(Compartment* comp);
854 IncrementalProgress beginMarkingSweepGroup(JS::GCContext* gcx,
855 SliceBudget& budget);
856 IncrementalProgress markGrayRootsInCurrentGroup(JS::GCContext* gcx,
857 SliceBudget& budget);
858 IncrementalProgress markGray(JS::GCContext* gcx, SliceBudget& budget);
859 IncrementalProgress endMarkingSweepGroup(JS::GCContext* gcx,
860 SliceBudget& budget);
861 void markIncomingGrayCrossCompartmentPointers();
862 IncrementalProgress beginSweepingSweepGroup(JS::GCContext* gcx,
863 SliceBudget& budget);
864 void initBackgroundSweep(Zone* zone, JS::GCContext* gcx,
865 const FinalizePhase& phase);
866 IncrementalProgress markDuringSweeping(JS::GCContext* gcx,
867 SliceBudget& budget);
868 void updateAtomsBitmap();
869 void sweepCCWrappers();
870 void sweepRealmGlobals();
871 void sweepEmbeddingWeakPointers(JS::GCContext* gcx);
872 void sweepMisc();
873 void sweepCompressionTasks();
874 void sweepWeakMaps();
875 void sweepUniqueIds();
876 void sweepObjectsWithWeakPointers();
877 void sweepDebuggerOnMainThread(JS::GCContext* gcx);
878 void sweepJitDataOnMainThread(JS::GCContext* gcx);
879 void sweepFinalizationObserversOnMainThread();
880 void traceWeakFinalizationObserverEdges(JSTracer* trc, Zone* zone);
881 void sweepWeakRefs();
882 IncrementalProgress endSweepingSweepGroup(JS::GCContext* gcx,
883 SliceBudget& budget);
884 IncrementalProgress performSweepActions(SliceBudget& sliceBudget);
885 void startSweepingAtomsTable();
886 IncrementalProgress sweepAtomsTable(JS::GCContext* gcx, SliceBudget& budget);
887 IncrementalProgress sweepWeakCaches(JS::GCContext* gcx, SliceBudget& budget);
888 IncrementalProgress finalizeAllocKind(JS::GCContext* gcx,
889 SliceBudget& budget);
890 bool foregroundFinalize(JS::GCContext* gcx, Zone* zone, AllocKind thingKind,
891 js::SliceBudget& sliceBudget,
892 SortedArenaList& sweepList);
893 IncrementalProgress sweepPropMapTree(JS::GCContext* gcx, SliceBudget& budget);
894 void endSweepPhase(bool destroyingRuntime);
895 void queueZonesAndStartBackgroundSweep(ZoneList&& zones);
896 void sweepFromBackgroundThread(AutoLockHelperThreadState& lock);
897 void startBackgroundFree();
898 void freeFromBackgroundThread(AutoLockHelperThreadState& lock);
899 void sweepBackgroundThings(ZoneList& zones);
900 void backgroundFinalize(JS::GCContext* gcx, Zone* zone, AllocKind kind,
901 Arena** empty);
902 void assertBackgroundSweepingFinished();
903
904 bool allCCVisibleZonesWereCollected();
905 void sweepZones(JS::GCContext* gcx, bool destroyingRuntime);
906 bool shouldDecommit() const;
907 void startDecommit();
908 void decommitEmptyChunks(const bool& cancel, AutoLockGC& lock);
909 void decommitFreeArenas(const bool& cancel, AutoLockGC& lock);
910 void decommitFreeArenasWithoutUnlocking(const AutoLockGC& lock);
911
912 // Compacting GC. Implemented in Compacting.cpp.
913 bool shouldCompact();
914 void beginCompactPhase();
915 IncrementalProgress compactPhase(JS::GCReason reason,
916 SliceBudget& sliceBudget,
917 AutoGCSession& session);
918 void endCompactPhase();
919 void sweepZoneAfterCompacting(MovingTracer* trc, Zone* zone);
920 bool canRelocateZone(Zone* zone) const;
921 [[nodiscard]] bool relocateArenas(Zone* zone, JS::GCReason reason,
922 Arena*& relocatedListOut,
923 SliceBudget& sliceBudget);
924 void updateCellPointers(Zone* zone, AllocKinds kinds);
925 void updateAllCellPointers(MovingTracer* trc, Zone* zone);
926 void updateZonePointersToRelocatedCells(Zone* zone);
927 void updateRuntimePointersToRelocatedCells(AutoGCSession& session);
928 void clearRelocatedArenas(Arena* arenaList, JS::GCReason reason);
929 void clearRelocatedArenasWithoutUnlocking(Arena* arenaList,
930 JS::GCReason reason,
931 const AutoLockGC& lock);
932 void releaseRelocatedArenas(Arena* arenaList);
933 void releaseRelocatedArenasWithoutUnlocking(Arena* arenaList,
934 const AutoLockGC& lock);
935#ifdef DEBUG1
936 void protectOrReleaseRelocatedArenas(Arena* arenaList, JS::GCReason reason);
937 void protectAndHoldArenas(Arena* arenaList);
938 void unprotectHeldRelocatedArenas(const AutoLockGC& lock);
939 void releaseHeldRelocatedArenas();
940 void releaseHeldRelocatedArenasWithoutUnlocking(const AutoLockGC& lock);
941#endif
942
943 /*
944 * Whether to immediately trigger a slice after a background task
945 * finishes. This may not happen at a convenient time, so the consideration is
946 * whether the slice will run quickly or may take a long time.
947 */
948 enum ShouldTriggerSliceWhenFinished : bool {
949 DontTriggerSliceWhenFinished = false,
950 TriggerSliceWhenFinished = true
951 };
952
953 IncrementalProgress waitForBackgroundTask(
954 GCParallelTask& task, const SliceBudget& budget, bool shouldPauseMutator,
955 ShouldTriggerSliceWhenFinished triggerSlice);
956
957 void maybeRequestGCAfterBackgroundTask(const AutoLockHelperThreadState& lock);
958 void cancelRequestedGCAfterBackgroundTask();
959 void finishCollection(JS::GCReason reason);
960 void maybeStopPretenuring();
961 void checkGCStateNotInUse();
962 IncrementalProgress joinBackgroundMarkTask();
963
964#ifdef JS_GC_ZEAL1
965 void computeNonIncrementalMarkingForValidation(AutoGCSession& session);
966 void validateIncrementalMarking();
967 void finishMarkingValidation();
968#endif
969
970#ifdef DEBUG1
971 void checkForCompartmentMismatches();
972#endif
973
974 void callFinalizeCallbacks(JS::GCContext* gcx, JSFinalizeStatus status) const;
975 void callWeakPointerZonesCallbacks(JSTracer* trc) const;
976 void callWeakPointerCompartmentCallbacks(JSTracer* trc,
977 JS::Compartment* comp) const;
978 void callDoCycleCollectionCallback(JSContext* cx);
979
980 public:
981 JSRuntime* const rt;
982
983 // Embedders can use this zone however they wish.
984 MainThreadData<JS::Zone*> systemZone;
985
986 MainThreadData<JS::GCContext> mainThreadContext;
987
988 private:
989 // For parent runtimes, a zone containing atoms that is shared by child
990 // runtimes.
991 MainThreadData<Zone*> sharedAtomsZone_;
992
993 // All zones in the runtime. The first element is always the atoms zone.
994 MainThreadOrGCTaskData<ZoneVector> zones_;
995
996 // Any activity affecting the heap.
997 MainThreadOrGCTaskData<JS::HeapState> heapState_;
998 friend class AutoHeapSession;
999 friend class JS::AutoEnterCycleCollection;
1000
1001 UnprotectedData<gcstats::Statistics> stats_;
1002
1003 public:
1004 js::StringStats stringStats;
1005
1006 Vector<UniquePtr<GCMarker>, 1, SystemAllocPolicy> markers;
1007
1008 // Delayed marking support in case we OOM pushing work onto the mark stack.
1009 MainThreadOrGCTaskData<js::gc::Arena*> delayedMarkingList;
1010 MainThreadOrGCTaskData<bool> delayedMarkingWorkAdded;
1011#ifdef DEBUG1
1012 /* Count of arenas that are currently in the stack. */
1013 MainThreadOrGCTaskData<size_t> markLaterArenas;
1014#endif
1015
1016 SweepingTracer sweepingTracer;
1017
1018 /* Track total GC heap size for this runtime. */
1019 HeapSize heapSize;
1020
1021 /* GC scheduling state and parameters. */
1022 GCSchedulingTunables tunables;
1023 GCSchedulingState schedulingState;
1024 MainThreadData<bool> fullGCRequested;
1025
1026 // Helper thread configuration.
1027 MainThreadData<double> helperThreadRatio;
1028 MainThreadData<size_t> maxHelperThreads;
1029 MainThreadOrGCTaskData<size_t> helperThreadCount;
1030 MainThreadData<size_t> maxMarkingThreads;
1031 MainThreadData<size_t> markingThreadCount;
1032
1033 // Per-runtime helper thread task queue. Can be accessed from helper threads
1034 // in maybeDispatchParallelTasks().
1035 HelperThreadLockData<size_t> maxParallelThreads;
1036 HelperThreadLockData<size_t> dispatchedParallelTasks;
1037 HelperThreadLockData<GCParallelTaskList> queuedParallelTasks;
1038
1039 // State used for managing atom mark bitmaps in each zone.
1040 AtomMarkingRuntime atomMarking;
1041
1042 /*
1043 * Pointer to a callback that, if set, will be used to create a
1044 * budget for internally-triggered GCs.
1045 */
1046 MainThreadData<JS::CreateSliceBudgetCallback> createBudgetCallback;
1047
1048 private:
1049 // Arenas used for permanent things created at startup and shared by child
1050 // runtimes.
1051 MainThreadData<ArenaList> permanentAtoms;
1052 MainThreadData<ArenaList> permanentWellKnownSymbols;
1053
1054 // When chunks are empty, they reside in the emptyChunks pool and are
1055 // re-used as needed or eventually expired if not re-used. The emptyChunks
1056 // pool gets refilled from the background allocation task heuristically so
1057 // that empty chunks should always be available for immediate allocation
1058 // without syscalls.
1059 GCLockData<ChunkPool> emptyChunks_;
1060
1061 // Chunks which have had some, but not all, of their arenas allocated live
1062 // in the available chunk lists. When all available arenas in a chunk have
1063 // been allocated, the chunk is removed from the available list and moved
1064 // to the fullChunks pool. During a GC, if all arenas are free, the chunk
1065 // is moved back to the emptyChunks pool and scheduled for eventual
1066 // release.
1067 GCLockData<ChunkPool> availableChunks_;
1068
1069 // When all arenas in a chunk are used, it is moved to the fullChunks pool
1070 // so as to reduce the cost of operations on the available lists.
1071 GCLockData<ChunkPool> fullChunks_;
1072
1073 /*
1074 * JSGC_MIN_EMPTY_CHUNK_COUNT
1075 * JSGC_MAX_EMPTY_CHUNK_COUNT
1076 *
1077 * Controls the number of empty chunks reserved for future allocation.
1078 *
1079 * They can be read off main thread by the background allocation task and the
1080 * background decommit task.
1081 */
1082 GCLockData<uint32_t> minEmptyChunkCount_;
1083 GCLockData<uint32_t> maxEmptyChunkCount_;
1084
1085 MainThreadData<RootedValueMap> rootsHash;
1086
1087 // An incrementing id used to assign unique ids to cells that require one.
1088 MainThreadData<uint64_t> nextCellUniqueId_;
1089
1090 /*
1091 * Number of the committed arenas in all GC chunks including empty chunks.
1092 */
1093 mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numArenasFreeCommitted;
1094 MainThreadData<VerifyPreTracer*> verifyPreData;
1095
1096 MainThreadData<mozilla::TimeStamp> lastGCStartTime_;
1097 MainThreadData<mozilla::TimeStamp> lastGCEndTime_;
1098
1099 WriteOnceData<bool> initialized;
1100 MainThreadData<bool> incrementalGCEnabled;
1101 MainThreadData<bool> perZoneGCEnabled;
1102
1103 mozilla::Atomic<size_t, mozilla::ReleaseAcquire> numActiveZoneIters;
1104
1105 /* During shutdown, the GC needs to clean up every possible object. */
1106 MainThreadData<bool> cleanUpEverything;
1107
1108 /*
1109 * The gray bits can become invalid if UnmarkGray overflows the stack. A
1110 * full GC will reset this bit, since it fills in all the gray bits.
1111 */
1112 UnprotectedData<bool> grayBitsValid;
1113
1114 mozilla::Atomic<JS::GCReason, mozilla::ReleaseAcquire> majorGCTriggerReason;
1115
1116 /* Incremented at the start of every minor GC. */
1117 MainThreadData<uint64_t> minorGCNumber;
1118
1119 /* Incremented at the start of every major GC. */
1120 MainThreadData<uint64_t> majorGCNumber;
1121
1122 /* Incremented on every GC slice or minor collection. */
1123 MainThreadData<uint64_t> number;
1124
1125 /* Incremented on every GC slice. */
1126 MainThreadData<uint64_t> sliceNumber;
1127
1128 /*
1129 * This runtime's current contribution to the global number of helper threads
1130 * 'reserved' for parallel marking. Does not affect other uses of helper
1131 * threads.
1132 */
1133 MainThreadData<size_t> reservedMarkingThreads;
1134
1135 /* Whether the currently running GC can finish in multiple slices. */
1136 MainThreadOrGCTaskData<bool> isIncremental;
1137
1138 /* Whether all zones are being collected in first GC slice. */
1139 MainThreadData<bool> isFull;
1140
1141 /* Whether the heap will be compacted at the end of GC. */
1142 MainThreadData<bool> isCompacting;
1143
1144 /* Whether to use parallel marking. */
1145 MainThreadData<ParallelMarking> useParallelMarking;
1146
1147 /* The invocation kind of the current GC, set at the start of collection. */
1148 MainThreadOrGCTaskData<mozilla::Maybe<JS::GCOptions>> maybeGcOptions;
1149
1150 /* The initial GC reason, taken from the first slice. */
1151 MainThreadData<JS::GCReason> initialReason;
1152
1153 /*
1154 * The current incremental GC phase. This is also used internally in
1155 * non-incremental GC.
1156 */
1157 MainThreadOrGCTaskData<State> incrementalState;
1158
1159 /* The incremental state at the start of this slice. */
1160 MainThreadOrGCTaskData<State> initialState;
1161
1162 /* Whether to pay attention the zeal settings in this incremental slice. */
1163#ifdef JS_GC_ZEAL1
1164 MainThreadData<bool> useZeal;
1165#else
1166 const bool useZeal;
1167#endif
1168
1169 /* Indicates that the last incremental slice exhausted the mark stack. */
1170 MainThreadData<bool> lastMarkSlice;
1171
1172 // Whether it's currently safe to yield to the mutator in an incremental GC.
1173 MainThreadData<bool> safeToYield;
1174
1175 // Whether to do any marking caused by barriers on a background thread during
1176 // incremental sweeping, while also sweeping zones which have finished
1177 // marking.
1178 MainThreadData<bool> markOnBackgroundThreadDuringSweeping;
1179
1180 // Whether any sweeping and decommitting will run on a separate GC helper
1181 // thread.
1182 MainThreadData<bool> useBackgroundThreads;
1183
1184 // Whether we have already discarded JIT code for all collected zones in this
1185 // slice.
1186 MainThreadData<bool> haveDiscardedJITCodeThisSlice;
1187
1188#ifdef DEBUG1
1189 /* Shutdown has started. Further collections must be shutdown collections. */
1190 MainThreadData<bool> hadShutdownGC;
1191#endif
1192
1193 /* Singly linked list of zones to be swept in the background. */
1194 HelperThreadLockData<ZoneList> backgroundSweepZones;
1195
1196 /*
1197 * Whether to trigger a GC slice after a background task is complete, so that
1198 * the collector can continue or finsish collecting. This is only used for the
1199 * tasks that run concurrently with the mutator, which are background
1200 * finalization and background decommit.
1201 */
1202 HelperThreadLockData<bool> requestSliceAfterBackgroundTask;
1203
1204 /*
1205 * Free LIFO blocks are transferred to these allocators before being freed on
1206 * a background thread.
1207 */
1208 HelperThreadLockData<LifoAlloc> lifoBlocksToFree;
1209 MainThreadData<LifoAlloc> lifoBlocksToFreeAfterFullMinorGC;
1210 MainThreadData<LifoAlloc> lifoBlocksToFreeAfterNextMinorGC;
1211 HelperThreadLockData<Nursery::BufferSet> buffersToFreeAfterMinorGC;
1212
1213 /* Index of current sweep group (for stats). */
1214 MainThreadData<unsigned> sweepGroupIndex;
1215
1216 /*
1217 * Incremental sweep state.
1218 */
1219 MainThreadData<JS::Zone*> sweepGroups;
1220 MainThreadOrGCTaskData<JS::Zone*> currentSweepGroup;
1221 MainThreadData<UniquePtr<SweepAction>> sweepActions;
1222 MainThreadOrGCTaskData<JS::Zone*> sweepZone;
1223 MainThreadOrGCTaskData<AllocKind> sweepAllocKind;
1224 MainThreadData<mozilla::Maybe<AtomsTable::SweepIterator>> maybeAtomsToSweep;
1225 MainThreadOrGCTaskData<mozilla::Maybe<WeakCacheSweepIterator>>
1226 weakCachesToSweep;
1227 MainThreadData<bool> abortSweepAfterCurrentGroup;
1228 MainThreadOrGCTaskData<IncrementalProgress> sweepMarkResult;
1229
1230 /*
1231 * During incremental foreground finalization, we may have a list of arenas of
1232 * the current AllocKind and Zone whose contents have been finalized but which
1233 * have not yet been merged back into the main arena lists.
1234 */
1235 MainThreadOrGCTaskData<JS::Zone*> foregroundFinalizedZone;
1236 MainThreadOrGCTaskData<AllocKind> foregroundFinalizedAllocKind;
1237 MainThreadData<mozilla::Maybe<SortedArenaList>> foregroundFinalizedArenas;
1238
1239#ifdef DEBUG1
1240 /*
1241 * List of objects to mark at the beginning of a GC for testing purposes. May
1242 * also contain string directives to change mark color or wait until different
1243 * phases of the GC.
1244 *
1245 * This is a WeakCache because not everything in this list is guaranteed to
1246 * end up marked (eg if you insert an object from an already-processed sweep
1247 * group in the middle of an incremental GC). Also, the mark queue is not
1248 * used during shutdown GCs. In either case, unmarked objects may need to be
1249 * discarded.
1250 */
1251 WeakCache<GCVector<HeapPtr<JS::Value>, 0, SystemAllocPolicy>> testMarkQueue;
1252
1253 /* Position within the test mark queue. */
1254 size_t queuePos = 0;
1255
1256 /* The test marking queue might want to be marking a particular color. */
1257 mozilla::Maybe<js::gc::MarkColor> queueMarkColor;
1258
1259 // During gray marking, delay AssertCellIsNotGray checks by
1260 // recording the cell pointers here and checking after marking has
1261 // finished.
1262 MainThreadData<Vector<const Cell*, 0, SystemAllocPolicy>>
1263 cellsToAssertNotGray;
1264 friend void js::gc::detail::AssertCellIsNotGray(const Cell*);
1265#endif
1266
1267 friend class SweepGroupsIter;
1268
1269 /*
1270 * Incremental compacting state.
1271 */
1272 MainThreadData<bool> startedCompacting;
1273 MainThreadData<ZoneList> zonesToMaybeCompact;
1274 MainThreadData<size_t> zonesCompacted;
1275#ifdef DEBUG1
1276 GCLockData<Arena*> relocatedArenasToRelease;
1277#endif
1278
1279#ifdef JS_GC_ZEAL1
1280 MainThreadData<MarkingValidator*> markingValidator;
1281#endif
1282
1283 /*
1284 * Default budget for incremental GC slice. See js/SliceBudget.h.
1285 *
1286 * JSGC_SLICE_TIME_BUDGET_MS
1287 * pref: javascript.options.mem.gc_incremental_slice_ms,
1288 */
1289 MainThreadData<int64_t> defaultTimeBudgetMS_;
1290
1291 /*
1292 * We disable incremental GC if we encounter a Class with a trace hook
1293 * that does not implement write barriers.
1294 */
1295 MainThreadData<bool> incrementalAllowed;
1296
1297 /*
1298 * Whether compacting GC can is enabled globally.
1299 *
1300 * JSGC_COMPACTING_ENABLED
1301 * pref: javascript.options.mem.gc_compacting
1302 */
1303 MainThreadData<bool> compactingEnabled;
1304
1305 /*
1306 * Whether parallel marking is enabled globally.
1307 *
1308 * JSGC_PARALLEL_MARKING_ENABLED
1309 * pref: javascript.options.mem.gc_parallel_marking
1310 */
1311 MainThreadData<bool> parallelMarkingEnabled;
1312
1313 MainThreadData<bool> rootsRemoved;
1314
1315 /*
1316 * These options control the zealousness of the GC. At every allocation,
1317 * nextScheduled is decremented. When it reaches zero we do a full GC.
1318 *
1319 * At this point, if zeal_ is one of the types that trigger periodic
1320 * collection, then nextScheduled is reset to the value of zealFrequency.
1321 * Otherwise, no additional GCs take place.
1322 *
1323 * You can control these values in several ways:
1324 * - Set the JS_GC_ZEAL environment variable
1325 * - Call gczeal() or schedulegc() from inside shell-executed JS code
1326 * (see the help for details)
1327 *
1328 * If gcZeal_ == 1 then we perform GCs in select places (during MaybeGC and
1329 * whenever we are notified that GC roots have been removed). This option is
1330 * mainly useful to embedders.
1331 *
1332 * We use zeal_ == 4 to enable write barrier verification. See the comment
1333 * in gc/Verifier.cpp for more information about this.
1334 *
1335 * zeal_ values from 8 to 10 periodically run different types of
1336 * incremental GC.
1337 *
1338 * zeal_ value 14 performs periodic shrinking collections.
1339 */
1340#ifdef JS_GC_ZEAL1
1341 static_assert(size_t(ZealMode::Count) <= 32,
1342 "Too many zeal modes to store in a uint32_t");
1343 MainThreadData<uint32_t> zealModeBits;
1344 MainThreadData<int> zealFrequency;
1345 MainThreadData<int> nextScheduled;
1346 MainThreadData<bool> deterministicOnly;
1347 MainThreadData<int> zealSliceBudget;
1348 MainThreadData<size_t> maybeMarkStackLimit;
1349
1350 MainThreadData<PersistentRooted<GCVector<JSObject*, 0, SystemAllocPolicy>>>
1351 selectedForMarking;
1352#endif
1353
1354 MainThreadData<bool> fullCompartmentChecks;
1355
1356 MainThreadData<uint32_t> gcCallbackDepth;
1357
1358 MainThreadData<Callback<JSGCCallback>> gcCallback;
1359 MainThreadData<Callback<JS::DoCycleCollectionCallback>>
1360 gcDoCycleCollectionCallback;
1361 MainThreadData<Callback<JSObjectsTenuredCallback>> tenuredCallback;
1362 MainThreadData<CallbackVector<JSFinalizeCallback>> finalizeCallbacks;
1363 MainThreadOrGCTaskData<Callback<JSHostCleanupFinalizationRegistryCallback>>
1364 hostCleanupFinalizationRegistryCallback;
1365 MainThreadData<CallbackVector<JSWeakPointerZonesCallback>>
1366 updateWeakPointerZonesCallbacks;
1367 MainThreadData<CallbackVector<JSWeakPointerCompartmentCallback>>
1368 updateWeakPointerCompartmentCallbacks;
1369 MainThreadData<CallbackVector<JS::GCNurseryCollectionCallback>>
1370 nurseryCollectionCallbacks;
1371
1372 /*
1373 * The trace operations to trace embedding-specific GC roots. One is for
1374 * tracing through black roots and the other is for tracing through gray
1375 * roots. The black/gray distinction is only relevant to the cycle
1376 * collector.
1377 */
1378 MainThreadData<CallbackVector<JSTraceDataOp>> blackRootTracers;
1379 MainThreadOrGCTaskData<Callback<JSGrayRootsTracer>> grayRootTracer;
1380
1381 /* Always preserve JIT code during GCs, for testing. */
1382 MainThreadData<bool> alwaysPreserveCode;
1383
1384 /* Count of the number of zones that are currently in page load. */
1385 MainThreadData<size_t> inPageLoadCount;
1386
1387 MainThreadData<bool> lowMemoryState;
1388
1389 /*
1390 * General purpose GC lock, used for synchronising operations on
1391 * arenas and during parallel marking.
1392 */
1393 friend class js::AutoLockGC;
1394 friend class js::AutoLockGCBgAlloc;
1395 Mutex lock MOZ_UNANNOTATED;
1396
1397 /*
1398 * Lock used to synchronise access to the store buffer during parallel
1399 * sweeping.
1400 */
1401 Mutex storeBufferLock MOZ_UNANNOTATED;
1402
1403 /* Lock used to synchronise access to delayed marking state. */
1404 Mutex delayedMarkingLock MOZ_UNANNOTATED;
1405
1406 friend class BackgroundSweepTask;
1407 friend class BackgroundFreeTask;
1408
1409 BackgroundAllocTask allocTask;
1410 BackgroundUnmarkTask unmarkTask;
1411 BackgroundMarkTask markTask;
1412 BackgroundSweepTask sweepTask;
1413 BackgroundFreeTask freeTask;
1414 BackgroundDecommitTask decommitTask;
1415
1416 MainThreadData<Nursery> nursery_;
1417
1418 // The store buffer used to track tenured to nursery edges for generational
1419 // GC. This is accessed off main thread when sweeping WeakCaches.
1420 MainThreadOrGCTaskData<gc::StoreBuffer> storeBuffer_;
1421
1422 mozilla::TimeStamp lastLastDitchTime;
1423
1424 // The last time per-zone allocation rates were updated.
1425 MainThreadData<mozilla::TimeStamp> lastAllocRateUpdateTime;
1426
1427 // Total collector time since per-zone allocation rates were last updated.
1428 MainThreadData<mozilla::TimeDuration> collectorTimeSinceAllocRateUpdate;
1429
1430 friend class MarkingValidator;
1431 friend class AutoEnterIteration;
1432};
1433
1434/* Prevent compartments and zones from being collected during iteration. */
1435class MOZ_RAII AutoEnterIteration {
1436 GCRuntime* gc;
1437
1438 public:
1439 explicit AutoEnterIteration(GCRuntime* gc_) : gc(gc_) {
1440 ++gc->numActiveZoneIters;
1441 }
1442
1443 ~AutoEnterIteration() {
1444 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"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/gc/GCRuntime.h"
, 1444); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gc->numActiveZoneIters"
")"); do { *((volatile int*)__null) = 1444; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1445 --gc->numActiveZoneIters;
1446 }
1447};
1448
1449#ifdef JS_GC_ZEAL1
1450
1451inline bool GCRuntime::hasZealMode(ZealMode mode) {
1452 static_assert(size_t(ZealMode::Limit) < sizeof(zealModeBits) * 8,
1453 "Zeal modes must fit in zealModeBits");
1454 return zealModeBits & (1 << uint32_t(mode));
1455}
1456
1457inline void GCRuntime::clearZealMode(ZealMode mode) {
1458 zealModeBits &= ~(1 << uint32_t(mode));
1459 MOZ_ASSERT(!hasZealMode(mode))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!hasZealMode(mode))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!hasZealMode(mode)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!hasZealMode(mode)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/gc/GCRuntime.h"
, 1459); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!hasZealMode(mode)"
")"); do { *((volatile int*)__null) = 1459; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1460}
1461
1462inline bool GCRuntime::needZealousGC() {
1463 if (nextScheduled > 0 && --nextScheduled == 0) {
1464 if (hasZealMode(ZealMode::Alloc) || hasZealMode(ZealMode::GenerationalGC) ||
1465 hasZealMode(ZealMode::IncrementalMultipleSlices) ||
1466 hasZealMode(ZealMode::Compact) || hasIncrementalTwoSliceZealMode()) {
1467 nextScheduled = zealFrequency;
1468 }
1469 return true;
1470 }
1471 return false;
1472}
1473
1474inline bool GCRuntime::hasIncrementalTwoSliceZealMode() {
1475 return hasZealMode(ZealMode::YieldBeforeRootMarking) ||
1476 hasZealMode(ZealMode::YieldBeforeMarking) ||
1477 hasZealMode(ZealMode::YieldBeforeSweeping) ||
1478 hasZealMode(ZealMode::YieldBeforeSweepingAtoms) ||
1479 hasZealMode(ZealMode::YieldBeforeSweepingCaches) ||
1480 hasZealMode(ZealMode::YieldBeforeSweepingObjects) ||
1481 hasZealMode(ZealMode::YieldBeforeSweepingNonObjects) ||
1482 hasZealMode(ZealMode::YieldBeforeSweepingPropMapTrees) ||
1483 hasZealMode(ZealMode::YieldWhileGrayMarking);
1484}
1485
1486#else
1487inline bool GCRuntime::hasZealMode(ZealMode mode) { return false; }
1488inline void GCRuntime::clearZealMode(ZealMode mode) {}
1489inline bool GCRuntime::needZealousGC() { return false; }
1490inline bool GCRuntime::hasIncrementalTwoSliceZealMode() { return false; }
1491#endif
1492
1493bool IsCurrentlyAnimating(const mozilla::TimeStamp& lastAnimationTime,
1494 const mozilla::TimeStamp& currentTime);
1495
1496} /* namespace gc */
1497} /* namespace js */
1498
1499#endif