GCAPI.h 23 KB

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