/work/obj-fuzz/dist/include/js/GCAPI.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: set ts=8 sts=4 et sw=4 tw=99: |
3 | | * This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | /* |
8 | | * High-level interface to the JS garbage collector. |
9 | | */ |
10 | | |
11 | | #ifndef js_GCAPI_h |
12 | | #define js_GCAPI_h |
13 | | |
14 | | #include "mozilla/TimeStamp.h" |
15 | | #include "mozilla/Vector.h" |
16 | | |
17 | | #include "js/GCAnnotations.h" |
18 | | #include "js/TypeDecls.h" |
19 | | #include "js/UniquePtr.h" |
20 | | #include "js/Utility.h" |
21 | | |
22 | | struct JSFreeOp; |
23 | | |
24 | | #ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING |
25 | | #pragma GCC diagnostic push |
26 | | #pragma GCC diagnostic ignored "-Wattributes" |
27 | | #endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING |
28 | | |
29 | | class JS_PUBLIC_API(JSTracer); |
30 | | |
31 | | #ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING |
32 | | #pragma GCC diagnostic pop |
33 | | #endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING |
34 | | |
35 | | namespace js { |
36 | | namespace gc { |
37 | | class GCRuntime; |
38 | | } // namespace gc |
39 | | namespace gcstats { |
40 | | struct Statistics; |
41 | | } // namespace gcstats |
42 | | } // namespace js |
43 | | |
44 | | typedef enum JSGCMode { |
45 | | /** Perform only global GCs. */ |
46 | | JSGC_MODE_GLOBAL = 0, |
47 | | |
48 | | /** Perform per-zone GCs until too much garbage has accumulated. */ |
49 | | JSGC_MODE_ZONE = 1, |
50 | | |
51 | | /** |
52 | | * Collect in short time slices rather than all at once. Implies |
53 | | * JSGC_MODE_ZONE. |
54 | | */ |
55 | | JSGC_MODE_INCREMENTAL = 2 |
56 | | } JSGCMode; |
57 | | |
58 | | /** |
59 | | * Kinds of js_GC invocation. |
60 | | */ |
61 | | typedef enum JSGCInvocationKind { |
62 | | /* Normal invocation. */ |
63 | | GC_NORMAL = 0, |
64 | | |
65 | | /* Minimize GC triggers and release empty GC chunks right away. */ |
66 | | GC_SHRINK = 1 |
67 | | } JSGCInvocationKind; |
68 | | |
69 | | typedef enum JSGCParamKey { |
70 | | /** |
71 | | * Maximum nominal heap before last ditch GC. |
72 | | * |
73 | | * Soft limit on the number of bytes we are allowed to allocate in the GC |
74 | | * heap. Attempts to allocate gcthings over this limit will return null and |
75 | | * subsequently invoke the standard OOM machinery, independent of available |
76 | | * physical memory. |
77 | | * |
78 | | * Pref: javascript.options.mem.max |
79 | | * Default: 0xffffffff |
80 | | */ |
81 | | JSGC_MAX_BYTES = 0, |
82 | | |
83 | | /** |
84 | | * Initial value for the malloc bytes threshold. |
85 | | * |
86 | | * Pref: javascript.options.mem.high_water_mark |
87 | | * Default: TuningDefaults::MaxMallocBytes |
88 | | */ |
89 | | JSGC_MAX_MALLOC_BYTES = 1, |
90 | | |
91 | | /** |
92 | | * Maximum size of the generational GC nurseries. |
93 | | * |
94 | | * Pref: javascript.options.mem.nursery.max_kb |
95 | | * Default: JS::DefaultNurseryBytes |
96 | | */ |
97 | | JSGC_MAX_NURSERY_BYTES = 2, |
98 | | |
99 | | /** Amount of bytes allocated by the GC. */ |
100 | | JSGC_BYTES = 3, |
101 | | |
102 | | /** Number of times GC has been invoked. Includes both major and minor GC. */ |
103 | | JSGC_NUMBER = 4, |
104 | | |
105 | | /** |
106 | | * Select GC mode. |
107 | | * |
108 | | * See: JSGCMode in GCAPI.h |
109 | | * prefs: javascript.options.mem.gc_per_zone and |
110 | | * javascript.options.mem.gc_incremental. |
111 | | * Default: JSGC_MODE_INCREMENTAL |
112 | | */ |
113 | | JSGC_MODE = 6, |
114 | | |
115 | | /** Number of cached empty GC chunks. */ |
116 | | JSGC_UNUSED_CHUNKS = 7, |
117 | | |
118 | | /** Total number of allocated GC chunks. */ |
119 | | JSGC_TOTAL_CHUNKS = 8, |
120 | | |
121 | | /** |
122 | | * Max milliseconds to spend in an incremental GC slice. |
123 | | * |
124 | | * Pref: javascript.options.mem.gc_incremental_slice_ms |
125 | | * Default: DefaultTimeBudget. |
126 | | */ |
127 | | JSGC_SLICE_TIME_BUDGET = 9, |
128 | | |
129 | | /** |
130 | | * Maximum size the GC mark stack can grow to. |
131 | | * |
132 | | * Pref: none |
133 | | * Default: MarkStack::DefaultCapacity |
134 | | */ |
135 | | JSGC_MARK_STACK_LIMIT = 10, |
136 | | |
137 | | /** |
138 | | * GCs less than this far apart in time will be considered 'high-frequency |
139 | | * GCs'. |
140 | | * |
141 | | * See setGCLastBytes in jsgc.cpp. |
142 | | * |
143 | | * Pref: javascript.options.mem.gc_high_frequency_time_limit_ms |
144 | | * Default: HighFrequencyThreshold |
145 | | */ |
146 | | JSGC_HIGH_FREQUENCY_TIME_LIMIT = 11, |
147 | | |
148 | | /** |
149 | | * Start of dynamic heap growth. |
150 | | * |
151 | | * Pref: javascript.options.mem.gc_high_frequency_low_limit_mb |
152 | | * Default: HighFrequencyLowLimitBytes |
153 | | */ |
154 | | JSGC_HIGH_FREQUENCY_LOW_LIMIT = 12, |
155 | | |
156 | | /** |
157 | | * End of dynamic heap growth. |
158 | | * |
159 | | * Pref: javascript.options.mem.gc_high_frequency_high_limit_mb |
160 | | * Default: HighFrequencyHighLimitBytes |
161 | | */ |
162 | | JSGC_HIGH_FREQUENCY_HIGH_LIMIT = 13, |
163 | | |
164 | | /** |
165 | | * Upper bound of heap growth. |
166 | | * |
167 | | * Pref: javascript.options.mem.gc_high_frequency_heap_growth_max |
168 | | * Default: HighFrequencyHeapGrowthMax |
169 | | */ |
170 | | JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX = 14, |
171 | | |
172 | | /** |
173 | | * Lower bound of heap growth. |
174 | | * |
175 | | * Pref: javascript.options.mem.gc_high_frequency_heap_growth_min |
176 | | * Default: HighFrequencyHeapGrowthMin |
177 | | */ |
178 | | JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN = 15, |
179 | | |
180 | | /** |
181 | | * Heap growth for low frequency GCs. |
182 | | * |
183 | | * Pref: javascript.options.mem.gc_low_frequency_heap_growth |
184 | | * Default: LowFrequencyHeapGrowth |
185 | | */ |
186 | | JSGC_LOW_FREQUENCY_HEAP_GROWTH = 16, |
187 | | |
188 | | /** |
189 | | * If false, the heap growth factor is fixed at 3. If true, it is determined |
190 | | * based on whether GCs are high- or low- frequency. |
191 | | * |
192 | | * Pref: javascript.options.mem.gc_dynamic_heap_growth |
193 | | * Default: DynamicHeapGrowthEnabled |
194 | | */ |
195 | | JSGC_DYNAMIC_HEAP_GROWTH = 17, |
196 | | |
197 | | /** |
198 | | * If true, high-frequency GCs will use a longer mark slice. |
199 | | * |
200 | | * Pref: javascript.options.mem.gc_dynamic_mark_slice |
201 | | * Default: DynamicMarkSliceEnabled |
202 | | */ |
203 | | JSGC_DYNAMIC_MARK_SLICE = 18, |
204 | | |
205 | | /** |
206 | | * Lower limit after which we limit the heap growth. |
207 | | * |
208 | | * The base value used to compute zone->threshold.gcTriggerBytes(). When |
209 | | * usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the |
210 | | * zone may be scheduled for a GC, depending on the exact circumstances. |
211 | | * |
212 | | * Pref: javascript.options.mem.gc_allocation_threshold_mb |
213 | | * Default GCZoneAllocThresholdBase |
214 | | */ |
215 | | JSGC_ALLOCATION_THRESHOLD = 19, |
216 | | |
217 | | /** |
218 | | * We try to keep at least this many unused chunks in the free chunk pool at |
219 | | * all times, even after a shrinking GC. |
220 | | * |
221 | | * Pref: javascript.options.mem.gc_min_empty_chunk_count |
222 | | * Default: MinEmptyChunkCount |
223 | | */ |
224 | | JSGC_MIN_EMPTY_CHUNK_COUNT = 21, |
225 | | |
226 | | /** |
227 | | * We never keep more than this many unused chunks in the free chunk |
228 | | * pool. |
229 | | * |
230 | | * Pref: javascript.options.mem.gc_min_empty_chunk_count |
231 | | * Default: MinEmptyChunkCount |
232 | | */ |
233 | | JSGC_MAX_EMPTY_CHUNK_COUNT = 22, |
234 | | |
235 | | /** |
236 | | * Whether compacting GC is enabled. |
237 | | * |
238 | | * Pref: javascript.options.mem.gc_compacting |
239 | | * Default: CompactingEnabled |
240 | | */ |
241 | | JSGC_COMPACTING_ENABLED = 23, |
242 | | |
243 | | /** |
244 | | * Factor for triggering a GC based on JSGC_ALLOCATION_THRESHOLD |
245 | | * |
246 | | * Default: ZoneAllocThresholdFactorDefault |
247 | | * Pref: None |
248 | | */ |
249 | | JSGC_ALLOCATION_THRESHOLD_FACTOR = 25, |
250 | | |
251 | | /** |
252 | | * Factor for triggering a GC based on JSGC_ALLOCATION_THRESHOLD. |
253 | | * Used if another GC (in different zones) is already running. |
254 | | * |
255 | | * Default: ZoneAllocThresholdFactorAvoidInterruptDefault |
256 | | * Pref: None |
257 | | */ |
258 | | JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT = 26, |
259 | | |
260 | | /** |
261 | | * Attempt to run a minor GC in the idle time if the free space falls |
262 | | * below this threshold. |
263 | | * |
264 | | * Default: NurseryChunkUsableSize / 4 |
265 | | * Pref: None |
266 | | */ |
267 | | JSGC_NURSERY_FREE_THRESHOLD_FOR_IDLE_COLLECTION = 27, |
268 | | } JSGCParamKey; |
269 | | |
270 | | /* |
271 | | * Generic trace operation that calls JS::TraceEdge on each traceable thing's |
272 | | * location reachable from data. |
273 | | */ |
274 | | typedef void |
275 | | (* JSTraceDataOp)(JSTracer* trc, void* data); |
276 | | |
277 | | typedef enum JSGCStatus { |
278 | | JSGC_BEGIN, |
279 | | JSGC_END |
280 | | } JSGCStatus; |
281 | | |
282 | | typedef void |
283 | | (* JSGCCallback)(JSContext* cx, JSGCStatus status, void* data); |
284 | | |
285 | | typedef void |
286 | | (* JSObjectsTenuredCallback)(JSContext* cx, void* data); |
287 | | |
288 | | typedef enum JSFinalizeStatus { |
289 | | /** |
290 | | * Called when preparing to sweep a group of zones, before anything has been |
291 | | * swept. The collector will not yield to the mutator before calling the |
292 | | * callback with JSFINALIZE_GROUP_START status. |
293 | | */ |
294 | | JSFINALIZE_GROUP_PREPARE, |
295 | | |
296 | | /** |
297 | | * Called after preparing to sweep a group of zones. Weak references to |
298 | | * unmarked things have been removed at this point, but no GC things have |
299 | | * been swept. The collector may yield to the mutator after this point. |
300 | | */ |
301 | | JSFINALIZE_GROUP_START, |
302 | | |
303 | | /** |
304 | | * Called after sweeping a group of zones. All dead GC things have been |
305 | | * swept at this point. |
306 | | */ |
307 | | JSFINALIZE_GROUP_END, |
308 | | |
309 | | /** |
310 | | * Called at the end of collection when everything has been swept. |
311 | | */ |
312 | | JSFINALIZE_COLLECTION_END |
313 | | } JSFinalizeStatus; |
314 | | |
315 | | typedef void |
316 | | (* JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, void* data); |
317 | | |
318 | | typedef void |
319 | | (* JSWeakPointerZonesCallback)(JSContext* cx, void* data); |
320 | | |
321 | | typedef void |
322 | | (* JSWeakPointerCompartmentCallback)(JSContext* cx, JS::Compartment* comp, void* data); |
323 | | |
324 | | /** |
325 | | * Finalizes external strings created by JS_NewExternalString. The finalizer |
326 | | * can be called off the main thread. |
327 | | */ |
328 | | struct JSStringFinalizer { |
329 | | void (*finalize)(const JSStringFinalizer* fin, char16_t* chars); |
330 | | }; |
331 | | |
332 | | namespace JS { |
333 | | |
334 | | #define GCREASONS(D) \ |
335 | | /* Reasons internal to the JS engine */ \ |
336 | 0 | D(API) \ |
337 | 0 | D(EAGER_ALLOC_TRIGGER) \ |
338 | 0 | D(DESTROY_RUNTIME) \ |
339 | 0 | D(ROOTS_REMOVED) \ |
340 | 0 | D(LAST_DITCH) \ |
341 | 0 | D(TOO_MUCH_MALLOC) \ |
342 | 118 | D(ALLOC_TRIGGER) \ |
343 | 118 | D(DEBUG_GC) \ |
344 | 0 | D(COMPARTMENT_REVIVED) \ |
345 | 0 | D(RESET) \ |
346 | 0 | D(OUT_OF_NURSERY) \ |
347 | 0 | D(EVICT_NURSERY) \ |
348 | 0 | D(DELAYED_ATOMS_GC) \ |
349 | 0 | D(SHARED_MEMORY_LIMIT) \ |
350 | 0 | D(IDLE_TIME_COLLECTION) \ |
351 | 0 | D(INCREMENTAL_TOO_SLOW) \ |
352 | 0 | D(ABORT_GC) \ |
353 | 0 | D(FULL_WHOLE_CELL_BUFFER) \ |
354 | 0 | D(FULL_GENERIC_BUFFER) \ |
355 | 0 | D(FULL_VALUE_BUFFER) \ |
356 | 0 | D(FULL_CELL_PTR_BUFFER) \ |
357 | 0 | D(FULL_SLOT_BUFFER) \ |
358 | 0 | D(FULL_SHAPE_BUFFER) \ |
359 | 0 | D(TOO_MUCH_WASM_MEMORY) \ |
360 | 0 | \ |
361 | 0 | /* These are reserved for future use. */ \ |
362 | 0 | D(RESERVED0) \ |
363 | 0 | D(RESERVED1) \ |
364 | 0 | D(RESERVED2) \ |
365 | 0 | D(RESERVED3) \ |
366 | 0 | D(RESERVED4) \ |
367 | 0 | D(RESERVED5) \ |
368 | 0 | D(RESERVED6) \ |
369 | 0 | D(RESERVED7) \ |
370 | 0 | D(RESERVED8) \ |
371 | 0 | \ |
372 | 0 | /* Reasons from Firefox */ \ |
373 | 0 | D(DOM_WINDOW_UTILS) \ |
374 | 0 | D(COMPONENT_UTILS) \ |
375 | 0 | D(MEM_PRESSURE) \ |
376 | 0 | D(CC_WAITING) \ |
377 | 0 | D(CC_FORCED) \ |
378 | 0 | D(LOAD_END) \ |
379 | 0 | D(POST_COMPARTMENT) \ |
380 | 0 | D(PAGE_HIDE) \ |
381 | 0 | D(NSJSCONTEXT_DESTROY) \ |
382 | 0 | D(SET_NEW_DOCUMENT) \ |
383 | 0 | D(SET_DOC_SHELL) \ |
384 | 0 | D(DOM_UTILS) \ |
385 | 0 | D(DOM_IPC) \ |
386 | 0 | D(DOM_WORKER) \ |
387 | 0 | D(INTER_SLICE_GC) \ |
388 | 0 | D(UNUSED1) \ |
389 | 0 | D(FULL_GC_TIMER) \ |
390 | 0 | D(SHUTDOWN_CC) \ |
391 | 0 | D(UNUSED2) \ |
392 | 0 | D(USER_INACTIVE) \ |
393 | 0 | D(XPCONNECT_SHUTDOWN) \ |
394 | 0 | D(DOCSHELL) \ |
395 | 0 | D(HTML_PARSER) |
396 | | |
397 | | namespace gcreason { |
398 | | |
399 | | /* GCReasons will end up looking like JSGC_MAYBEGC */ |
400 | | enum Reason { |
401 | | #define MAKE_REASON(name) name, |
402 | | GCREASONS(MAKE_REASON) |
403 | | #undef MAKE_REASON |
404 | | NO_REASON, |
405 | | NUM_REASONS, |
406 | | |
407 | | /* |
408 | | * For telemetry, we want to keep a fixed max bucket size over time so we |
409 | | * don't have to switch histograms. 100 is conservative; as of this writing |
410 | | * there are 52. But the cost of extra buckets seems to be low while the |
411 | | * cost of switching histograms is high. |
412 | | */ |
413 | | NUM_TELEMETRY_REASONS = 100 |
414 | | }; |
415 | | |
416 | | /** |
417 | | * Get a statically allocated C string explaining the given GC reason. |
418 | | */ |
419 | | extern JS_PUBLIC_API(const char*) |
420 | | ExplainReason(JS::gcreason::Reason reason); |
421 | | |
422 | | } /* namespace gcreason */ |
423 | | |
424 | | /* |
425 | | * Zone GC: |
426 | | * |
427 | | * SpiderMonkey's GC is capable of performing a collection on an arbitrary |
428 | | * subset of the zones in the system. This allows an embedding to minimize |
429 | | * collection time by only collecting zones that have run code recently, |
430 | | * ignoring the parts of the heap that are unlikely to have changed. |
431 | | * |
432 | | * When triggering a GC using one of the functions below, it is first necessary |
433 | | * to select the zones to be collected. To do this, you can call |
434 | | * PrepareZoneForGC on each zone, or you can call PrepareForFullGC to select |
435 | | * all zones. Failing to select any zone is an error. |
436 | | */ |
437 | | |
438 | | /** |
439 | | * Schedule the given zone to be collected as part of the next GC. |
440 | | */ |
441 | | extern JS_PUBLIC_API(void) |
442 | | PrepareZoneForGC(Zone* zone); |
443 | | |
444 | | /** |
445 | | * Schedule all zones to be collected in the next GC. |
446 | | */ |
447 | | extern JS_PUBLIC_API(void) |
448 | | PrepareForFullGC(JSContext* cx); |
449 | | |
450 | | /** |
451 | | * When performing an incremental GC, the zones that were selected for the |
452 | | * previous incremental slice must be selected in subsequent slices as well. |
453 | | * This function selects those slices automatically. |
454 | | */ |
455 | | extern JS_PUBLIC_API(void) |
456 | | PrepareForIncrementalGC(JSContext* cx); |
457 | | |
458 | | /** |
459 | | * Returns true if any zone in the system has been scheduled for GC with one of |
460 | | * the functions above or by the JS engine. |
461 | | */ |
462 | | extern JS_PUBLIC_API(bool) |
463 | | IsGCScheduled(JSContext* cx); |
464 | | |
465 | | /** |
466 | | * Undoes the effect of the Prepare methods above. The given zone will not be |
467 | | * collected in the next GC. |
468 | | */ |
469 | | extern JS_PUBLIC_API(void) |
470 | | SkipZoneForGC(Zone* zone); |
471 | | |
472 | | /* |
473 | | * Non-Incremental GC: |
474 | | * |
475 | | * The following functions perform a non-incremental GC. |
476 | | */ |
477 | | |
478 | | /** |
479 | | * Performs a non-incremental collection of all selected zones. |
480 | | * |
481 | | * If the gckind argument is GC_NORMAL, then some objects that are unreachable |
482 | | * from the program may still be alive afterwards because of internal |
483 | | * references; if GC_SHRINK is passed then caches and other temporary references |
484 | | * to objects will be cleared and all unreferenced objects will be removed from |
485 | | * the system. |
486 | | */ |
487 | | extern JS_PUBLIC_API(void) |
488 | | NonIncrementalGC(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason); |
489 | | |
490 | | /* |
491 | | * Incremental GC: |
492 | | * |
493 | | * Incremental GC divides the full mark-and-sweep collection into multiple |
494 | | * slices, allowing client JavaScript code to run between each slice. This |
495 | | * allows interactive apps to avoid long collection pauses. Incremental GC does |
496 | | * not make collection take less time, it merely spreads that time out so that |
497 | | * the pauses are less noticable. |
498 | | * |
499 | | * For a collection to be carried out incrementally the following conditions |
500 | | * must be met: |
501 | | * - The collection must be run by calling JS::IncrementalGC() rather than |
502 | | * JS_GC(). |
503 | | * - The GC mode must have been set to JSGC_MODE_INCREMENTAL with |
504 | | * JS_SetGCParameter(). |
505 | | * |
506 | | * Note: Even if incremental GC is enabled and working correctly, |
507 | | * non-incremental collections can still happen when low on memory. |
508 | | */ |
509 | | |
510 | | /** |
511 | | * Begin an incremental collection and perform one slice worth of work. When |
512 | | * this function returns, the collection may not be complete. |
513 | | * IncrementalGCSlice() must be called repeatedly until |
514 | | * !IsIncrementalGCInProgress(cx). |
515 | | * |
516 | | * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or |
517 | | * shorter than the requested interval. |
518 | | */ |
519 | | extern JS_PUBLIC_API(void) |
520 | | StartIncrementalGC(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason, |
521 | | int64_t millis = 0); |
522 | | |
523 | | /** |
524 | | * Perform a slice of an ongoing incremental collection. When this function |
525 | | * returns, the collection may not be complete. It must be called repeatedly |
526 | | * until !IsIncrementalGCInProgress(cx). |
527 | | * |
528 | | * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or |
529 | | * shorter than the requested interval. |
530 | | */ |
531 | | extern JS_PUBLIC_API(void) |
532 | | IncrementalGCSlice(JSContext* cx, gcreason::Reason reason, int64_t millis = 0); |
533 | | |
534 | | /** |
535 | | * If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection |
536 | | * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(cx), |
537 | | * this is equivalent to NonIncrementalGC. When this function returns, |
538 | | * IsIncrementalGCInProgress(cx) will always be false. |
539 | | */ |
540 | | extern JS_PUBLIC_API(void) |
541 | | FinishIncrementalGC(JSContext* cx, gcreason::Reason reason); |
542 | | |
543 | | /** |
544 | | * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and |
545 | | * performs whatever work needs to be done to return the collector to its idle |
546 | | * state. This may take an arbitrarily long time. When this function returns, |
547 | | * IsIncrementalGCInProgress(cx) will always be false. |
548 | | */ |
549 | | extern JS_PUBLIC_API(void) |
550 | | AbortIncrementalGC(JSContext* cx); |
551 | | |
552 | | namespace dbg { |
553 | | |
554 | | // The `JS::dbg::GarbageCollectionEvent` class is essentially a view of the |
555 | | // `js::gcstats::Statistics` data without the uber implementation-specific bits. |
556 | | // It should generally be palatable for web developers. |
557 | | class GarbageCollectionEvent |
558 | | { |
559 | | // The major GC number of the GC cycle this data pertains to. |
560 | | uint64_t majorGCNumber_; |
561 | | |
562 | | // Reference to a non-owned, statically allocated C string. This is a very |
563 | | // short reason explaining why a GC was triggered. |
564 | | const char* reason; |
565 | | |
566 | | // Reference to a nullable, non-owned, statically allocated C string. If the |
567 | | // collection was forced to be non-incremental, this is a short reason of |
568 | | // why the GC could not perform an incremental collection. |
569 | | const char* nonincrementalReason; |
570 | | |
571 | | // Represents a single slice of a possibly multi-slice incremental garbage |
572 | | // collection. |
573 | | struct Collection { |
574 | | mozilla::TimeStamp startTimestamp; |
575 | | mozilla::TimeStamp endTimestamp; |
576 | | }; |
577 | | |
578 | | // The set of garbage collection slices that made up this GC cycle. |
579 | | mozilla::Vector<Collection> collections; |
580 | | |
581 | | GarbageCollectionEvent(const GarbageCollectionEvent& rhs) = delete; |
582 | | GarbageCollectionEvent& operator=(const GarbageCollectionEvent& rhs) = delete; |
583 | | |
584 | | public: |
585 | | explicit GarbageCollectionEvent(uint64_t majorGCNum) |
586 | | : majorGCNumber_(majorGCNum) |
587 | | , reason(nullptr) |
588 | | , nonincrementalReason(nullptr) |
589 | | , collections() |
590 | 0 | { } |
591 | | |
592 | | using Ptr = js::UniquePtr<GarbageCollectionEvent>; |
593 | | static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber); |
594 | | |
595 | | JSObject* toJSObject(JSContext* cx) const; |
596 | | |
597 | 0 | uint64_t majorGCNumber() const { return majorGCNumber_; } |
598 | | }; |
599 | | |
600 | | } // namespace dbg |
601 | | |
602 | | enum GCProgress { |
603 | | /* |
604 | | * During GC, the GC is bracketed by GC_CYCLE_BEGIN/END callbacks. Each |
605 | | * slice between those (whether an incremental or the sole non-incremental |
606 | | * slice) is bracketed by GC_SLICE_BEGIN/GC_SLICE_END. |
607 | | */ |
608 | | |
609 | | GC_CYCLE_BEGIN, |
610 | | GC_SLICE_BEGIN, |
611 | | GC_SLICE_END, |
612 | | GC_CYCLE_END |
613 | | }; |
614 | | |
615 | | struct JS_PUBLIC_API(GCDescription) { |
616 | | bool isZone_; |
617 | | bool isComplete_; |
618 | | JSGCInvocationKind invocationKind_; |
619 | | gcreason::Reason reason_; |
620 | | |
621 | | GCDescription(bool isZone, bool isComplete, JSGCInvocationKind kind, gcreason::Reason reason) |
622 | 0 | : isZone_(isZone), isComplete_(isComplete), invocationKind_(kind), reason_(reason) {} |
623 | | |
624 | | char16_t* formatSliceMessage(JSContext* cx) const; |
625 | | char16_t* formatSummaryMessage(JSContext* cx) const; |
626 | | char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const; |
627 | | |
628 | | mozilla::TimeStamp startTime(JSContext* cx) const; |
629 | | mozilla::TimeStamp endTime(JSContext* cx) const; |
630 | | mozilla::TimeStamp lastSliceStart(JSContext* cx) const; |
631 | | mozilla::TimeStamp lastSliceEnd(JSContext* cx) const; |
632 | | |
633 | | JS::UniqueChars sliceToJSON(JSContext* cx) const; |
634 | | JS::UniqueChars summaryToJSON(JSContext* cx) const; |
635 | | |
636 | | JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const; |
637 | | }; |
638 | | |
639 | | extern JS_PUBLIC_API(UniqueChars) |
640 | | MinorGcToJSON(JSContext* cx); |
641 | | |
642 | | typedef void |
643 | | (* GCSliceCallback)(JSContext* cx, GCProgress progress, const GCDescription& desc); |
644 | | |
645 | | /** |
646 | | * The GC slice callback is called at the beginning and end of each slice. This |
647 | | * callback may be used for GC notifications as well as to perform additional |
648 | | * marking. |
649 | | */ |
650 | | extern JS_PUBLIC_API(GCSliceCallback) |
651 | | SetGCSliceCallback(JSContext* cx, GCSliceCallback callback); |
652 | | |
653 | | /** |
654 | | * Describes the progress of an observed nursery collection. |
655 | | */ |
656 | | enum class GCNurseryProgress { |
657 | | /** |
658 | | * The nursery collection is starting. |
659 | | */ |
660 | | GC_NURSERY_COLLECTION_START, |
661 | | /** |
662 | | * The nursery collection is ending. |
663 | | */ |
664 | | GC_NURSERY_COLLECTION_END |
665 | | }; |
666 | | |
667 | | /** |
668 | | * A nursery collection callback receives the progress of the nursery collection |
669 | | * and the reason for the collection. |
670 | | */ |
671 | | using GCNurseryCollectionCallback = void(*)(JSContext* cx, GCNurseryProgress progress, |
672 | | gcreason::Reason reason); |
673 | | |
674 | | /** |
675 | | * Set the nursery collection callback for the given runtime. When set, it will |
676 | | * be called at the start and end of every nursery collection. |
677 | | */ |
678 | | extern JS_PUBLIC_API(GCNurseryCollectionCallback) |
679 | | SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback); |
680 | | |
681 | | typedef void |
682 | | (* DoCycleCollectionCallback)(JSContext* cx); |
683 | | |
684 | | /** |
685 | | * The purge gray callback is called after any COMPARTMENT_REVIVED GC in which |
686 | | * the majority of compartments have been marked gray. |
687 | | */ |
688 | | extern JS_PUBLIC_API(DoCycleCollectionCallback) |
689 | | SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback); |
690 | | |
691 | | /** |
692 | | * Incremental GC defaults to enabled, but may be disabled for testing or in |
693 | | * embeddings that have not yet implemented barriers on their native classes. |
694 | | * There is not currently a way to re-enable incremental GC once it has been |
695 | | * disabled on the runtime. |
696 | | */ |
697 | | extern JS_PUBLIC_API(void) |
698 | | DisableIncrementalGC(JSContext* cx); |
699 | | |
700 | | /** |
701 | | * Returns true if incremental GC is enabled. Simply having incremental GC |
702 | | * enabled is not sufficient to ensure incremental collections are happening. |
703 | | * See the comment "Incremental GC" above for reasons why incremental GC may be |
704 | | * suppressed. Inspection of the "nonincremental reason" field of the |
705 | | * GCDescription returned by GCSliceCallback may help narrow down the cause if |
706 | | * collections are not happening incrementally when expected. |
707 | | */ |
708 | | extern JS_PUBLIC_API(bool) |
709 | | IsIncrementalGCEnabled(JSContext* cx); |
710 | | |
711 | | /** |
712 | | * Returns true while an incremental GC is ongoing, both when actively |
713 | | * collecting and between slices. |
714 | | */ |
715 | | extern JS_PUBLIC_API(bool) |
716 | | IsIncrementalGCInProgress(JSContext* cx); |
717 | | |
718 | | /** |
719 | | * Returns true while an incremental GC is ongoing, both when actively |
720 | | * collecting and between slices. |
721 | | */ |
722 | | extern JS_PUBLIC_API(bool) |
723 | | IsIncrementalGCInProgress(JSRuntime* rt); |
724 | | |
725 | | /** |
726 | | * Returns true if the most recent GC ran incrementally. |
727 | | */ |
728 | | extern JS_PUBLIC_API(bool) |
729 | | WasIncrementalGC(JSRuntime* rt); |
730 | | |
731 | | /* |
732 | | * Generational GC: |
733 | | * |
734 | | * Note: Generational GC is not yet enabled by default. The following class |
735 | | * is non-functional unless SpiderMonkey was configured with |
736 | | * --enable-gcgenerational. |
737 | | */ |
738 | | |
739 | | /** Ensure that generational GC is disabled within some scope. */ |
740 | | class JS_PUBLIC_API(AutoDisableGenerationalGC) |
741 | | { |
742 | | JSContext* cx; |
743 | | |
744 | | public: |
745 | | explicit AutoDisableGenerationalGC(JSContext* cx); |
746 | | ~AutoDisableGenerationalGC(); |
747 | | }; |
748 | | |
749 | | /** |
750 | | * Returns true if generational allocation and collection is currently enabled |
751 | | * on the given runtime. |
752 | | */ |
753 | | extern JS_PUBLIC_API(bool) |
754 | | IsGenerationalGCEnabled(JSRuntime* rt); |
755 | | |
756 | | /** |
757 | | * Returns the GC's "number". This does not correspond directly to the number |
758 | | * of GCs that have been run, but is guaranteed to be monotonically increasing |
759 | | * with GC activity. |
760 | | */ |
761 | | extern JS_PUBLIC_API(size_t) |
762 | | GetGCNumber(); |
763 | | |
764 | | /** |
765 | | * Pass a subclass of this "abstract" class to callees to require that they |
766 | | * never GC. Subclasses can use assertions or the hazard analysis to ensure no |
767 | | * GC happens. |
768 | | */ |
769 | | class JS_PUBLIC_API(AutoRequireNoGC) |
770 | | { |
771 | | protected: |
772 | 0 | AutoRequireNoGC() {} |
773 | 0 | ~AutoRequireNoGC() {} |
774 | | }; |
775 | | |
776 | | /** |
777 | | * Diagnostic assert (see MOZ_DIAGNOSTIC_ASSERT) that GC cannot occur while this |
778 | | * class is live. This class does not disable the static rooting hazard |
779 | | * analysis. |
780 | | * |
781 | | * This works by entering a GC unsafe region, which is checked on allocation and |
782 | | * on GC. |
783 | | */ |
784 | | class JS_PUBLIC_API(AutoAssertNoGC) : public AutoRequireNoGC |
785 | | { |
786 | | #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED |
787 | | JSContext* cx_; |
788 | | |
789 | | public: |
790 | | // This gets the context from TLS if it is not passed in. |
791 | | explicit AutoAssertNoGC(JSContext* cx = nullptr); |
792 | | ~AutoAssertNoGC(); |
793 | | #else |
794 | | public: |
795 | | explicit AutoAssertNoGC(JSContext* cx = nullptr) {} |
796 | | ~AutoAssertNoGC() {} |
797 | | #endif |
798 | | }; |
799 | | |
800 | | /** |
801 | | * Disable the static rooting hazard analysis in the live region and assert in |
802 | | * debug builds if any allocation that could potentially trigger a GC occurs |
803 | | * while this guard object is live. This is most useful to help the exact |
804 | | * rooting hazard analysis in complex regions, since it cannot understand |
805 | | * dataflow. |
806 | | * |
807 | | * Note: GC behavior is unpredictable even when deterministic and is generally |
808 | | * non-deterministic in practice. The fact that this guard has not |
809 | | * asserted is not a guarantee that a GC cannot happen in the guarded |
810 | | * region. As a rule, anyone performing a GC unsafe action should |
811 | | * understand the GC properties of all code in that region and ensure |
812 | | * that the hazard analysis is correct for that code, rather than relying |
813 | | * on this class. |
814 | | */ |
815 | | #ifdef DEBUG |
816 | | class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoGC |
817 | | { |
818 | | public: |
819 | | explicit AutoSuppressGCAnalysis(JSContext* cx = nullptr) : AutoAssertNoGC(cx) {} |
820 | | } JS_HAZ_GC_SUPPRESSED; |
821 | | #else |
822 | | class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoRequireNoGC |
823 | | { |
824 | | public: |
825 | 0 | explicit AutoSuppressGCAnalysis(JSContext* cx = nullptr) {} |
826 | | } JS_HAZ_GC_SUPPRESSED; |
827 | | #endif |
828 | | |
829 | | /** |
830 | | * Assert that code is only ever called from a GC callback, disable the static |
831 | | * rooting hazard analysis and assert if any allocation that could potentially |
832 | | * trigger a GC occurs while this guard object is live. |
833 | | * |
834 | | * This is useful to make the static analysis ignore code that runs in GC |
835 | | * callbacks. |
836 | | */ |
837 | | class JS_PUBLIC_API(AutoAssertGCCallback) : public AutoSuppressGCAnalysis |
838 | | { |
839 | | public: |
840 | | #ifdef DEBUG |
841 | | AutoAssertGCCallback(); |
842 | | #else |
843 | 0 | AutoAssertGCCallback() {} |
844 | | #endif |
845 | | }; |
846 | | |
847 | | /** |
848 | | * Place AutoCheckCannotGC in scopes that you believe can never GC. These |
849 | | * annotations will be verified both dynamically via AutoAssertNoGC, and |
850 | | * statically with the rooting hazard analysis (implemented by making the |
851 | | * analysis consider AutoCheckCannotGC to be a GC pointer, and therefore |
852 | | * complain if it is live across a GC call.) It is useful when dealing with |
853 | | * internal pointers to GC things where the GC thing itself may not be present |
854 | | * for the static analysis: e.g. acquiring inline chars from a JSString* on the |
855 | | * heap. |
856 | | * |
857 | | * We only do the assertion checking in DEBUG builds. |
858 | | */ |
859 | | #ifdef DEBUG |
860 | | class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertNoGC |
861 | | { |
862 | | public: |
863 | | explicit AutoCheckCannotGC(JSContext* cx = nullptr) : AutoAssertNoGC(cx) {} |
864 | | } JS_HAZ_GC_INVALIDATED; |
865 | | #else |
866 | | class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoRequireNoGC |
867 | | { |
868 | | public: |
869 | 0 | explicit AutoCheckCannotGC(JSContext* cx = nullptr) {} |
870 | | } JS_HAZ_GC_INVALIDATED; |
871 | | #endif |
872 | | |
873 | | /* |
874 | | * Internal to Firefox. |
875 | | */ |
876 | | extern JS_FRIEND_API(void) |
877 | | NotifyGCRootsRemoved(JSContext* cx); |
878 | | |
879 | | } /* namespace JS */ |
880 | | |
881 | | /** |
882 | | * Register externally maintained GC roots. |
883 | | * |
884 | | * traceOp: the trace operation. For each root the implementation should call |
885 | | * JS::TraceEdge whenever the root contains a traceable thing. |
886 | | * data: the data argument to pass to each invocation of traceOp. |
887 | | */ |
888 | | extern JS_PUBLIC_API(bool) |
889 | | JS_AddExtraGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); |
890 | | |
891 | | /** Undo a call to JS_AddExtraGCRootsTracer. */ |
892 | | extern JS_PUBLIC_API(void) |
893 | | JS_RemoveExtraGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); |
894 | | |
895 | | extern JS_PUBLIC_API(void) |
896 | | JS_GC(JSContext* cx); |
897 | | |
898 | | extern JS_PUBLIC_API(void) |
899 | | JS_MaybeGC(JSContext* cx); |
900 | | |
901 | | extern JS_PUBLIC_API(void) |
902 | | JS_SetGCCallback(JSContext* cx, JSGCCallback cb, void* data); |
903 | | |
904 | | extern JS_PUBLIC_API(void) |
905 | | JS_SetObjectsTenuredCallback(JSContext* cx, JSObjectsTenuredCallback cb, |
906 | | void* data); |
907 | | |
908 | | extern JS_PUBLIC_API(bool) |
909 | | JS_AddFinalizeCallback(JSContext* cx, JSFinalizeCallback cb, void* data); |
910 | | |
911 | | extern JS_PUBLIC_API(void) |
912 | | JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb); |
913 | | |
914 | | /* |
915 | | * Weak pointers and garbage collection |
916 | | * |
917 | | * Weak pointers are by their nature not marked as part of garbage collection, |
918 | | * but they may need to be updated in two cases after a GC: |
919 | | * |
920 | | * 1) Their referent was found not to be live and is about to be finalized |
921 | | * 2) Their referent has been moved by a compacting GC |
922 | | * |
923 | | * To handle this, any part of the system that maintain weak pointers to |
924 | | * JavaScript GC things must register a callback with |
925 | | * JS_(Add,Remove)WeakPointer{ZoneGroup,Compartment}Callback(). This callback |
926 | | * must then call JS_UpdateWeakPointerAfterGC() on all weak pointers it knows |
927 | | * about. |
928 | | * |
929 | | * Since sweeping is incremental, we have several callbacks to avoid repeatedly |
930 | | * having to visit all embedder structures. The WeakPointerZonesCallback is |
931 | | * called once for each strongly connected group of zones, whereas the |
932 | | * WeakPointerCompartmentCallback is called once for each compartment that is |
933 | | * visited while sweeping. Structures that cannot contain references in more |
934 | | * than one compartment should sweep the relevant per-compartment structures |
935 | | * using the latter callback to minimizer per-slice overhead. |
936 | | * |
937 | | * The argument to JS_UpdateWeakPointerAfterGC() is an in-out param. If the |
938 | | * referent is about to be finalized the pointer will be set to null. If the |
939 | | * referent has been moved then the pointer will be updated to point to the new |
940 | | * location. |
941 | | * |
942 | | * Callers of this method are responsible for updating any state that is |
943 | | * dependent on the object's address. For example, if the object's address is |
944 | | * used as a key in a hashtable, then the object must be removed and |
945 | | * re-inserted with the correct hash. |
946 | | */ |
947 | | |
948 | | extern JS_PUBLIC_API(bool) |
949 | | JS_AddWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb, void* data); |
950 | | |
951 | | extern JS_PUBLIC_API(void) |
952 | | JS_RemoveWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb); |
953 | | |
954 | | extern JS_PUBLIC_API(bool) |
955 | | JS_AddWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb, |
956 | | void* data); |
957 | | |
958 | | extern JS_PUBLIC_API(void) |
959 | | JS_RemoveWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb); |
960 | | |
961 | | namespace JS { |
962 | | template <typename T> class Heap; |
963 | | } |
964 | | |
965 | | extern JS_PUBLIC_API(void) |
966 | | JS_UpdateWeakPointerAfterGC(JS::Heap<JSObject*>* objp); |
967 | | |
968 | | extern JS_PUBLIC_API(void) |
969 | | JS_UpdateWeakPointerAfterGCUnbarriered(JSObject** objp); |
970 | | |
971 | | extern JS_PUBLIC_API(void) |
972 | | JS_SetGCParameter(JSContext* cx, JSGCParamKey key, uint32_t value); |
973 | | |
974 | | extern JS_PUBLIC_API(void) |
975 | | JS_ResetGCParameter(JSContext* cx, JSGCParamKey key); |
976 | | |
977 | | extern JS_PUBLIC_API(uint32_t) |
978 | | JS_GetGCParameter(JSContext* cx, JSGCParamKey key); |
979 | | |
980 | | extern JS_PUBLIC_API(void) |
981 | | JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx, uint32_t availMem); |
982 | | |
983 | | /** |
984 | | * Create a new JSString whose chars member refers to external memory, i.e., |
985 | | * memory requiring application-specific finalization. |
986 | | */ |
987 | | extern JS_PUBLIC_API(JSString*) |
988 | | JS_NewExternalString(JSContext* cx, const char16_t* chars, size_t length, |
989 | | const JSStringFinalizer* fin); |
990 | | |
991 | | /** |
992 | | * Create a new JSString whose chars member may refer to external memory. |
993 | | * If a new external string is allocated, |*allocatedExternal| is set to true. |
994 | | * Otherwise the returned string is either not an external string or an |
995 | | * external string allocated by a previous call and |*allocatedExternal| is set |
996 | | * to false. If |*allocatedExternal| is false, |fin| won't be called. |
997 | | */ |
998 | | extern JS_PUBLIC_API(JSString*) |
999 | | JS_NewMaybeExternalString(JSContext* cx, const char16_t* chars, size_t length, |
1000 | | const JSStringFinalizer* fin, bool* allocatedExternal); |
1001 | | |
1002 | | /** |
1003 | | * Return whether 'str' was created with JS_NewExternalString or |
1004 | | * JS_NewExternalStringWithClosure. |
1005 | | */ |
1006 | | extern JS_PUBLIC_API(bool) |
1007 | | JS_IsExternalString(JSString* str); |
1008 | | |
1009 | | /** |
1010 | | * Return the 'fin' arg passed to JS_NewExternalString. |
1011 | | */ |
1012 | | extern JS_PUBLIC_API(const JSStringFinalizer*) |
1013 | | JS_GetExternalStringFinalizer(JSString* str); |
1014 | | |
1015 | | namespace JS { |
1016 | | |
1017 | | extern JS_PUBLIC_API(bool) |
1018 | | IsIdleGCTaskNeeded(JSRuntime* rt); |
1019 | | |
1020 | | extern JS_PUBLIC_API(void) |
1021 | | RunIdleTimeGCTask(JSRuntime* rt); |
1022 | | |
1023 | | } // namespace JS |
1024 | | |
1025 | | namespace js { |
1026 | | namespace gc { |
1027 | | |
1028 | | /** |
1029 | | * Create an object providing access to the garbage collector's internal notion |
1030 | | * of the current state of memory (both GC heap memory and GCthing-controlled |
1031 | | * malloc memory. |
1032 | | */ |
1033 | | extern JS_PUBLIC_API(JSObject*) |
1034 | | NewMemoryInfoObject(JSContext* cx); |
1035 | | |
1036 | | } /* namespace gc */ |
1037 | | } /* namespace js */ |
1038 | | |
1039 | | #endif /* js_GCAPI_h */ |