Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef js_GCAPI_h
8 : #define js_GCAPI_h
9 :
10 : #include "mozilla/TimeStamp.h"
11 : #include "mozilla/Vector.h"
12 :
13 : #include "js/GCAnnotations.h"
14 : #include "js/HeapAPI.h"
15 : #include "js/UniquePtr.h"
16 : #include "js/Utility.h"
17 :
18 : namespace js {
19 : namespace gc {
20 : class GCRuntime;
21 : } // namespace gc
22 : namespace gcstats {
23 : struct Statistics;
24 : } // namespace gcstats
25 : } // namespace js
26 :
27 : typedef enum JSGCMode {
28 : /** Perform only global GCs. */
29 : JSGC_MODE_GLOBAL = 0,
30 :
31 : /** Perform per-zone GCs until too much garbage has accumulated. */
32 : JSGC_MODE_ZONE = 1,
33 :
34 : /**
35 : * Collect in short time slices rather than all at once. Implies
36 : * JSGC_MODE_ZONE.
37 : */
38 : JSGC_MODE_INCREMENTAL = 2
39 : } JSGCMode;
40 :
41 : /**
42 : * Kinds of js_GC invocation.
43 : */
44 : typedef enum JSGCInvocationKind {
45 : /* Normal invocation. */
46 : GC_NORMAL = 0,
47 :
48 : /* Minimize GC triggers and release empty GC chunks right away. */
49 : GC_SHRINK = 1
50 : } JSGCInvocationKind;
51 :
52 : namespace JS {
53 :
54 : #define GCREASONS(D) \
55 : /* Reasons internal to the JS engine */ \
56 : D(API) \
57 : D(EAGER_ALLOC_TRIGGER) \
58 : D(DESTROY_RUNTIME) \
59 : D(ROOTS_REMOVED) \
60 : D(LAST_DITCH) \
61 : D(TOO_MUCH_MALLOC) \
62 : D(ALLOC_TRIGGER) \
63 : D(DEBUG_GC) \
64 : D(COMPARTMENT_REVIVED) \
65 : D(RESET) \
66 : D(OUT_OF_NURSERY) \
67 : D(EVICT_NURSERY) \
68 : D(FULL_STORE_BUFFER) \
69 : D(SHARED_MEMORY_LIMIT) \
70 : D(UNUSED1) \
71 : D(INCREMENTAL_TOO_SLOW) \
72 : D(ABORT_GC) \
73 : \
74 : /* These are reserved for future use. */ \
75 : D(RESERVED0) \
76 : D(RESERVED1) \
77 : D(RESERVED2) \
78 : D(RESERVED3) \
79 : D(RESERVED4) \
80 : D(RESERVED5) \
81 : D(RESERVED6) \
82 : D(RESERVED7) \
83 : D(RESERVED8) \
84 : D(RESERVED9) \
85 : D(RESERVED10) \
86 : D(RESERVED11) \
87 : D(RESERVED12) \
88 : D(RESERVED13) \
89 : D(RESERVED14) \
90 : D(RESERVED15) \
91 : \
92 : /* Reasons from Firefox */ \
93 : D(DOM_WINDOW_UTILS) \
94 : D(COMPONENT_UTILS) \
95 : D(MEM_PRESSURE) \
96 : D(CC_WAITING) \
97 : D(CC_FORCED) \
98 : D(LOAD_END) \
99 : D(POST_COMPARTMENT) \
100 : D(PAGE_HIDE) \
101 : D(NSJSCONTEXT_DESTROY) \
102 : D(SET_NEW_DOCUMENT) \
103 : D(SET_DOC_SHELL) \
104 : D(DOM_UTILS) \
105 : D(DOM_IPC) \
106 : D(DOM_WORKER) \
107 : D(INTER_SLICE_GC) \
108 : D(REFRESH_FRAME) \
109 : D(FULL_GC_TIMER) \
110 : D(SHUTDOWN_CC) \
111 : D(UNUSED2) \
112 : D(USER_INACTIVE) \
113 : D(XPCONNECT_SHUTDOWN)
114 :
115 : namespace gcreason {
116 :
117 : /* GCReasons will end up looking like JSGC_MAYBEGC */
118 : enum Reason {
119 : #define MAKE_REASON(name) name,
120 : GCREASONS(MAKE_REASON)
121 : #undef MAKE_REASON
122 : NO_REASON,
123 : NUM_REASONS,
124 :
125 : /*
126 : * For telemetry, we want to keep a fixed max bucket size over time so we
127 : * don't have to switch histograms. 100 is conservative; as of this writing
128 : * there are 52. But the cost of extra buckets seems to be low while the
129 : * cost of switching histograms is high.
130 : */
131 : NUM_TELEMETRY_REASONS = 100
132 : };
133 :
134 : /**
135 : * Get a statically allocated C string explaining the given GC reason.
136 : */
137 : extern JS_PUBLIC_API(const char*)
138 : ExplainReason(JS::gcreason::Reason reason);
139 :
140 : } /* namespace gcreason */
141 :
142 : /*
143 : * Zone GC:
144 : *
145 : * SpiderMonkey's GC is capable of performing a collection on an arbitrary
146 : * subset of the zones in the system. This allows an embedding to minimize
147 : * collection time by only collecting zones that have run code recently,
148 : * ignoring the parts of the heap that are unlikely to have changed.
149 : *
150 : * When triggering a GC using one of the functions below, it is first necessary
151 : * to select the zones to be collected. To do this, you can call
152 : * PrepareZoneForGC on each zone, or you can call PrepareForFullGC to select
153 : * all zones. Failing to select any zone is an error.
154 : */
155 :
156 : /**
157 : * Schedule the given zone to be collected as part of the next GC.
158 : */
159 : extern JS_PUBLIC_API(void)
160 : PrepareZoneForGC(Zone* zone);
161 :
162 : /**
163 : * Schedule all zones to be collected in the next GC.
164 : */
165 : extern JS_PUBLIC_API(void)
166 : PrepareForFullGC(JSContext* cx);
167 :
168 : /**
169 : * When performing an incremental GC, the zones that were selected for the
170 : * previous incremental slice must be selected in subsequent slices as well.
171 : * This function selects those slices automatically.
172 : */
173 : extern JS_PUBLIC_API(void)
174 : PrepareForIncrementalGC(JSContext* cx);
175 :
176 : /**
177 : * Returns true if any zone in the system has been scheduled for GC with one of
178 : * the functions above or by the JS engine.
179 : */
180 : extern JS_PUBLIC_API(bool)
181 : IsGCScheduled(JSContext* cx);
182 :
183 : /**
184 : * Undoes the effect of the Prepare methods above. The given zone will not be
185 : * collected in the next GC.
186 : */
187 : extern JS_PUBLIC_API(void)
188 : SkipZoneForGC(Zone* zone);
189 :
190 : /*
191 : * Non-Incremental GC:
192 : *
193 : * The following functions perform a non-incremental GC.
194 : */
195 :
196 : /**
197 : * Performs a non-incremental collection of all selected zones.
198 : *
199 : * If the gckind argument is GC_NORMAL, then some objects that are unreachable
200 : * from the program may still be alive afterwards because of internal
201 : * references; if GC_SHRINK is passed then caches and other temporary references
202 : * to objects will be cleared and all unreferenced objects will be removed from
203 : * the system.
204 : */
205 : extern JS_PUBLIC_API(void)
206 : GCForReason(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason);
207 :
208 : /*
209 : * Incremental GC:
210 : *
211 : * Incremental GC divides the full mark-and-sweep collection into multiple
212 : * slices, allowing client JavaScript code to run between each slice. This
213 : * allows interactive apps to avoid long collection pauses. Incremental GC does
214 : * not make collection take less time, it merely spreads that time out so that
215 : * the pauses are less noticable.
216 : *
217 : * For a collection to be carried out incrementally the following conditions
218 : * must be met:
219 : * - The collection must be run by calling JS::IncrementalGC() rather than
220 : * JS_GC().
221 : * - The GC mode must have been set to JSGC_MODE_INCREMENTAL with
222 : * JS_SetGCParameter().
223 : *
224 : * Note: Even if incremental GC is enabled and working correctly,
225 : * non-incremental collections can still happen when low on memory.
226 : */
227 :
228 : /**
229 : * Begin an incremental collection and perform one slice worth of work. When
230 : * this function returns, the collection may not be complete.
231 : * IncrementalGCSlice() must be called repeatedly until
232 : * !IsIncrementalGCInProgress(cx).
233 : *
234 : * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
235 : * shorter than the requested interval.
236 : */
237 : extern JS_PUBLIC_API(void)
238 : StartIncrementalGC(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason,
239 : int64_t millis = 0);
240 :
241 : /**
242 : * Perform a slice of an ongoing incremental collection. When this function
243 : * returns, the collection may not be complete. It must be called repeatedly
244 : * until !IsIncrementalGCInProgress(cx).
245 : *
246 : * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
247 : * shorter than the requested interval.
248 : */
249 : extern JS_PUBLIC_API(void)
250 : IncrementalGCSlice(JSContext* cx, gcreason::Reason reason, int64_t millis = 0);
251 :
252 : /**
253 : * If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection
254 : * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(cx),
255 : * this is equivalent to GCForReason. When this function returns,
256 : * IsIncrementalGCInProgress(cx) will always be false.
257 : */
258 : extern JS_PUBLIC_API(void)
259 : FinishIncrementalGC(JSContext* cx, gcreason::Reason reason);
260 :
261 : /**
262 : * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and
263 : * performs whatever work needs to be done to return the collector to its idle
264 : * state. This may take an arbitrarily long time. When this function returns,
265 : * IsIncrementalGCInProgress(cx) will always be false.
266 : */
267 : extern JS_PUBLIC_API(void)
268 : AbortIncrementalGC(JSContext* cx);
269 :
270 : namespace dbg {
271 :
272 : // The `JS::dbg::GarbageCollectionEvent` class is essentially a view of the
273 : // `js::gcstats::Statistics` data without the uber implementation-specific bits.
274 : // It should generally be palatable for web developers.
275 0 : class GarbageCollectionEvent
276 : {
277 : // The major GC number of the GC cycle this data pertains to.
278 : uint64_t majorGCNumber_;
279 :
280 : // Reference to a non-owned, statically allocated C string. This is a very
281 : // short reason explaining why a GC was triggered.
282 : const char* reason;
283 :
284 : // Reference to a nullable, non-owned, statically allocated C string. If the
285 : // collection was forced to be non-incremental, this is a short reason of
286 : // why the GC could not perform an incremental collection.
287 : const char* nonincrementalReason;
288 :
289 : // Represents a single slice of a possibly multi-slice incremental garbage
290 : // collection.
291 0 : struct Collection {
292 : mozilla::TimeStamp startTimestamp;
293 : mozilla::TimeStamp endTimestamp;
294 : };
295 :
296 : // The set of garbage collection slices that made up this GC cycle.
297 : mozilla::Vector<Collection> collections;
298 :
299 : GarbageCollectionEvent(const GarbageCollectionEvent& rhs) = delete;
300 : GarbageCollectionEvent& operator=(const GarbageCollectionEvent& rhs) = delete;
301 :
302 : public:
303 0 : explicit GarbageCollectionEvent(uint64_t majorGCNum)
304 0 : : majorGCNumber_(majorGCNum)
305 : , reason(nullptr)
306 : , nonincrementalReason(nullptr)
307 0 : , collections()
308 0 : { }
309 :
310 : using Ptr = js::UniquePtr<GarbageCollectionEvent>;
311 : static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber);
312 :
313 : JSObject* toJSObject(JSContext* cx) const;
314 :
315 0 : uint64_t majorGCNumber() const { return majorGCNumber_; }
316 : };
317 :
318 : } // namespace dbg
319 :
320 : enum GCProgress {
321 : /*
322 : * During GC, the GC is bracketed by GC_CYCLE_BEGIN/END callbacks. Each
323 : * slice between those (whether an incremental or the sole non-incremental
324 : * slice) is bracketed by GC_SLICE_BEGIN/GC_SLICE_END.
325 : */
326 :
327 : GC_CYCLE_BEGIN,
328 : GC_SLICE_BEGIN,
329 : GC_SLICE_END,
330 : GC_CYCLE_END
331 : };
332 :
333 : struct JS_PUBLIC_API(GCDescription) {
334 : bool isZone_;
335 : bool isComplete_;
336 : JSGCInvocationKind invocationKind_;
337 : gcreason::Reason reason_;
338 :
339 6 : GCDescription(bool isZone, bool isComplete, JSGCInvocationKind kind, gcreason::Reason reason)
340 6 : : isZone_(isZone), isComplete_(isComplete), invocationKind_(kind), reason_(reason) {}
341 :
342 : char16_t* formatSliceMessage(JSContext* cx) const;
343 : char16_t* formatSummaryMessage(JSContext* cx) const;
344 : char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const;
345 :
346 : mozilla::TimeStamp startTime(JSContext* cx) const;
347 : mozilla::TimeStamp endTime(JSContext* cx) const;
348 : mozilla::TimeStamp lastSliceStart(JSContext* cx) const;
349 : mozilla::TimeStamp lastSliceEnd(JSContext* cx) const;
350 :
351 : JS::UniqueChars sliceToJSON(JSContext* cx) const;
352 : JS::UniqueChars summaryToJSON(JSContext* cx) const;
353 :
354 : JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const;
355 : };
356 :
357 : extern JS_PUBLIC_API(UniqueChars)
358 : MinorGcToJSON(JSContext* cx);
359 :
360 : typedef void
361 : (* GCSliceCallback)(JSContext* cx, GCProgress progress, const GCDescription& desc);
362 :
363 : /**
364 : * The GC slice callback is called at the beginning and end of each slice. This
365 : * callback may be used for GC notifications as well as to perform additional
366 : * marking.
367 : */
368 : extern JS_PUBLIC_API(GCSliceCallback)
369 : SetGCSliceCallback(JSContext* cx, GCSliceCallback callback);
370 :
371 : /**
372 : * Describes the progress of an observed nursery collection.
373 : */
374 : enum class GCNurseryProgress {
375 : /**
376 : * The nursery collection is starting.
377 : */
378 : GC_NURSERY_COLLECTION_START,
379 : /**
380 : * The nursery collection is ending.
381 : */
382 : GC_NURSERY_COLLECTION_END
383 : };
384 :
385 : /**
386 : * A nursery collection callback receives the progress of the nursery collection
387 : * and the reason for the collection.
388 : */
389 : using GCNurseryCollectionCallback = void(*)(JSContext* cx, GCNurseryProgress progress,
390 : gcreason::Reason reason);
391 :
392 : /**
393 : * Set the nursery collection callback for the given runtime. When set, it will
394 : * be called at the start and end of every nursery collection.
395 : */
396 : extern JS_PUBLIC_API(GCNurseryCollectionCallback)
397 : SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback);
398 :
399 : typedef void
400 : (* DoCycleCollectionCallback)(JSContext* cx);
401 :
402 : /**
403 : * The purge gray callback is called after any COMPARTMENT_REVIVED GC in which
404 : * the majority of compartments have been marked gray.
405 : */
406 : extern JS_PUBLIC_API(DoCycleCollectionCallback)
407 : SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback);
408 :
409 : /**
410 : * Incremental GC defaults to enabled, but may be disabled for testing or in
411 : * embeddings that have not yet implemented barriers on their native classes.
412 : * There is not currently a way to re-enable incremental GC once it has been
413 : * disabled on the runtime.
414 : */
415 : extern JS_PUBLIC_API(void)
416 : DisableIncrementalGC(JSContext* cx);
417 :
418 : /**
419 : * Returns true if incremental GC is enabled. Simply having incremental GC
420 : * enabled is not sufficient to ensure incremental collections are happening.
421 : * See the comment "Incremental GC" above for reasons why incremental GC may be
422 : * suppressed. Inspection of the "nonincremental reason" field of the
423 : * GCDescription returned by GCSliceCallback may help narrow down the cause if
424 : * collections are not happening incrementally when expected.
425 : */
426 : extern JS_PUBLIC_API(bool)
427 : IsIncrementalGCEnabled(JSContext* cx);
428 :
429 : /**
430 : * Returns true while an incremental GC is ongoing, both when actively
431 : * collecting and between slices.
432 : */
433 : extern JS_PUBLIC_API(bool)
434 : IsIncrementalGCInProgress(JSContext* cx);
435 :
436 : /**
437 : * Returns true while an incremental GC is ongoing, both when actively
438 : * collecting and between slices.
439 : */
440 : extern JS_PUBLIC_API(bool)
441 : IsIncrementalGCInProgress(JSRuntime* rt);
442 :
443 : /*
444 : * Returns true when writes to GC thing pointers (and reads from weak pointers)
445 : * must call an incremental barrier. This is generally only true when running
446 : * mutator code in-between GC slices. At other times, the barrier may be elided
447 : * for performance.
448 : */
449 : extern JS_PUBLIC_API(bool)
450 : IsIncrementalBarrierNeeded(JSContext* cx);
451 :
452 : /*
453 : * Notify the GC that a reference to a JSObject is about to be overwritten.
454 : * This method must be called if IsIncrementalBarrierNeeded.
455 : */
456 : extern JS_PUBLIC_API(void)
457 : IncrementalPreWriteBarrier(JSObject* obj);
458 :
459 : /*
460 : * Notify the GC that a weak reference to a GC thing has been read.
461 : * This method must be called if IsIncrementalBarrierNeeded.
462 : */
463 : extern JS_PUBLIC_API(void)
464 : IncrementalReadBarrier(GCCellPtr thing);
465 :
466 : /**
467 : * Returns true if the most recent GC ran incrementally.
468 : */
469 : extern JS_PUBLIC_API(bool)
470 : WasIncrementalGC(JSRuntime* rt);
471 :
472 : /*
473 : * Generational GC:
474 : *
475 : * Note: Generational GC is not yet enabled by default. The following class
476 : * is non-functional unless SpiderMonkey was configured with
477 : * --enable-gcgenerational.
478 : */
479 :
480 : /** Ensure that generational GC is disabled within some scope. */
481 : class JS_PUBLIC_API(AutoDisableGenerationalGC)
482 : {
483 : JSContext* cx;
484 :
485 : public:
486 : explicit AutoDisableGenerationalGC(JSContext* cx);
487 : ~AutoDisableGenerationalGC();
488 : };
489 :
490 : /**
491 : * Returns true if generational allocation and collection is currently enabled
492 : * on the given runtime.
493 : */
494 : extern JS_PUBLIC_API(bool)
495 : IsGenerationalGCEnabled(JSRuntime* rt);
496 :
497 : /**
498 : * Returns the GC's "number". This does not correspond directly to the number
499 : * of GCs that have been run, but is guaranteed to be monotonically increasing
500 : * with GC activity.
501 : */
502 : extern JS_PUBLIC_API(size_t)
503 : GetGCNumber();
504 :
505 : /**
506 : * Pass a subclass of this "abstract" class to callees to require that they
507 : * never GC. Subclasses can use assertions or the hazard analysis to ensure no
508 : * GC happens.
509 : */
510 : class JS_PUBLIC_API(AutoRequireNoGC)
511 : {
512 : protected:
513 3346583 : AutoRequireNoGC() {}
514 3347429 : ~AutoRequireNoGC() {}
515 : };
516 :
517 : /**
518 : * Diagnostic assert (see MOZ_DIAGNOSTIC_ASSERT) that GC cannot occur while this
519 : * class is live. This class does not disable the static rooting hazard
520 : * analysis.
521 : *
522 : * This works by entering a GC unsafe region, which is checked on allocation and
523 : * on GC.
524 : */
525 : class JS_PUBLIC_API(AutoAssertNoGC) : public AutoRequireNoGC
526 : {
527 : JSContext* cx_;
528 :
529 : public:
530 : explicit AutoAssertNoGC(JSContext* cx = nullptr);
531 : ~AutoAssertNoGC();
532 : };
533 :
534 : /**
535 : * Assert if an allocation of a GC thing occurs while this class is live. This
536 : * class does not disable the static rooting hazard analysis.
537 : */
538 : class JS_PUBLIC_API(AutoAssertNoAlloc)
539 : {
540 : #ifdef JS_DEBUG
541 : js::gc::GCRuntime* gc;
542 :
543 : public:
544 670075 : AutoAssertNoAlloc() : gc(nullptr) {}
545 : explicit AutoAssertNoAlloc(JSContext* cx);
546 : void disallowAlloc(JSRuntime* rt);
547 : ~AutoAssertNoAlloc();
548 : #else
549 : public:
550 : AutoAssertNoAlloc() {}
551 : explicit AutoAssertNoAlloc(JSContext* cx) {}
552 : void disallowAlloc(JSRuntime* rt) {}
553 : #endif
554 : };
555 :
556 : /**
557 : * Disable the static rooting hazard analysis in the live region and assert if
558 : * any allocation that could potentially trigger a GC occurs while this guard
559 : * object is live. This is most useful to help the exact rooting hazard analysis
560 : * in complex regions, since it cannot understand dataflow.
561 : *
562 : * Note: GC behavior is unpredictable even when deterministic and is generally
563 : * non-deterministic in practice. The fact that this guard has not
564 : * asserted is not a guarantee that a GC cannot happen in the guarded
565 : * region. As a rule, anyone performing a GC unsafe action should
566 : * understand the GC properties of all code in that region and ensure
567 : * that the hazard analysis is correct for that code, rather than relying
568 : * on this class.
569 : */
570 670042 : class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc
571 : {
572 : public:
573 670074 : AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {}
574 0 : explicit AutoSuppressGCAnalysis(JSContext* cx) : AutoAssertNoAlloc(cx) {}
575 : } JS_HAZ_GC_SUPPRESSED;
576 :
577 : /**
578 : * Assert that code is only ever called from a GC callback, disable the static
579 : * rooting hazard analysis and assert if any allocation that could potentially
580 : * trigger a GC occurs while this guard object is live.
581 : *
582 : * This is useful to make the static analysis ignore code that runs in GC
583 : * callbacks.
584 : */
585 61 : class JS_PUBLIC_API(AutoAssertGCCallback) : public AutoSuppressGCAnalysis
586 : {
587 : public:
588 : #ifdef DEBUG
589 : AutoAssertGCCallback();
590 : #else
591 : AutoAssertGCCallback() {}
592 : #endif
593 : };
594 :
595 : /**
596 : * Place AutoCheckCannotGC in scopes that you believe can never GC. These
597 : * annotations will be verified both dynamically via AutoAssertNoGC, and
598 : * statically with the rooting hazard analysis (implemented by making the
599 : * analysis consider AutoCheckCannotGC to be a GC pointer, and therefore
600 : * complain if it is live across a GC call.) It is useful when dealing with
601 : * internal pointers to GC things where the GC thing itself may not be present
602 : * for the static analysis: e.g. acquiring inline chars from a JSString* on the
603 : * heap.
604 : *
605 : * We only do the assertion checking in DEBUG builds.
606 : */
607 : #ifdef DEBUG
608 3372741 : class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertNoGC
609 : {
610 : public:
611 3372469 : explicit AutoCheckCannotGC(JSContext* cx = nullptr) : AutoAssertNoGC(cx) {}
612 : } JS_HAZ_GC_INVALIDATED;
613 : #else
614 : class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoRequireNoGC
615 : {
616 : public:
617 : explicit AutoCheckCannotGC(JSContext* cx = nullptr) {}
618 : } JS_HAZ_GC_INVALIDATED;
619 : #endif
620 :
621 : /**
622 : * Unsets the gray bit for anything reachable from |thing|. |kind| should not be
623 : * JS::TraceKind::Shape. |thing| should be non-null. The return value indicates
624 : * if anything was unmarked.
625 : */
626 : extern JS_FRIEND_API(bool)
627 : UnmarkGrayGCThingRecursively(GCCellPtr thing);
628 :
629 : } /* namespace JS */
630 :
631 : namespace js {
632 : namespace gc {
633 :
634 : static MOZ_ALWAYS_INLINE void
635 254077 : ExposeGCThingToActiveJS(JS::GCCellPtr thing)
636 : {
637 : // GC things residing in the nursery cannot be gray: they have no mark bits.
638 : // All live objects in the nursery are moved to tenured at the beginning of
639 : // each GC slice, so the gray marker never sees nursery things.
640 254077 : if (IsInsideNursery(thing.asCell()))
641 21107 : return;
642 :
643 : // There's nothing to do for permanent GC things that might be owned by
644 : // another runtime.
645 232970 : if (thing.mayBeOwnedByOtherRuntime())
646 3 : return;
647 :
648 232967 : if (IsIncrementalBarrierNeededOnTenuredGCThing(thing))
649 3277 : JS::IncrementalReadBarrier(thing);
650 229691 : else if (js::gc::detail::TenuredCellIsMarkedGray(thing.asCell()))
651 0 : JS::UnmarkGrayGCThingRecursively(thing);
652 :
653 232968 : MOZ_ASSERT(!js::gc::detail::TenuredCellIsMarkedGray(thing.asCell()));
654 : }
655 :
656 : template <typename T>
657 : extern JS_PUBLIC_API(bool)
658 : EdgeNeedsSweepUnbarrieredSlow(T* thingp);
659 :
660 : static MOZ_ALWAYS_INLINE bool
661 27970 : EdgeNeedsSweepUnbarriered(JSObject** objp)
662 : {
663 : // This function does not handle updating nursery pointers. Raw JSObject
664 : // pointers should be updated separately or replaced with
665 : // JS::Heap<JSObject*> which handles this automatically.
666 27970 : MOZ_ASSERT(!JS::CurrentThreadIsHeapMinorCollecting());
667 27971 : if (IsInsideNursery(reinterpret_cast<Cell*>(*objp)))
668 363 : return false;
669 :
670 27608 : auto zone = JS::shadow::Zone::asShadowZone(detail::GetGCThingZone(uintptr_t(*objp)));
671 27608 : if (!zone->isGCSweepingOrCompacting())
672 27608 : return false;
673 :
674 0 : return EdgeNeedsSweepUnbarrieredSlow(objp);
675 : }
676 :
677 : } /* namespace gc */
678 : } /* namespace js */
679 :
680 : namespace JS {
681 :
682 : /*
683 : * This should be called when an object that is marked gray is exposed to the JS
684 : * engine (by handing it to running JS code or writing it into live JS
685 : * data). During incremental GC, since the gray bits haven't been computed yet,
686 : * we conservatively mark the object black.
687 : */
688 : static MOZ_ALWAYS_INLINE void
689 197281 : ExposeObjectToActiveJS(JSObject* obj)
690 : {
691 197281 : MOZ_ASSERT(obj);
692 197281 : MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&obj));
693 197280 : js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj));
694 197281 : }
695 :
696 : static MOZ_ALWAYS_INLINE void
697 0 : ExposeScriptToActiveJS(JSScript* script)
698 : {
699 0 : MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&script));
700 0 : js::gc::ExposeGCThingToActiveJS(GCCellPtr(script));
701 0 : }
702 :
703 : /*
704 : * Internal to Firefox.
705 : */
706 : extern JS_FRIEND_API(void)
707 : NotifyGCRootsRemoved(JSContext* cx);
708 :
709 : /*
710 : * Internal to Firefox.
711 : */
712 : extern JS_FRIEND_API(void)
713 : NotifyDidPaint(JSContext* cx);
714 :
715 : } /* namespace JS */
716 :
717 : #endif /* js_GCAPI_h */
|