Bug 1832850 - Part 5: Move the allocateObject definition into gc/Nursery.h r=jandem
[gecko.git] / js / src / gc / Nursery.h
blob0877d334e3db049613d8d54bb25d3b7c464de491
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sw=2 et tw=80:
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
6 * You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #ifndef gc_Nursery_h
9 #define gc_Nursery_h
11 #include "mozilla/EnumeratedArray.h"
12 #include "mozilla/TimeStamp.h"
14 #include "gc/Heap.h"
15 #include "gc/MallocedBlockCache.h"
16 #include "gc/Pretenuring.h"
17 #include "js/AllocPolicy.h"
18 #include "js/Class.h"
19 #include "js/GCAPI.h"
20 #include "js/TypeDecls.h"
21 #include "js/UniquePtr.h"
22 #include "js/Vector.h"
24 #define FOR_EACH_NURSERY_PROFILE_TIME(_) \
25 /* Key Header text */ \
26 _(Total, "total") \
27 _(TraceValues, "mkVals") \
28 _(TraceCells, "mkClls") \
29 _(TraceSlots, "mkSlts") \
30 _(TraceWholeCells, "mcWCll") \
31 _(TraceGenericEntries, "mkGnrc") \
32 _(CheckHashTables, "ckTbls") \
33 _(MarkRuntime, "mkRntm") \
34 _(MarkDebugger, "mkDbgr") \
35 _(SweepCaches, "swpCch") \
36 _(CollectToObjFP, "colObj") \
37 _(CollectToStrFP, "colStr") \
38 _(ObjectsTenuredCallback, "tenCB") \
39 _(Sweep, "sweep") \
40 _(UpdateJitActivations, "updtIn") \
41 _(FreeMallocedBuffers, "frSlts") \
42 _(FreeTrailerBlocks, "frTrBs") \
43 _(ClearStoreBuffer, "clrSB") \
44 _(ClearNursery, "clear") \
45 _(PurgeStringToAtomCache, "pStoA") \
46 _(Pretenure, "pretnr")
48 template <typename T>
49 class SharedMem;
51 namespace js {
53 struct StringStats;
54 class AutoLockGCBgAlloc;
55 class ObjectElements;
56 struct NurseryChunk;
57 class HeapSlot;
58 class JSONPrinter;
59 class MapObject;
60 class SetObject;
61 class JS_PUBLIC_API Sprinter;
63 namespace gc {
64 class AutoGCSession;
65 struct Cell;
66 class GCSchedulingTunables;
67 class TenuringTracer;
68 } // namespace gc
70 // Classes with JSCLASS_SKIP_NURSERY_FINALIZE or Wrapper classes with
71 // CROSS_COMPARTMENT flags will not have their finalizer called if they are
72 // nursery allocated and not promoted to the tenured heap. The finalizers for
73 // these classes must do nothing except free data which was allocated via
74 // Nursery::allocateBuffer.
75 inline bool CanNurseryAllocateFinalizedClass(const JSClass* const clasp) {
76 MOZ_ASSERT(clasp->hasFinalize());
77 return clasp->flags & JSCLASS_SKIP_NURSERY_FINALIZE;
80 class alignas(TypicalCacheLineSize) Nursery {
81 public:
82 static const size_t Alignment = gc::ChunkSize;
83 static const size_t ChunkShift = gc::ChunkShift;
85 using BufferRelocationOverlay = void*;
86 using BufferSet = HashSet<void*, PointerHasher<void*>, SystemAllocPolicy>;
88 explicit Nursery(gc::GCRuntime* gc);
89 ~Nursery();
91 [[nodiscard]] bool init(AutoLockGCBgAlloc& lock);
93 // Number of allocated (ready to use) chunks.
94 unsigned allocatedChunkCount() const { return chunks_.length(); }
96 // Total number of chunks and the capacity of the nursery. Chunks will be
97 // lazilly allocated and added to the chunks array up to this limit, after
98 // that the nursery must be collected, this limit may be raised during
99 // collection.
100 unsigned maxChunkCount() const {
101 MOZ_ASSERT(capacity());
102 return HowMany(capacity(), gc::ChunkSize);
105 void enable();
106 void disable();
107 bool isEnabled() const { return capacity() != 0; }
109 void enableStrings();
110 void disableStrings();
111 bool canAllocateStrings() const { return canAllocateStrings_; }
113 void enableBigInts();
114 void disableBigInts();
115 bool canAllocateBigInts() const { return canAllocateBigInts_; }
117 // Return true if no allocations have been made since the last collection.
118 bool isEmpty() const;
120 // Check whether an arbitrary pointer is within the nursery. This is
121 // slower than IsInsideNursery(Cell*), but works on all types of pointers.
122 MOZ_ALWAYS_INLINE bool isInside(gc::Cell* cellp) const = delete;
123 MOZ_ALWAYS_INLINE bool isInside(const void* p) const {
124 for (auto chunk : chunks_) {
125 if (uintptr_t(p) - uintptr_t(chunk) < gc::ChunkSize) {
126 return true;
129 return false;
132 template <typename T>
133 inline bool isInside(const SharedMem<T>& p) const;
135 // Allocate and return a pointer to a new GC object with its |slots|
136 // pointer pre-filled. Returns nullptr if the Nursery is full.
137 void* allocateObject(gc::AllocSite* site, size_t size, const JSClass* clasp) {
138 MOZ_ASSERT_IF(clasp->hasFinalize() && !clasp->isProxyObject(),
139 CanNurseryAllocateFinalizedClass(clasp));
140 return allocateCell(site, size, JS::TraceKind::Object);
143 void* allocateBigInt(gc::AllocSite* site, size_t size) {
144 MOZ_ASSERT(canAllocateBigInts());
145 return allocateCell(site, size, JS::TraceKind::BigInt);
147 void* allocateString(gc::AllocSite* site, size_t size) {
148 MOZ_ASSERT(canAllocateStrings());
149 return allocateCell(site, size, JS::TraceKind::String);
152 // Allocate and return a pointer to a new GC thing. Returns nullptr if the
153 // Nursery is full.
154 void* allocateCell(gc::AllocSite* site, size_t size, JS::TraceKind kind);
156 static size_t nurseryCellHeaderSize() {
157 return sizeof(gc::NurseryCellHeader);
160 // Allocate a buffer for a given zone, using the nursery if possible.
161 void* allocateBuffer(JS::Zone* zone, size_t nbytes);
163 // Allocate a buffer for a given object, using the nursery if possible and
164 // obj is in the nursery.
165 void* allocateBuffer(JS::Zone* zone, JSObject* obj, size_t nbytes);
167 // Allocate a buffer for a given object, always using the nursery if obj is
168 // in the nursery. The requested size must be less than or equal to
169 // MaxNurseryBufferSize.
170 void* allocateBufferSameLocation(JSObject* obj, size_t nbytes);
172 // Allocate a zero-initialized buffer for a given zone, using the nursery if
173 // possible. If the buffer isn't allocated in the nursery, the given arena is
174 // used.
175 void* allocateZeroedBuffer(JS::Zone* zone, size_t nbytes,
176 arena_id_t arena = js::MallocArena);
178 // Allocate a zero-initialized buffer for a given object, using the nursery if
179 // possible and obj is in the nursery. If the buffer isn't allocated in the
180 // nursery, the given arena is used.
181 void* allocateZeroedBuffer(JSObject* obj, size_t nbytes,
182 arena_id_t arena = js::MallocArena);
184 // Resize an existing buffer.
185 void* reallocateBuffer(JS::Zone* zone, gc::Cell* cell, void* oldBuffer,
186 size_t oldBytes, size_t newBytes);
188 // Allocate a digits buffer for a given BigInt, using the nursery if possible
189 // and |bi| is in the nursery.
190 void* allocateBuffer(JS::BigInt* bi, size_t nbytes);
192 // Free an object buffer.
193 void freeBuffer(void* buffer, size_t nbytes);
195 // The maximum number of bytes allowed to reside in nursery buffers.
196 static const size_t MaxNurseryBufferSize = 1024;
198 // Do a minor collection.
199 void collect(JS::GCOptions options, JS::GCReason reason);
201 // If the thing at |*ref| in the Nursery has been forwarded, set |*ref| to
202 // the new location and return true. Otherwise return false and leave
203 // |*ref| unset.
204 [[nodiscard]] MOZ_ALWAYS_INLINE static bool getForwardedPointer(
205 js::gc::Cell** ref);
207 // Forward a slots/elements pointer stored in an Ion frame.
208 void forwardBufferPointer(uintptr_t* pSlotsElems);
210 inline void maybeSetForwardingPointer(JSTracer* trc, void* oldData,
211 void* newData, bool direct);
212 inline void setForwardingPointerWhileTenuring(void* oldData, void* newData,
213 bool direct);
215 // Register a malloced buffer that is held by a nursery object, which
216 // should be freed at the end of a minor GC. Buffers are unregistered when
217 // their owning objects are tenured.
218 [[nodiscard]] bool registerMallocedBuffer(void* buffer, size_t nbytes);
220 // Mark a malloced buffer as no longer needing to be freed.
221 void removeMallocedBuffer(void* buffer, size_t nbytes) {
222 MOZ_ASSERT(mallocedBuffers.has(buffer));
223 MOZ_ASSERT(nbytes > 0);
224 MOZ_ASSERT(mallocedBufferBytes >= nbytes);
225 mallocedBuffers.remove(buffer);
226 mallocedBufferBytes -= nbytes;
229 // Mark a malloced buffer as no longer needing to be freed during minor
230 // GC. There's no need to account for the size here since all remaining
231 // buffers will soon be freed.
232 void removeMallocedBufferDuringMinorGC(void* buffer) {
233 MOZ_ASSERT(JS::RuntimeHeapIsMinorCollecting());
234 MOZ_ASSERT(mallocedBuffers.has(buffer));
235 mallocedBuffers.remove(buffer);
238 [[nodiscard]] bool addedUniqueIdToCell(gc::Cell* cell) {
239 MOZ_ASSERT(IsInsideNursery(cell));
240 MOZ_ASSERT(isEnabled());
241 return cellsWithUid_.append(cell);
244 size_t sizeOfMallocedBuffers(mozilla::MallocSizeOf mallocSizeOf) const {
245 size_t total = 0;
246 for (BufferSet::Range r = mallocedBuffers.all(); !r.empty(); r.popFront()) {
247 total += mallocSizeOf(r.front());
249 total += mallocedBuffers.shallowSizeOfExcludingThis(mallocSizeOf);
250 return total;
253 // Wasm "trailer" (C++-heap-allocated) blocks.
255 // All involved blocks are allocated/deallocated via this nursery's
256 // `mallocedBlockCache_`. Hence we must store both the block address and
257 // its freelist ID, wrapped up in a PointerAndUint7.
259 // Trailer blocks registered here are added to `trailersAdded_`. Those that
260 // are later deregistered as a result of `obj_moved` calls that indicate
261 // tenuring, should be added to `trailersRemoved_`.
263 // Unfortunately ::unregisterTrailer cannot be allowed to OOM. To get
264 // around this we rely on the observation that all deregistered blocks
265 // should previously have been registered, so the deregistered set can never
266 // be larger than the registered set. Hence ::registerTrailer effectively
267 // preallocates space in `trailersRemoved_` so as to ensure that, in the
268 // worst case, all registered blocks can be handed to ::unregisterTrailer
269 // without needing to resize `trailersRemoved_` in ::unregisterTrailer.
271 // The downside is that most of the space in `trailersRemoved_` is wasted in
272 // the case where there are few blocks deregistered. This is unfortunate
273 // but it's hard to see how to avoid it.
275 // At the end of a minor collection, all blocks in the set `trailersAdded_ -
276 // trailersRemoved_[0 .. trailersRemovedUsed_ - 1]` are handed back to the
277 // `mallocedBlockCache_`.
278 [[nodiscard]] bool registerTrailer(PointerAndUint7 blockAndListID,
279 size_t nBytes) {
280 MOZ_ASSERT(trailersAdded_.length() == trailersRemoved_.length());
281 MOZ_ASSERT(nBytes > 0);
282 if (MOZ_UNLIKELY(!trailersAdded_.append(blockAndListID))) {
283 return false;
285 if (MOZ_UNLIKELY(!trailersRemoved_.append(nullptr))) {
286 trailersAdded_.popBack();
287 return false;
290 // This is a clone of the logic in ::registerMallocedBuffer. It may be
291 // that some other heuristic is better, once we know more about the
292 // typical behaviour of wasm-GC applications.
293 trailerBytes_ += nBytes;
294 if (MOZ_UNLIKELY(trailerBytes_ > capacity() * 8)) {
295 requestMinorGC(JS::GCReason::NURSERY_TRAILERS);
297 return true;
300 void unregisterTrailer(void* block) {
301 MOZ_ASSERT(trailersRemovedUsed_ < trailersRemoved_.length());
302 trailersRemoved_[trailersRemovedUsed_] = block;
303 trailersRemovedUsed_++;
306 size_t sizeOfTrailerBlockSets(mozilla::MallocSizeOf mallocSizeOf) const {
307 return trailersAdded_.sizeOfExcludingThis(mallocSizeOf) +
308 trailersRemoved_.sizeOfExcludingThis(mallocSizeOf);
311 // The number of bytes from the start position to the end of the nursery.
312 // pass maxChunkCount(), allocatedChunkCount() or chunkCountLimit()
313 // to calculate the nursery size, current lazy-allocated size or nursery
314 // limit respectively.
315 size_t spaceToEnd(unsigned chunkCount) const;
317 size_t capacity() const { return capacity_; }
318 size_t committed() const { return spaceToEnd(allocatedChunkCount()); }
320 // Used and free space both include chunk headers for that part of the
321 // nursery.
323 // usedSpace() + freeSpace() == capacity()
325 MOZ_ALWAYS_INLINE size_t usedSpace() const {
326 return capacity() - freeSpace();
328 MOZ_ALWAYS_INLINE size_t freeSpace() const {
329 MOZ_ASSERT(isEnabled());
330 MOZ_ASSERT(currentEnd_ - position_ <= NurseryChunkUsableSize);
331 MOZ_ASSERT(currentChunk_ < maxChunkCount());
332 return (currentEnd_ - position_) +
333 (maxChunkCount() - currentChunk_ - 1) * gc::ChunkSize;
336 #ifdef JS_GC_ZEAL
337 void enterZealMode();
338 void leaveZealMode();
339 #endif
341 // Write profile time JSON on JSONPrinter.
342 void renderProfileJSON(JSONPrinter& json) const;
344 // Print header line for profile times.
345 void printProfileHeader();
347 // Print total profile times on shutdown.
348 void printTotalProfileTimes();
350 void* addressOfPosition() const { return (void**)&position_; }
351 const void* addressOfCurrentEnd() const { return (void**)&currentEnd_; }
352 const void* addressOfCurrentStringEnd() const {
353 return (void*)&currentStringEnd_;
355 const void* addressOfCurrentBigIntEnd() const {
356 return (void*)&currentBigIntEnd_;
358 void* addressOfNurseryAllocatedSites() {
359 return pretenuringNursery.addressOfAllocatedSites();
362 void requestMinorGC(JS::GCReason reason) const;
364 bool minorGCRequested() const {
365 return minorGCTriggerReason_ != JS::GCReason::NO_REASON;
367 JS::GCReason minorGCTriggerReason() const { return minorGCTriggerReason_; }
368 void clearMinorGCRequest() {
369 minorGCTriggerReason_ = JS::GCReason::NO_REASON;
372 bool shouldCollect() const;
373 bool isNearlyFull() const;
374 bool isUnderused() const;
376 bool enableProfiling() const { return enableProfiling_; }
378 bool addMapWithNurseryMemory(MapObject* obj) {
379 MOZ_ASSERT_IF(!mapsWithNurseryMemory_.empty(),
380 mapsWithNurseryMemory_.back() != obj);
381 return mapsWithNurseryMemory_.append(obj);
383 bool addSetWithNurseryMemory(SetObject* obj) {
384 MOZ_ASSERT_IF(!setsWithNurseryMemory_.empty(),
385 setsWithNurseryMemory_.back() != obj);
386 return setsWithNurseryMemory_.append(obj);
389 // The amount of space in the mapped nursery available to allocations.
390 static const size_t NurseryChunkUsableSize =
391 gc::ChunkSize - sizeof(gc::ChunkBase);
393 void joinDecommitTask();
395 mozilla::TimeStamp collectionStartTime() {
396 return startTimes_[ProfileKey::Total];
399 bool canCreateAllocSite() { return pretenuringNursery.canCreateAllocSite(); }
400 void noteAllocSiteCreated() { pretenuringNursery.noteAllocSiteCreated(); }
401 bool reportPretenuring() const { return reportPretenuring_; }
402 void maybeStopPretenuring(gc::GCRuntime* gc) {
403 pretenuringNursery.maybeStopPretenuring(gc);
406 // Round a size in bytes to the nearest valid nursery size.
407 static size_t roundSize(size_t size);
409 // The malloc'd block cache.
410 gc::MallocedBlockCache& mallocedBlockCache() { return mallocedBlockCache_; }
411 size_t sizeOfMallocedBlockCache(mozilla::MallocSizeOf mallocSizeOf) const {
412 return mallocedBlockCache_.sizeOfExcludingThis(mallocSizeOf);
415 private:
416 // Fields used during allocation fast path are grouped first:
418 // Pointer to the first unallocated byte in the nursery.
419 uintptr_t position_;
421 // Pointer to the last byte of space in the current chunk.
422 uintptr_t currentEnd_;
424 // Pointer to the last byte of space in the current chunk, or nullptr if we
425 // are not allocating strings in the nursery.
426 uintptr_t currentStringEnd_;
428 // Pointer to the last byte of space in the current chunk, or nullptr if we
429 // are not allocating BigInts in the nursery.
430 uintptr_t currentBigIntEnd_;
432 // Other fields not necessarily used during allocation follow:
434 gc::GCRuntime* const gc;
436 // Vector of allocated chunks to allocate from.
437 Vector<NurseryChunk*, 0, SystemAllocPolicy> chunks_;
439 // The index of the chunk that is currently being allocated from.
440 uint32_t currentChunk_;
442 // These fields refer to the beginning of the nursery. They're normally 0
443 // and chunk(0).start() respectively. Except when a generational GC zeal
444 // mode is active, then they may be arbitrary (see Nursery::clear()).
445 uint32_t currentStartChunk_;
446 uintptr_t currentStartPosition_;
448 // The current nursery capacity measured in bytes. It may grow up to this
449 // value without a collection, allocating chunks on demand. This limit may be
450 // changed by maybeResizeNursery() each collection. It includes chunk headers.
451 size_t capacity_;
453 gc::PretenuringNursery pretenuringNursery;
455 mozilla::TimeDuration timeInChunkAlloc_;
457 // Report minor collections taking at least this long, if enabled.
458 bool enableProfiling_;
459 bool profileWorkers_;
460 mozilla::TimeDuration profileThreshold_;
462 // Whether we will nursery-allocate strings.
463 bool canAllocateStrings_;
465 // Whether we will nursery-allocate BigInts.
466 bool canAllocateBigInts_;
468 // Report how many strings were deduplicated.
469 bool reportDeduplications_;
471 // Whether to report information on pretenuring, and if so the allocation
472 // threshold at which to report details of each allocation site.
473 bool reportPretenuring_;
474 size_t reportPretenuringThreshold_;
476 // Whether and why a collection of this nursery has been requested. This is
477 // mutable as it is set by the store buffer, which otherwise cannot modify
478 // anything in the nursery.
479 mutable JS::GCReason minorGCTriggerReason_;
481 // Profiling data.
483 enum class ProfileKey {
484 #define DEFINE_TIME_KEY(name, text) name,
485 FOR_EACH_NURSERY_PROFILE_TIME(DEFINE_TIME_KEY)
486 #undef DEFINE_TIME_KEY
487 KeyCount
490 using ProfileTimes =
491 mozilla::EnumeratedArray<ProfileKey, ProfileKey::KeyCount,
492 mozilla::TimeStamp>;
493 using ProfileDurations =
494 mozilla::EnumeratedArray<ProfileKey, ProfileKey::KeyCount,
495 mozilla::TimeDuration>;
497 ProfileTimes startTimes_;
498 ProfileDurations profileDurations_;
499 ProfileDurations totalDurations_;
501 // Data about the previous collection.
502 struct PreviousGC {
503 JS::GCReason reason = JS::GCReason::NO_REASON;
504 size_t nurseryCapacity = 0;
505 size_t nurseryCommitted = 0;
506 size_t nurseryUsedBytes = 0;
507 size_t nurseryUsedChunkCount = 0;
508 size_t tenuredBytes = 0;
509 size_t tenuredCells = 0;
510 mozilla::TimeStamp endTime;
512 PreviousGC previousGC;
514 bool hasRecentGrowthData;
515 double smoothedTargetSize;
517 // Calculate the promotion rate of the most recent minor GC.
518 // The valid_for_tenuring parameter is used to return whether this
519 // promotion rate is accurate enough (the nursery was full enough) to be
520 // used for tenuring and other decisions.
522 // Must only be called if the previousGC data is initialised.
523 double calcPromotionRate(bool* validForTenuring) const;
525 // The set of externally malloced buffers potentially kept live by objects
526 // stored in the nursery. Any external buffers that do not belong to a
527 // tenured thing at the end of a minor GC must be freed.
528 BufferSet mallocedBuffers;
529 size_t mallocedBufferBytes = 0;
531 // Wasm "trailer" (C++-heap-allocated) blocks. See comments above on
532 // ::registerTrailer and ::unregisterTrailer.
533 Vector<PointerAndUint7, 0, SystemAllocPolicy> trailersAdded_;
534 Vector<void*, 0, SystemAllocPolicy> trailersRemoved_;
535 size_t trailersRemovedUsed_ = 0;
536 size_t trailerBytes_ = 0;
538 void freeTrailerBlocks();
540 // During a collection most hoisted slot and element buffers indicate their
541 // new location with a forwarding pointer at the base. This does not work
542 // for buffers whose length is less than pointer width, or when different
543 // buffers might overlap each other. For these, an entry in the following
544 // table is used.
545 typedef HashMap<void*, void*, PointerHasher<void*>, SystemAllocPolicy>
546 ForwardedBufferMap;
547 ForwardedBufferMap forwardedBuffers;
549 // When we assign a unique id to cell in the nursery, that almost always
550 // means that the cell will be in a hash table, and thus, held live,
551 // automatically moving the uid from the nursery to its new home in
552 // tenured. It is possible, if rare, for an object that acquired a uid to
553 // be dead before the next collection, in which case we need to know to
554 // remove it when we sweep.
556 // Note: we store the pointers as Cell* here, resulting in an ugly cast in
557 // sweep. This is because this structure is used to help implement
558 // stable object hashing and we have to break the cycle somehow.
559 using CellsWithUniqueIdVector = Vector<gc::Cell*, 8, SystemAllocPolicy>;
560 CellsWithUniqueIdVector cellsWithUid_;
562 // Lists of map and set objects allocated in the nursery or with iterators
563 // allocated there. Such objects need to be swept after minor GC.
564 Vector<MapObject*, 0, SystemAllocPolicy> mapsWithNurseryMemory_;
565 Vector<SetObject*, 0, SystemAllocPolicy> setsWithNurseryMemory_;
567 UniquePtr<NurseryDecommitTask> decommitTask;
569 // A cache of small C++-heap allocated blocks associated with this Nursery.
570 // This provided so as to provide cheap allocation/deallocation of
571 // out-of-line storage areas as used by WasmStructObject and
572 // WasmArrayObject, although the mechanism is general and not specific to
573 // these object types. Regarding lifetimes, because the cache holds only
574 // blocks that are not currently in use, it can be flushed at any point with
575 // no correctness impact, only a performance impact.
576 gc::MallocedBlockCache mallocedBlockCache_;
578 #ifdef JS_GC_ZEAL
579 struct Canary;
580 Canary* lastCanary_;
581 #endif
583 NurseryChunk& chunk(unsigned index) const { return *chunks_[index]; }
585 // Set the current chunk. This updates the currentChunk_, position_
586 // currentEnd_ and currentStringEnd_ values as approprite. It'll also
587 // poison the chunk, either a portion of the chunk if it is already the
588 // current chunk, or the whole chunk if fullPoison is true or it is not
589 // the current chunk.
590 void setCurrentChunk(unsigned chunkno);
592 bool initFirstChunk(AutoLockGCBgAlloc& lock);
594 // extent is advisory, it will be ignored in sub-chunk and generational zeal
595 // modes. It will be clamped to Min(NurseryChunkUsableSize, capacity_).
596 void poisonAndInitCurrentChunk(size_t extent = gc::ChunkSize);
598 void setCurrentEnd();
599 void setStartPosition();
601 // Allocate the next chunk, or the first chunk for initialization.
602 // Callers will probably want to call setCurrentChunk(0) next.
603 [[nodiscard]] bool allocateNextChunk(unsigned chunkno,
604 AutoLockGCBgAlloc& lock);
606 MOZ_ALWAYS_INLINE uintptr_t currentEnd() const;
608 uintptr_t position() const { return position_; }
610 MOZ_ALWAYS_INLINE bool isSubChunkMode() const;
612 JSRuntime* runtime() const;
613 gcstats::Statistics& stats() const;
615 const js::gc::GCSchedulingTunables& tunables() const;
617 void updateAllZoneAllocFlags();
618 void updateAllocFlagsForZone(JS::Zone* zone);
619 void discardJitCodeForZone(JS::Zone* zone);
621 // Common internal allocator function.
622 void* allocate(size_t size);
624 void* moveToNextChunkAndAllocate(size_t size);
626 #ifdef JS_GC_ZEAL
627 void writeCanary(uintptr_t address);
628 #endif
630 struct CollectionResult {
631 size_t tenuredBytes;
632 size_t tenuredCells;
634 CollectionResult doCollection(gc::AutoGCSession& session,
635 JS::GCOptions options, JS::GCReason reason);
636 void traceRoots(gc::AutoGCSession& session, gc::TenuringTracer& mover);
638 size_t doPretenuring(JSRuntime* rt, JS::GCReason reason,
639 bool validPromotionRate, double promotionRate);
641 // Handle relocation of slots/elements pointers stored in Ion frames.
642 inline void setForwardingPointer(void* oldData, void* newData, bool direct);
644 inline void setDirectForwardingPointer(void* oldData, void* newData);
645 void setIndirectForwardingPointer(void* oldData, void* newData);
647 inline void setSlotsForwardingPointer(HeapSlot* oldSlots, HeapSlot* newSlots,
648 uint32_t nslots);
649 inline void setElementsForwardingPointer(ObjectElements* oldHeader,
650 ObjectElements* newHeader,
651 uint32_t capacity);
653 #ifdef DEBUG
654 bool checkForwardingPointerLocation(void* ptr, bool expectedInside);
655 #endif
657 // Updates pointers to nursery objects that have been tenured and discards
658 // pointers to objects that have been freed.
659 void sweep();
661 // Reset the current chunk and position after a minor collection. Also poison
662 // the nursery on debug & nightly builds.
663 void clear();
665 void sweepMapAndSetObjects();
667 // Change the allocable space provided by the nursery.
668 void maybeResizeNursery(JS::GCOptions options, JS::GCReason reason);
669 size_t targetSize(JS::GCOptions options, JS::GCReason reason);
670 void clearRecentGrowthData();
671 void growAllocableSpace(size_t newCapacity);
672 void shrinkAllocableSpace(size_t newCapacity);
673 void minimizeAllocableSpace();
675 // Free the chunks starting at firstFreeChunk until the end of the chunks
676 // vector. Shrinks the vector but does not update maxChunkCount().
677 void freeChunksFrom(unsigned firstFreeChunk);
679 void sendTelemetry(JS::GCReason reason, mozilla::TimeDuration totalTime,
680 bool wasEmpty, double promotionRate,
681 size_t sitesPretenured);
683 void printCollectionProfile(JS::GCReason reason, double promotionRate);
684 void printDeduplicationData(js::StringStats& prev, js::StringStats& curr);
686 // Profile recording and printing.
687 void maybeClearProfileDurations();
688 void startProfile(ProfileKey key);
689 void endProfile(ProfileKey key);
690 static bool printProfileDurations(const ProfileDurations& times,
691 Sprinter& sprinter);
693 mozilla::TimeStamp collectionStartTime() const;
694 mozilla::TimeStamp lastCollectionEndTime() const;
696 friend class gc::GCRuntime;
697 friend class gc::TenuringTracer;
698 friend struct NurseryChunk;
701 } // namespace js
703 #endif // gc_Nursery_h