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/. */
8 * High-level interface to the JS garbage collector.
14 #include "mozilla/TimeStamp.h"
15 #include "mozilla/Vector.h"
17 #include "js/CharacterEncoding.h" // JS::UTF8Chars
18 #include "js/GCAnnotations.h"
19 #include "js/shadow/Zone.h"
20 #include "js/SliceBudget.h"
21 #include "js/TypeDecls.h"
22 #include "js/UniquePtr.h"
23 #include "js/Utility.h"
25 class JS_PUBLIC_API JSTracer
;
31 class JS_PUBLIC_API SliceBudget
;
34 } // namespace gcstats
39 // Options used when starting a GC.
40 enum class GCOptions
: uint32_t {
41 // Normal GC invocation.
43 // Some objects that are unreachable from the program may still be alive after
44 // collection because of internal references
49 // Try to release as much memory as possible by clearing internal caches,
50 // aggressively discarding JIT code and decommitting unused chunks. This
51 // ensures all unreferenced objects are removed from the system.
53 // Finally, compact the GC heap.
58 // This does more drastic cleanup as part of system shutdown, including:
59 // - clearing WeakRef kept object sets
60 // - not marking FinalizationRegistry roots
61 // - repeating collection if JS::NotifyGCRootsRemoved was called
62 // - skipping scheduling of various future work that won't be needed
64 // Note that this assumes that no JS will run after this point!
70 typedef enum JSGCParamKey
{
72 * Maximum nominal heap before last ditch GC.
74 * Soft limit on the number of bytes we are allowed to allocate in the GC
75 * heap. Attempts to allocate gcthings over this limit will return null and
76 * subsequently invoke the standard OOM machinery, independent of available
79 * Pref: javascript.options.mem.max
85 * Maximum size of the generational GC nurseries.
87 * This will be rounded to the nearest gc::ChunkSize.
89 * Pref: javascript.options.mem.nursery.max_kb
90 * Default: JS::DefaultNurseryMaxBytes
92 JSGC_MAX_NURSERY_BYTES
= 2,
94 /** Amount of bytes allocated by the GC. */
97 /** Number of times GC has been invoked. Includes both major and minor GC. */
101 * Whether incremental GC is enabled. If not, GC will always run to
104 * prefs: javascript.options.mem.gc_incremental.
107 JSGC_INCREMENTAL_GC_ENABLED
= 5,
110 * Whether per-zone GC is enabled. If not, all zones are collected every time.
112 * prefs: javascript.options.mem.gc_per_zone
115 JSGC_PER_ZONE_GC_ENABLED
= 6,
117 /** Number of cached empty GC chunks. */
118 JSGC_UNUSED_CHUNKS
= 7,
120 /** Total number of allocated GC chunks. */
121 JSGC_TOTAL_CHUNKS
= 8,
124 * Max milliseconds to spend in an incremental GC slice.
126 * A value of zero means there is no maximum.
128 * Pref: javascript.options.mem.gc_incremental_slice_ms
129 * Default: DefaultTimeBudgetMS.
131 JSGC_SLICE_TIME_BUDGET_MS
= 9,
134 * The "do we collect?" decision depends on various parameters and can be
137 * ZoneSize > Max(ThresholdBase, LastSize) * GrowthFactor * ThresholdFactor
140 * ZoneSize: Current size of this zone.
141 * LastSize: Heap size immediately after the most recent collection.
142 * ThresholdBase: The JSGC_ALLOCATION_THRESHOLD parameter
143 * GrowthFactor: A number above 1, calculated based on some of the
144 * following parameters.
145 * See computeZoneHeapGrowthFactorForHeapSize() in GC.cpp
146 * ThresholdFactor: 1.0 to trigger an incremental collections or between
147 * JSGC_SMALL_HEAP_INCREMENTAL_LIMIT and
148 * JSGC_LARGE_HEAP_INCREMENTAL_LIMIT to trigger a
149 * non-incremental collection.
151 * The RHS of the equation above is calculated and sets
152 * zone->gcHeapThreshold.bytes(). When gcHeapSize.bytes() exeeds
153 * gcHeapThreshold.bytes() for a zone, the zone may be scheduled for a GC.
157 * GCs less than this far apart in milliseconds will be considered
158 * 'high-frequency GCs'.
160 * Pref: javascript.options.mem.gc_high_frequency_time_limit_ms
161 * Default: HighFrequencyThreshold
163 JSGC_HIGH_FREQUENCY_TIME_LIMIT
= 11,
166 * Upper limit for classifying a heap as small (MB).
168 * Dynamic heap growth thresholds are based on whether the heap is small,
169 * medium or large. Heaps smaller than this size are classified as small;
170 * larger heaps are classified as medium or large.
172 * Pref: javascript.options.mem.gc_small_heap_size_max_mb
173 * Default: SmallHeapSizeMaxBytes
175 JSGC_SMALL_HEAP_SIZE_MAX
= 12,
178 * Lower limit for classifying a heap as large (MB).
180 * Dynamic heap growth thresholds are based on whether the heap is small,
181 * medium or large. Heaps larger than this size are classified as large;
182 * smaller heaps are classified as small or medium.
184 * Pref: javascript.options.mem.gc_large_heap_size_min_mb
185 * Default: LargeHeapSizeMinBytes
187 JSGC_LARGE_HEAP_SIZE_MIN
= 13,
190 * Heap growth factor for small heaps in the high-frequency GC state.
192 * Pref: javascript.options.mem.gc_high_frequency_small_heap_growth
193 * Default: HighFrequencySmallHeapGrowth
195 JSGC_HIGH_FREQUENCY_SMALL_HEAP_GROWTH
= 14,
198 * Heap growth factor for large heaps in the high-frequency GC state.
200 * Pref: javascript.options.mem.gc_high_frequency_large_heap_growth
201 * Default: HighFrequencyLargeHeapGrowth
203 JSGC_HIGH_FREQUENCY_LARGE_HEAP_GROWTH
= 15,
206 * Heap growth factor for low frequency GCs.
208 * This factor is applied regardless of the size of the heap when not in the
209 * high-frequency GC state.
211 * Pref: javascript.options.mem.gc_low_frequency_heap_growth
212 * Default: LowFrequencyHeapGrowth
214 JSGC_LOW_FREQUENCY_HEAP_GROWTH
= 16,
217 * Whether balanced heap limits are enabled.
219 * If this is set to true then heap limits are calculated in a way designed to
220 * balance memory usage optimally between many heaps.
222 * Otherwise, heap limits are set based on a linear multiple of the retained
223 * size after the last collection.
225 * Pref: javascript.options.mem.gc_balanced_heap_limits
226 * Default: BalancedHeapLimitsEnabled
228 JSGC_BALANCED_HEAP_LIMITS_ENABLED
= 17,
231 * Heap growth parameter for balanced heap limit calculation.
233 * This parameter trades off GC time for memory usage. Smaller values result
234 * in lower memory use and larger values result in less time spent collecting.
236 * Heap limits are set to the heap's retained size plus some extra space. The
237 * extra space is calculated based on several factors but is scaled
238 * proportionally to this parameter.
240 * Pref: javascript.options.mem.gc_heap_growth_factor
241 * Default: HeapGrowthFactor
243 JSGC_HEAP_GROWTH_FACTOR
= 18,
246 * Lower limit for collecting a zone (MB).
248 * Zones smaller than this size will not normally be collected.
250 * Pref: javascript.options.mem.gc_allocation_threshold_mb
251 * Default GCZoneAllocThresholdBase
253 JSGC_ALLOCATION_THRESHOLD
= 19,
256 * We try to keep at least this many unused chunks in the free chunk pool at
257 * all times, even after a shrinking GC.
259 * Pref: javascript.options.mem.gc_min_empty_chunk_count
260 * Default: MinEmptyChunkCount
262 JSGC_MIN_EMPTY_CHUNK_COUNT
= 21,
265 * We never keep more than this many unused chunks in the free chunk pool.
267 * Pref: javascript.options.mem.gc_max_empty_chunk_count
268 * Default: MaxEmptyChunkCount
270 JSGC_MAX_EMPTY_CHUNK_COUNT
= 22,
273 * Whether compacting GC is enabled.
275 * Pref: javascript.options.mem.gc_compacting
276 * Default: CompactingEnabled
278 JSGC_COMPACTING_ENABLED
= 23,
281 * Whether parallel marking is enabled.
283 * Pref: javascript.options.mem.gc_parallel_marking
284 * Default: ParallelMarkingEnabled
286 JSGC_PARALLEL_MARKING_ENABLED
= 24,
289 * Limit of how far over the incremental trigger threshold we allow the heap
290 * to grow before finishing a collection non-incrementally, for small heaps.
292 * We trigger an incremental GC when a trigger threshold is reached but the
293 * collection may not be fast enough to keep up with the mutator. At some
294 * point we finish the collection non-incrementally.
296 * Default: SmallHeapIncrementalLimit
297 * Pref: javascript.options.mem.gc_small_heap_incremental_limit
299 JSGC_SMALL_HEAP_INCREMENTAL_LIMIT
= 25,
302 * Limit of how far over the incremental trigger threshold we allow the heap
303 * to grow before finishing a collection non-incrementally, for large heaps.
305 * Default: LargeHeapIncrementalLimit
306 * Pref: javascript.options.mem.gc_large_heap_incremental_limit
308 JSGC_LARGE_HEAP_INCREMENTAL_LIMIT
= 26,
311 * Attempt to run a minor GC in the idle time if the free space falls
312 * below this number of bytes.
314 * Default: NurseryChunkUsableSize / 4
317 JSGC_NURSERY_FREE_THRESHOLD_FOR_IDLE_COLLECTION
= 27,
320 * Attempt to run a minor GC in the idle time if the free space falls
321 * below this percentage (from 0 to 99).
326 JSGC_NURSERY_FREE_THRESHOLD_FOR_IDLE_COLLECTION_PERCENT
= 30,
329 * Minimum size of the generational GC nurseries.
331 * This value will be rounded to the nearest Nursery::SubChunkStep if below
332 * gc::ChunkSize, otherwise it'll be rounded to the nearest gc::ChunkSize.
334 * Default: Nursery::SubChunkLimit
335 * Pref: javascript.options.mem.nursery.min_kb
337 JSGC_MIN_NURSERY_BYTES
= 31,
340 * The minimum time to allow between triggering last ditch GCs in seconds.
342 * Default: 60 seconds
345 JSGC_MIN_LAST_DITCH_GC_PERIOD
= 32,
348 * The delay (in heapsize kilobytes) between slices of an incremental GC.
350 * Default: ZoneAllocDelayBytes
352 JSGC_ZONE_ALLOC_DELAY_KB
= 33,
355 * The current size of the nursery.
357 * This parameter is read-only.
359 JSGC_NURSERY_BYTES
= 34,
362 * Retained size base value for calculating malloc heap threshold.
364 * Default: MallocThresholdBase
366 JSGC_MALLOC_THRESHOLD_BASE
= 35,
369 * Whether incremental weakmap marking is enabled.
371 * Pref: javascript.options.mem.incremental_weakmap
372 * Default: IncrementalWeakMarkEnabled
374 JSGC_INCREMENTAL_WEAKMAP_ENABLED
= 37,
377 * The chunk size in bytes for this system.
379 * This parameter is read-only.
381 JSGC_CHUNK_BYTES
= 38,
384 * The number of background threads to use for parallel GC work for each CPU
385 * core, expressed as an integer percentage.
387 * Pref: javascript.options.mem.gc_helper_thread_ratio
389 JSGC_HELPER_THREAD_RATIO
= 39,
392 * The maximum number of background threads to use for parallel GC work.
394 * Pref: javascript.options.mem.gc_max_helper_threads
396 JSGC_MAX_HELPER_THREADS
= 40,
399 * The number of background threads to use for parallel GC work.
401 * This parameter is read-only and is set based on the
402 * JSGC_HELPER_THREAD_RATIO and JSGC_MAX_HELPER_THREADS parameters.
404 JSGC_HELPER_THREAD_COUNT
= 41,
407 * A number that is incremented on every major GC slice.
409 JSGC_MAJOR_GC_NUMBER
= 44,
412 * A number that is incremented on every minor GC.
414 JSGC_MINOR_GC_NUMBER
= 45,
417 * JS::MaybeRunNurseryCollection will collect the nursery if it hasn't been
418 * collected in this many milliseconds.
423 JSGC_NURSERY_TIMEOUT_FOR_IDLE_COLLECTION_MS
= 46,
426 * The system page size in KB.
428 * This parameter is read-only.
430 JSGC_SYSTEM_PAGE_SIZE_KB
= 47,
433 * In an incremental GC, this determines the point at which to start
434 * increasing the slice budget and frequency of allocation triggered slices to
435 * try to avoid reaching the incremental limit and finishing the collection
438 * The threshold is calculated by subtracting this value from the heap's
441 JSGC_URGENT_THRESHOLD_MB
= 48,
444 * Set the number of threads to use for parallel marking, or zero to use the
447 * The actual number used is capped to the number of available helper threads.
449 * This is provided for testing purposes.
452 * Default: 0 (no effect).
454 JSGC_MARKING_THREAD_COUNT
= 49,
457 * The heap size above which to use parallel marking.
459 * Default: ParallelMarkingThresholdMB
461 JSGC_PARALLEL_MARKING_THRESHOLD_MB
= 50,
465 * Generic trace operation that calls JS::TraceEdge on each traceable thing's
466 * location reachable from data.
468 typedef void (*JSTraceDataOp
)(JSTracer
* trc
, void* data
);
471 * Trace hook used to trace gray roots incrementally.
473 * This should return whether tracing is finished. It will be called repeatedly
474 * in subsequent GC slices until it returns true.
476 * While tracing this should check the budget and return false if it has been
477 * exceeded. When passed an unlimited budget it should always return true.
479 typedef bool (*JSGrayRootsTracer
)(JSTracer
* trc
, js::SliceBudget
& budget
,
482 typedef enum JSGCStatus
{ JSGC_BEGIN
, JSGC_END
} JSGCStatus
;
484 typedef void (*JSObjectsTenuredCallback
)(JSContext
* cx
, void* data
);
486 typedef enum JSFinalizeStatus
{
488 * Called when preparing to sweep a group of zones, before anything has been
489 * swept. The collector will not yield to the mutator before calling the
490 * callback with JSFINALIZE_GROUP_START status.
492 JSFINALIZE_GROUP_PREPARE
,
495 * Called after preparing to sweep a group of zones. Weak references to
496 * unmarked things have been removed at this point, but no GC things have
497 * been swept. The collector may yield to the mutator after this point.
499 JSFINALIZE_GROUP_START
,
502 * Called after sweeping a group of zones. All dead GC things have been
503 * swept at this point.
505 JSFINALIZE_GROUP_END
,
508 * Called at the end of collection when everything has been swept.
510 JSFINALIZE_COLLECTION_END
513 typedef void (*JSFinalizeCallback
)(JS::GCContext
* gcx
, JSFinalizeStatus status
,
516 typedef void (*JSWeakPointerZonesCallback
)(JSTracer
* trc
, void* data
);
518 typedef void (*JSWeakPointerCompartmentCallback
)(JSTracer
* trc
,
519 JS::Compartment
* comp
,
523 * This is called to tell the embedding that a FinalizationRegistry object has
524 * cleanup work, and that the engine should be called back at an appropriate
525 * later time to perform this cleanup, by calling the function |doCleanup|.
527 * This callback must not do anything that could cause GC.
529 using JSHostCleanupFinalizationRegistryCallback
=
530 void (*)(JSFunction
* doCleanup
, JSObject
* incumbentGlobal
, void* data
);
533 * Each external string has a pointer to JSExternalStringCallbacks. Embedders
534 * can use this to implement custom finalization or memory reporting behavior.
536 struct JSExternalStringCallbacks
{
538 * Finalizes external strings created by JS_NewExternalStringLatin1 or
539 * JS_NewExternalUCString. The finalizer can be called off the main
542 virtual void finalize(JS::Latin1Char
* chars
) const = 0;
543 virtual void finalize(char16_t
* chars
) const = 0;
546 * Callback used by memory reporting to ask the embedder how much memory an
547 * external string is keeping alive. The embedder is expected to return a
548 * value that corresponds to the size of the allocation that will be released
549 * by the finalizer callback above.
551 * Implementations of this callback MUST NOT do anything that can cause GC.
553 virtual size_t sizeOfBuffer(const JS::Latin1Char
* chars
,
554 mozilla::MallocSizeOf mallocSizeOf
) const = 0;
555 virtual size_t sizeOfBuffer(const char16_t
* chars
,
556 mozilla::MallocSizeOf mallocSizeOf
) const = 0;
561 #define GCREASONS(D) \
562 /* Reasons internal to the JS engine. */ \
564 D(EAGER_ALLOC_TRIGGER, 1) \
565 D(DESTROY_RUNTIME, 2) \
566 D(ROOTS_REMOVED, 3) \
568 D(TOO_MUCH_MALLOC, 5) \
569 D(ALLOC_TRIGGER, 6) \
571 D(COMPARTMENT_REVIVED, 8) \
573 D(OUT_OF_NURSERY, 10) \
574 D(EVICT_NURSERY, 11) \
575 D(SHARED_MEMORY_LIMIT, 13) \
576 D(EAGER_NURSERY_COLLECTION, 14) \
577 D(BG_TASK_FINISHED, 15) \
579 D(FULL_WHOLE_CELL_BUFFER, 17) \
580 D(FULL_GENERIC_BUFFER, 18) \
581 D(FULL_VALUE_BUFFER, 19) \
582 D(FULL_CELL_PTR_OBJ_BUFFER, 20) \
583 D(FULL_SLOT_BUFFER, 21) \
584 D(FULL_SHAPE_BUFFER, 22) \
585 D(TOO_MUCH_WASM_MEMORY, 23) \
586 D(DISABLE_GENERATIONAL_GC, 24) \
588 D(PREPARE_FOR_TRACING, 26) \
589 D(FULL_WASM_ANYREF_BUFFER, 27) \
590 D(FULL_CELL_PTR_STR_BUFFER, 28) \
591 D(TOO_MUCH_JIT_CODE, 29) \
592 D(FULL_CELL_PTR_BIGINT_BUFFER, 30) \
593 D(NURSERY_TRAILERS, 31) \
594 D(NURSERY_MALLOC_BUFFERS, 32) \
597 * Reasons from Firefox. \
599 * The JS engine attaches special meanings to some of these reasons. \
601 D(DOM_WINDOW_UTILS, FIRST_FIREFOX_REASON) \
602 D(COMPONENT_UTILS, 34) \
603 D(MEM_PRESSURE, 35) \
609 D(NSJSCONTEXT_DESTROY, 41) \
610 D(WORKER_SHUTDOWN, 42) \
611 D(SET_DOC_SHELL, 43) \
615 D(INTER_SLICE_GC, 47) \
617 D(FULL_GC_TIMER, 49) \
620 D(USER_INACTIVE, 52) \
621 D(XPCONNECT_SHUTDOWN, 53) \
624 D(DOM_TESTUTILS, 56) \
625 D(PREPARE_FOR_PAGELOAD, 57) \
627 /* Reasons reserved for embeddings. */ \
628 D(RESERVED1, FIRST_RESERVED_REASON) \
638 enum class GCReason
{
639 FIRST_FIREFOX_REASON
= 33,
640 FIRST_RESERVED_REASON
= 90,
642 #define MAKE_REASON(name, val) name = val,
643 GCREASONS(MAKE_REASON
)
649 * For telemetry, we want to keep a fixed max bucket size over time so we
650 * don't have to switch histograms. 100 is conservative; but the cost of extra
651 * buckets seems to be low while the cost of switching histograms is high.
653 NUM_TELEMETRY_REASONS
= 100
657 * Get a statically allocated C string explaining the given GC reason.
659 extern JS_PUBLIC_API
const char* ExplainGCReason(JS::GCReason reason
);
662 * Return true if the GC reason is internal to the JS engine.
664 extern JS_PUBLIC_API
bool InternalGCReason(JS::GCReason reason
);
669 * SpiderMonkey's GC is capable of performing a collection on an arbitrary
670 * subset of the zones in the system. This allows an embedding to minimize
671 * collection time by only collecting zones that have run code recently,
672 * ignoring the parts of the heap that are unlikely to have changed.
674 * When triggering a GC using one of the functions below, it is first necessary
675 * to select the zones to be collected. To do this, you can call
676 * PrepareZoneForGC on each zone, or you can call PrepareForFullGC to select
677 * all zones. Failing to select any zone is an error.
681 * Schedule the given zone to be collected as part of the next GC.
683 extern JS_PUBLIC_API
void PrepareZoneForGC(JSContext
* cx
, Zone
* zone
);
686 * Schedule all zones to be collected in the next GC.
688 extern JS_PUBLIC_API
void PrepareForFullGC(JSContext
* cx
);
691 * When performing an incremental GC, the zones that were selected for the
692 * previous incremental slice must be selected in subsequent slices as well.
693 * This function selects those slices automatically.
695 extern JS_PUBLIC_API
void PrepareForIncrementalGC(JSContext
* cx
);
698 * Returns true if any zone in the system has been scheduled for GC with one of
699 * the functions above or by the JS engine.
701 extern JS_PUBLIC_API
bool IsGCScheduled(JSContext
* cx
);
704 * Undoes the effect of the Prepare methods above. The given zone will not be
705 * collected in the next GC.
707 extern JS_PUBLIC_API
void SkipZoneForGC(JSContext
* cx
, Zone
* zone
);
710 * Non-Incremental GC:
712 * The following functions perform a non-incremental GC.
716 * Performs a non-incremental collection of all selected zones.
718 extern JS_PUBLIC_API
void NonIncrementalGC(JSContext
* cx
, JS::GCOptions options
,
724 * Incremental GC divides the full mark-and-sweep collection into multiple
725 * slices, allowing client JavaScript code to run between each slice. This
726 * allows interactive apps to avoid long collection pauses. Incremental GC does
727 * not make collection take less time, it merely spreads that time out so that
728 * the pauses are less noticable.
730 * For a collection to be carried out incrementally the following conditions
732 * - The collection must be run by calling JS::IncrementalGC() rather than
734 * - The GC parameter JSGC_INCREMENTAL_GC_ENABLED must be true.
736 * Note: Even if incremental GC is enabled and working correctly,
737 * non-incremental collections can still happen when low on memory.
741 * Begin an incremental collection and perform one slice worth of work. When
742 * this function returns, the collection may not be complete.
743 * IncrementalGCSlice() must be called repeatedly until
744 * !IsIncrementalGCInProgress(cx).
746 * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
747 * shorter than the requested interval.
749 extern JS_PUBLIC_API
void StartIncrementalGC(JSContext
* cx
,
750 JS::GCOptions options
,
752 const js::SliceBudget
& budget
);
755 * Perform a slice of an ongoing incremental collection. When this function
756 * returns, the collection may not be complete. It must be called repeatedly
757 * until !IsIncrementalGCInProgress(cx).
759 * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
760 * shorter than the requested interval.
762 extern JS_PUBLIC_API
void IncrementalGCSlice(JSContext
* cx
, GCReason reason
,
763 const js::SliceBudget
& budget
);
766 * Return whether an incremental GC has work to do on the foreground thread and
767 * would make progress if a slice was run now. If this returns false then the GC
768 * is waiting for background threads to finish their work and a slice started
769 * now would return immediately.
771 extern JS_PUBLIC_API
bool IncrementalGCHasForegroundWork(JSContext
* cx
);
774 * If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection
775 * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(cx),
776 * this is equivalent to NonIncrementalGC. When this function returns,
777 * IsIncrementalGCInProgress(cx) will always be false.
779 extern JS_PUBLIC_API
void FinishIncrementalGC(JSContext
* cx
, GCReason reason
);
782 * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and
783 * performs whatever work needs to be done to return the collector to its idle
784 * state. This may take an arbitrarily long time. When this function returns,
785 * IsIncrementalGCInProgress(cx) will always be false.
787 extern JS_PUBLIC_API
void AbortIncrementalGC(JSContext
* cx
);
791 // The `JS::dbg::GarbageCollectionEvent` class is essentially a view of the
792 // `js::gcstats::Statistics` data without the uber implementation-specific bits.
793 // It should generally be palatable for web developers.
794 class GarbageCollectionEvent
{
795 // The major GC number of the GC cycle this data pertains to.
796 uint64_t majorGCNumber_
;
798 // Reference to a non-owned, statically allocated C string. This is a very
799 // short reason explaining why a GC was triggered.
802 // Reference to a nullable, non-owned, statically allocated C string. If the
803 // collection was forced to be non-incremental, this is a short reason of
804 // why the GC could not perform an incremental collection.
805 const char* nonincrementalReason
;
807 // Represents a single slice of a possibly multi-slice incremental garbage
810 mozilla::TimeStamp startTimestamp
;
811 mozilla::TimeStamp endTimestamp
;
814 // The set of garbage collection slices that made up this GC cycle.
815 mozilla::Vector
<Collection
> collections
;
817 GarbageCollectionEvent(const GarbageCollectionEvent
& rhs
) = delete;
818 GarbageCollectionEvent
& operator=(const GarbageCollectionEvent
& rhs
) = delete;
821 explicit GarbageCollectionEvent(uint64_t majorGCNum
)
822 : majorGCNumber_(majorGCNum
),
824 nonincrementalReason(nullptr),
827 using Ptr
= js::UniquePtr
<GarbageCollectionEvent
>;
828 static Ptr
Create(JSRuntime
* rt
, ::js::gcstats::Statistics
& stats
,
829 uint64_t majorGCNumber
);
831 JSObject
* toJSObject(JSContext
* cx
) const;
833 uint64_t majorGCNumber() const { return majorGCNumber_
; }
840 * During GC, the GC is bracketed by GC_CYCLE_BEGIN/END callbacks. Each
841 * slice between those (whether an incremental or the sole non-incremental
842 * slice) is bracketed by GC_SLICE_BEGIN/GC_SLICE_END.
851 struct JS_PUBLIC_API GCDescription
{
854 JS::GCOptions options_
;
857 GCDescription(bool isZone
, bool isComplete
, JS::GCOptions options
,
860 isComplete_(isComplete
),
864 char16_t
* formatSliceMessage(JSContext
* cx
) const;
865 char16_t
* formatSummaryMessage(JSContext
* cx
) const;
867 mozilla::TimeStamp
startTime(JSContext
* cx
) const;
868 mozilla::TimeStamp
endTime(JSContext
* cx
) const;
869 mozilla::TimeStamp
lastSliceStart(JSContext
* cx
) const;
870 mozilla::TimeStamp
lastSliceEnd(JSContext
* cx
) const;
872 JS::UniqueChars
sliceToJSONProfiler(JSContext
* cx
) const;
873 JS::UniqueChars
formatJSONProfiler(JSContext
* cx
) const;
875 JS::dbg::GarbageCollectionEvent::Ptr
toGCEvent(JSContext
* cx
) const;
878 extern JS_PUBLIC_API UniqueChars
MinorGcToJSON(JSContext
* cx
);
880 typedef void (*GCSliceCallback
)(JSContext
* cx
, GCProgress progress
,
881 const GCDescription
& desc
);
884 * The GC slice callback is called at the beginning and end of each slice. This
885 * callback may be used for GC notifications as well as to perform additional
888 extern JS_PUBLIC_API GCSliceCallback
889 SetGCSliceCallback(JSContext
* cx
, GCSliceCallback callback
);
892 * Describes the progress of an observed nursery collection.
894 enum class GCNurseryProgress
{
896 * The nursery collection is starting.
898 GC_NURSERY_COLLECTION_START
,
900 * The nursery collection is ending.
902 GC_NURSERY_COLLECTION_END
906 * A nursery collection callback receives the progress of the nursery collection
907 * and the reason for the collection.
909 using GCNurseryCollectionCallback
= void (*)(JSContext
* cx
,
910 GCNurseryProgress progress
,
911 GCReason reason
, void* data
);
914 * Add and remove nursery collection callbacks for the given runtime. These will
915 * be called at the start and end of every nursery collection.
917 extern JS_PUBLIC_API
bool AddGCNurseryCollectionCallback(
918 JSContext
* cx
, GCNurseryCollectionCallback callback
, void* data
);
919 extern JS_PUBLIC_API
void RemoveGCNurseryCollectionCallback(
920 JSContext
* cx
, GCNurseryCollectionCallback callback
, void* data
);
922 typedef void (*DoCycleCollectionCallback
)(JSContext
* cx
);
925 * The purge gray callback is called after any COMPARTMENT_REVIVED GC in which
926 * the majority of compartments have been marked gray.
928 extern JS_PUBLIC_API DoCycleCollectionCallback
929 SetDoCycleCollectionCallback(JSContext
* cx
, DoCycleCollectionCallback callback
);
931 using CreateSliceBudgetCallback
= js::SliceBudget (*)(JS::GCReason reason
,
935 * Called when generating a GC slice budget. It allows the embedding to control
936 * the duration of slices and potentially check an interrupt flag as well. For
937 * internally triggered GCs, the given millis parameter is the JS engine's
938 * internal scheduling decision, which the embedding can choose to ignore.
939 * (Otherwise, it will be the value that was passed to eg
940 * JS::IncrementalGCSlice()).
942 extern JS_PUBLIC_API
void SetCreateGCSliceBudgetCallback(
943 JSContext
* cx
, CreateSliceBudgetCallback cb
);
946 * Incremental GC defaults to enabled, but may be disabled for testing or in
947 * embeddings that have not yet implemented barriers on their native classes.
948 * There is not currently a way to re-enable incremental GC once it has been
949 * disabled on the runtime.
951 extern JS_PUBLIC_API
void DisableIncrementalGC(JSContext
* cx
);
954 * Returns true if incremental GC is enabled. Simply having incremental GC
955 * enabled is not sufficient to ensure incremental collections are happening.
956 * See the comment "Incremental GC" above for reasons why incremental GC may be
957 * suppressed. Inspection of the "nonincremental reason" field of the
958 * GCDescription returned by GCSliceCallback may help narrow down the cause if
959 * collections are not happening incrementally when expected.
961 extern JS_PUBLIC_API
bool IsIncrementalGCEnabled(JSContext
* cx
);
964 * Returns true while an incremental GC is ongoing, both when actively
965 * collecting and between slices.
967 extern JS_PUBLIC_API
bool IsIncrementalGCInProgress(JSContext
* cx
);
970 * Returns true while an incremental GC is ongoing, both when actively
971 * collecting and between slices.
973 extern JS_PUBLIC_API
bool IsIncrementalGCInProgress(JSRuntime
* rt
);
976 * Returns true if the most recent GC ran incrementally.
978 extern JS_PUBLIC_API
bool WasIncrementalGC(JSRuntime
* rt
);
985 * Ensure that generational GC is disabled within some scope.
987 * This evicts the nursery and discards JIT code so it is not a lightweight
990 class JS_PUBLIC_API AutoDisableGenerationalGC
{
994 explicit AutoDisableGenerationalGC(JSContext
* cx
);
995 ~AutoDisableGenerationalGC();
999 * Returns true if generational allocation and collection is currently enabled
1000 * on the given runtime.
1002 extern JS_PUBLIC_API
bool IsGenerationalGCEnabled(JSRuntime
* rt
);
1005 * Enable or disable support for pretenuring allocations based on their
1008 extern JS_PUBLIC_API
void SetSiteBasedPretenuringEnabled(bool enable
);
1011 * Pass a subclass of this "abstract" class to callees to require that they
1012 * never GC. Subclasses can use assertions or the hazard analysis to ensure no
1015 class JS_PUBLIC_API AutoRequireNoGC
{
1017 AutoRequireNoGC() = default;
1018 ~AutoRequireNoGC() = default;
1022 * Diagnostic assert (see MOZ_DIAGNOSTIC_ASSERT) that GC cannot occur while this
1023 * class is live. This class does not disable the static rooting hazard
1026 * This works by entering a GC unsafe region, which is checked on allocation and
1029 class JS_PUBLIC_API AutoAssertNoGC
: public AutoRequireNoGC
{
1030 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1032 JSContext
* cx_
; // nullptr if inactive.
1035 // Nullptr here means get the context from TLS. It does not mean inactive
1036 // (though cx_ may end up nullptr, and thus inactive, if TLS has not yet been
1038 explicit AutoAssertNoGC(JSContext
* cx
= nullptr);
1039 AutoAssertNoGC(AutoAssertNoGC
&& other
) : cx_(other
.cx_
) {
1040 other
.cx_
= nullptr;
1047 explicit AutoAssertNoGC(JSContext
* cx
= nullptr) {}
1048 ~AutoAssertNoGC() {}
1055 * Disable the static rooting hazard analysis in the live region and assert in
1056 * debug builds if any allocation that could potentially trigger a GC occurs
1057 * while this guard object is live. This is most useful to help the exact
1058 * rooting hazard analysis in complex regions, since it cannot understand
1061 * Note: GC behavior is unpredictable even when deterministic and is generally
1062 * non-deterministic in practice. The fact that this guard has not
1063 * asserted is not a guarantee that a GC cannot happen in the guarded
1064 * region. As a rule, anyone performing a GC unsafe action should
1065 * understand the GC properties of all code in that region and ensure
1066 * that the hazard analysis is correct for that code, rather than relying
1070 class JS_PUBLIC_API AutoSuppressGCAnalysis
: public AutoAssertNoGC
{
1072 explicit AutoSuppressGCAnalysis(JSContext
* cx
= nullptr)
1073 : AutoAssertNoGC(cx
) {}
1074 } JS_HAZ_GC_SUPPRESSED
;
1076 class JS_PUBLIC_API AutoSuppressGCAnalysis
: public AutoRequireNoGC
{
1078 explicit AutoSuppressGCAnalysis(JSContext
* cx
= nullptr) {}
1079 } JS_HAZ_GC_SUPPRESSED
;
1083 * Assert that code is only ever called from a GC callback, disable the static
1084 * rooting hazard analysis and assert if any allocation that could potentially
1085 * trigger a GC occurs while this guard object is live.
1087 * This is useful to make the static analysis ignore code that runs in GC
1090 class JS_PUBLIC_API AutoAssertGCCallback
: public AutoSuppressGCAnalysis
{
1093 AutoAssertGCCallback();
1095 AutoAssertGCCallback() {}
1100 * Place AutoCheckCannotGC in scopes that you believe can never GC. These
1101 * annotations will be verified both dynamically via AutoAssertNoGC, and
1102 * statically with the rooting hazard analysis (implemented by making the
1103 * analysis consider AutoCheckCannotGC to be a GC pointer, and therefore
1104 * complain if it is live across a GC call.) It is useful when dealing with
1105 * internal pointers to GC things where the GC thing itself may not be present
1106 * for the static analysis: e.g. acquiring inline chars from a JSString* on the
1109 * We only do the assertion checking in DEBUG builds.
1112 class JS_PUBLIC_API AutoCheckCannotGC
: public AutoAssertNoGC
{
1114 explicit AutoCheckCannotGC(JSContext
* cx
= nullptr) : AutoAssertNoGC(cx
) {}
1115 # ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1116 AutoCheckCannotGC(const AutoCheckCannotGC
& other
)
1117 : AutoCheckCannotGC(other
.cx_
) {}
1119 AutoCheckCannotGC(const AutoCheckCannotGC
& other
) : AutoCheckCannotGC() {}
1121 AutoCheckCannotGC(AutoCheckCannotGC
&& other
)
1122 : AutoAssertNoGC(std::forward
<AutoAssertNoGC
>(other
)) {}
1124 class JS_PUBLIC_API AutoCheckCannotGC
: public AutoRequireNoGC
{
1126 explicit AutoCheckCannotGC(JSContext
* cx
= nullptr) {}
1127 AutoCheckCannotGC(const AutoCheckCannotGC
& other
) : AutoCheckCannotGC() {}
1128 AutoCheckCannotGC(AutoCheckCannotGC
&& other
) : AutoCheckCannotGC() {}
1131 } JS_HAZ_GC_INVALIDATED JS_HAZ_GC_REF
;
1133 extern JS_PUBLIC_API
void SetLowMemoryState(JSContext
* cx
, bool newState
);
1136 * Internal to Firefox.
1138 extern JS_PUBLIC_API
void NotifyGCRootsRemoved(JSContext
* cx
);
1140 } /* namespace JS */
1142 typedef void (*JSGCCallback
)(JSContext
* cx
, JSGCStatus status
,
1143 JS::GCReason reason
, void* data
);
1146 * Register externally maintained GC roots.
1148 * traceOp: the trace operation. For each root the implementation should call
1149 * JS::TraceEdge whenever the root contains a traceable thing.
1150 * data: the data argument to pass to each invocation of traceOp.
1152 extern JS_PUBLIC_API
bool JS_AddExtraGCRootsTracer(JSContext
* cx
,
1153 JSTraceDataOp traceOp
,
1156 /** Undo a call to JS_AddExtraGCRootsTracer. */
1157 extern JS_PUBLIC_API
void JS_RemoveExtraGCRootsTracer(JSContext
* cx
,
1158 JSTraceDataOp traceOp
,
1161 extern JS_PUBLIC_API
void JS_GC(JSContext
* cx
,
1162 JS::GCReason reason
= JS::GCReason::API
);
1164 extern JS_PUBLIC_API
void JS_MaybeGC(JSContext
* cx
);
1166 extern JS_PUBLIC_API
void JS_SetGCCallback(JSContext
* cx
, JSGCCallback cb
,
1169 extern JS_PUBLIC_API
void JS_SetObjectsTenuredCallback(
1170 JSContext
* cx
, JSObjectsTenuredCallback cb
, void* data
);
1172 extern JS_PUBLIC_API
bool JS_AddFinalizeCallback(JSContext
* cx
,
1173 JSFinalizeCallback cb
,
1176 extern JS_PUBLIC_API
void JS_RemoveFinalizeCallback(JSContext
* cx
,
1177 JSFinalizeCallback cb
);
1180 * Weak pointers and garbage collection
1182 * Weak pointers are by their nature not marked as part of garbage collection,
1183 * but they may need to be updated in two cases after a GC:
1185 * 1) Their referent was found not to be live and is about to be finalized
1186 * 2) Their referent has been moved by a compacting GC
1188 * To handle this, any part of the system that maintain weak pointers to
1189 * JavaScript GC things must register a callback with
1190 * JS_(Add,Remove)WeakPointer{ZoneGroup,Compartment}Callback(). This callback
1191 * must then call JS_UpdateWeakPointerAfterGC() on all weak pointers it knows
1194 * Since sweeping is incremental, we have several callbacks to avoid repeatedly
1195 * having to visit all embedder structures. The WeakPointerZonesCallback is
1196 * called once for each strongly connected group of zones, whereas the
1197 * WeakPointerCompartmentCallback is called once for each compartment that is
1198 * visited while sweeping. Structures that cannot contain references in more
1199 * than one compartment should sweep the relevant per-compartment structures
1200 * using the latter callback to minimizer per-slice overhead.
1202 * The argument to JS_UpdateWeakPointerAfterGC() is an in-out param. If the
1203 * referent is about to be finalized the pointer will be set to null. If the
1204 * referent has been moved then the pointer will be updated to point to the new
1207 * The return value of JS_UpdateWeakPointerAfterGC() indicates whether the
1208 * referent is still alive. If the referent is is about to be finalized, this
1209 * will return false.
1211 * Callers of this method are responsible for updating any state that is
1212 * dependent on the object's address. For example, if the object's address is
1213 * used as a key in a hashtable, then the object must be removed and
1214 * re-inserted with the correct hash.
1217 extern JS_PUBLIC_API
bool JS_AddWeakPointerZonesCallback(
1218 JSContext
* cx
, JSWeakPointerZonesCallback cb
, void* data
);
1220 extern JS_PUBLIC_API
void JS_RemoveWeakPointerZonesCallback(
1221 JSContext
* cx
, JSWeakPointerZonesCallback cb
);
1223 extern JS_PUBLIC_API
bool JS_AddWeakPointerCompartmentCallback(
1224 JSContext
* cx
, JSWeakPointerCompartmentCallback cb
, void* data
);
1226 extern JS_PUBLIC_API
void JS_RemoveWeakPointerCompartmentCallback(
1227 JSContext
* cx
, JSWeakPointerCompartmentCallback cb
);
1230 template <typename T
>
1234 extern JS_PUBLIC_API
bool JS_UpdateWeakPointerAfterGC(
1235 JSTracer
* trc
, JS::Heap
<JSObject
*>* objp
);
1237 extern JS_PUBLIC_API
bool JS_UpdateWeakPointerAfterGCUnbarriered(
1238 JSTracer
* trc
, JSObject
** objp
);
1240 extern JS_PUBLIC_API
void JS_SetGCParameter(JSContext
* cx
, JSGCParamKey key
,
1243 extern JS_PUBLIC_API
void JS_ResetGCParameter(JSContext
* cx
, JSGCParamKey key
);
1245 extern JS_PUBLIC_API
uint32_t JS_GetGCParameter(JSContext
* cx
,
1248 extern JS_PUBLIC_API
void JS_SetGCParametersBasedOnAvailableMemory(
1249 JSContext
* cx
, uint32_t availMemMB
);
1252 * Create a new JSString whose chars member refers to external memory, i.e.,
1253 * memory requiring application-specific finalization.
1255 extern JS_PUBLIC_API JSString
* JS_NewExternalStringLatin1(
1256 JSContext
* cx
, const JS::Latin1Char
* chars
, size_t length
,
1257 const JSExternalStringCallbacks
* callbacks
);
1258 extern JS_PUBLIC_API JSString
* JS_NewExternalUCString(
1259 JSContext
* cx
, const char16_t
* chars
, size_t length
,
1260 const JSExternalStringCallbacks
* callbacks
);
1263 * Create a new JSString whose chars member may refer to external memory.
1264 * If a new external string is allocated, |*allocatedExternal| is set to true.
1265 * Otherwise the returned string is either not an external string or an
1266 * external string allocated by a previous call and |*allocatedExternal| is set
1267 * to false. If |*allocatedExternal| is false, |fin| won't be called.
1269 extern JS_PUBLIC_API JSString
* JS_NewMaybeExternalStringLatin1(
1270 JSContext
* cx
, const JS::Latin1Char
* chars
, size_t length
,
1271 const JSExternalStringCallbacks
* callbacks
, bool* allocatedExternal
);
1272 extern JS_PUBLIC_API JSString
* JS_NewMaybeExternalUCString(
1273 JSContext
* cx
, const char16_t
* chars
, size_t length
,
1274 const JSExternalStringCallbacks
* callbacks
, bool* allocatedExternal
);
1277 * Similar to JS_NewMaybeExternalStringLatin1.
1279 * Create an external Latin1 string if the utf8 buffer contains only ASCII
1280 * chars, otherwise copy the chars into a non-external string.
1282 extern JS_PUBLIC_API JSString
* JS_NewMaybeExternalStringUTF8(
1283 JSContext
* cx
, const JS::UTF8Chars
& utf8
,
1284 const JSExternalStringCallbacks
* callbacks
, bool* allocatedExternal
);
1287 * Return the 'callbacks' arg passed to JS_NewExternalStringLatin1,
1288 * JS_NewExternalUCString, JS_NewMaybeExternalStringLatin1,
1289 * or JS_NewMaybeExternalUCString.
1291 extern JS_PUBLIC_API
const JSExternalStringCallbacks
*
1292 JS_GetExternalStringCallbacks(JSString
* str
);
1296 extern JS_PUBLIC_API GCReason
WantEagerMinorGC(JSRuntime
* rt
);
1298 extern JS_PUBLIC_API GCReason
WantEagerMajorGC(JSRuntime
* rt
);
1300 extern JS_PUBLIC_API
void MaybeRunNurseryCollection(JSRuntime
* rt
,
1301 JS::GCReason reason
);
1303 extern JS_PUBLIC_API
void RunNurseryCollection(
1304 JSRuntime
* rt
, JS::GCReason reason
,
1305 mozilla::TimeDuration aSinceLastMinorGC
);
1307 extern JS_PUBLIC_API
void SetHostCleanupFinalizationRegistryCallback(
1308 JSContext
* cx
, JSHostCleanupFinalizationRegistryCallback cb
, void* data
);
1311 * Clear kept alive objects in JS WeakRef.
1312 * https://tc39.es/proposal-weakrefs/#sec-clear-kept-objects
1314 extern JS_PUBLIC_API
void ClearKeptObjects(JSContext
* cx
);
1316 inline JS_PUBLIC_API
bool NeedGrayRootsForZone(Zone
* zoneArg
) {
1317 shadow::Zone
* zone
= shadow::Zone::from(zoneArg
);
1318 return zone
->isGCMarkingBlackAndGray() || zone
->isGCCompacting();
1321 extern JS_PUBLIC_API
bool AtomsZoneIsCollecting(JSRuntime
* runtime
);
1322 extern JS_PUBLIC_API
bool IsAtomsZone(Zone
* zone
);
1330 * Create an object providing access to the garbage collector's internal notion
1331 * of the current state of memory (both GC heap memory and GCthing-controlled
1334 extern JS_PUBLIC_API JSObject
* NewMemoryInfoObject(JSContext
* cx
);
1337 * Run the finalizer of a nursery-allocated JSObject that is known to be dead.
1339 * This is a dangerous operation - only use this if you know what you're doing!
1341 * This is used by the browser to implement nursery-allocated wrapper cached
1344 extern JS_PUBLIC_API
void FinalizeDeadNurseryObject(JSContext
* cx
,
1347 } /* namespace gc */
1348 } /* namespace js */
1352 # define JS_DEFAULT_ZEAL_FREQ 100
1354 extern JS_PUBLIC_API
void JS_GetGCZealBits(JSContext
* cx
, uint32_t* zealBits
,
1355 uint32_t* frequency
,
1356 uint32_t* nextScheduled
);
1358 extern JS_PUBLIC_API
void JS_SetGCZeal(JSContext
* cx
, uint8_t zeal
,
1359 uint32_t frequency
);
1361 extern JS_PUBLIC_API
void JS_UnsetGCZeal(JSContext
* cx
, uint8_t zeal
);
1363 extern JS_PUBLIC_API
void JS_ScheduleGC(JSContext
* cx
, uint32_t count
);
1367 #endif /* js_GCAPI_h */