Backed out changeset 4191b252db9b (bug 1886734) for causing build bustages @netwerk...
[gecko.git] / js / src / gc / Nursery.h
bloba94ecd2d36edd5e7d0b0f4537d59b71b3a88e13f
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 <tuple>
16 #include "gc/GCEnum.h"
17 #include "gc/GCProbes.h"
18 #include "gc/Heap.h"
19 #include "gc/MallocedBlockCache.h"
20 #include "gc/Pretenuring.h"
21 #include "js/AllocPolicy.h"
22 #include "js/Class.h"
23 #include "js/GCAPI.h"
24 #include "js/GCVector.h"
25 #include "js/HeapAPI.h"
26 #include "js/TypeDecls.h"
27 #include "js/UniquePtr.h"
28 #include "js/Utility.h"
29 #include "js/Vector.h"
31 #define FOR_EACH_NURSERY_PROFILE_TIME(_) \
32 /* Key Header text */ \
33 _(Total, "total") \
34 _(TraceValues, "mkVals") \
35 _(TraceCells, "mkClls") \
36 _(TraceSlots, "mkSlts") \
37 _(TraceWasmAnyRefs, "mkWars") \
38 _(TraceWholeCells, "mcWCll") \
39 _(TraceGenericEntries, "mkGnrc") \
40 _(CheckHashTables, "ckTbls") \
41 _(MarkRuntime, "mkRntm") \
42 _(MarkDebugger, "mkDbgr") \
43 _(SweepCaches, "swpCch") \
44 _(CollectToObjFP, "colObj") \
45 _(CollectToStrFP, "colStr") \
46 _(ObjectsTenuredCallback, "tenCB") \
47 _(Sweep, "sweep") \
48 _(UpdateJitActivations, "updtIn") \
49 _(FreeMallocedBuffers, "frSlts") \
50 _(FreeTrailerBlocks, "frTrBs") \
51 _(ClearNursery, "clear") \
52 _(PurgeStringToAtomCache, "pStoA") \
53 _(Pretenure, "pretnr")
55 template <typename T>
56 class SharedMem;
58 namespace js {
60 struct StringStats;
61 class AutoLockGCBgAlloc;
62 class ObjectElements;
63 struct NurseryChunk;
64 class HeapSlot;
65 class JSONPrinter;
66 class MapObject;
67 class SetObject;
68 class JS_PUBLIC_API Sprinter;
70 namespace gc {
71 class AutoGCSession;
72 struct Cell;
73 class GCSchedulingTunables;
74 class StoreBuffer;
75 class TenuringTracer;
76 } // namespace gc
78 class Nursery {
79 public:
80 explicit Nursery(gc::GCRuntime* gc);
81 ~Nursery();
83 [[nodiscard]] bool init(AutoLockGCBgAlloc& lock);
85 void enable();
86 void disable();
87 bool isEnabled() const { return capacity() != 0; }
89 void enableStrings();
90 void disableStrings();
91 bool canAllocateStrings() const { return canAllocateStrings_; }
93 void enableBigInts();
94 void disableBigInts();
95 bool canAllocateBigInts() const { return canAllocateBigInts_; }
97 void setSemispaceEnabled(bool enabled);
98 bool semispaceEnabled() const { return semispaceEnabled_; }
100 // Return true if no allocations have been made since the last collection.
101 bool isEmpty() const;
103 // Check whether an arbitrary pointer is within the nursery. This is
104 // slower than IsInsideNursery(Cell*), but works on all types of pointers.
105 bool isInside(gc::Cell* cellp) const = delete;
106 inline bool isInside(const void* p) const;
108 template <typename T>
109 inline bool isInside(const SharedMem<T>& p) const;
111 // Allocate and return a pointer to a new GC thing. Returns nullptr if the
112 // Nursery is full.
113 void* allocateCell(gc::AllocSite* site, size_t size, JS::TraceKind kind);
115 // Allocate and return a pointer to a new GC thing. Returns nullptr if the
116 // handleAllocationFailure() needs to be called before retrying.
117 inline void* tryAllocateCell(gc::AllocSite* site, size_t size,
118 JS::TraceKind kind);
120 // Attempt to handle the failure of tryAllocate. Returns a GCReason if minor
121 // GC is required, or NO_REASON if the failure was handled and allocation will
122 // now succeed.
123 [[nodiscard]] JS::GCReason handleAllocationFailure();
125 static size_t nurseryCellHeaderSize() {
126 return sizeof(gc::NurseryCellHeader);
129 // Allocate a buffer for a given zone, using the nursery if possible. Returns
130 // <buffer, isMalloced> so the caller can register the buffer if
131 // needed. Returns false in |isMalloced| if the allocation fails.
133 // Use the following API if the owning Cell is already known.
134 std::tuple<void*, bool> allocateBuffer(JS::Zone* zone, size_t nbytes,
135 arena_id_t arenaId);
137 // Allocate a buffer for a given Cell, using the nursery if possible and
138 // owner is in the nursery.
139 void* allocateBuffer(JS::Zone* zone, gc::Cell* owner, size_t nbytes,
140 arena_id_t arenaId);
142 // Allocate a buffer for a given Cell, always using the nursery if |owner| is
143 // in the nursery. The requested size must be less than or equal to
144 // MaxNurseryBufferSize.
145 void* allocateBufferSameLocation(gc::Cell* owner, size_t nbytes,
146 arena_id_t arenaId);
148 // Allocate a zero-initialized buffer for a given zone, using the nursery if
149 // possible. If the buffer isn't allocated in the nursery, the given arena is
150 // used. Returns <buffer, isMalloced>. Returns false in |isMalloced| if the
151 // allocation fails.
152 std::tuple<void*, bool> allocateZeroedBuffer(JS::Zone* zone, size_t nbytes,
153 arena_id_t arena);
155 // Allocate a zero-initialized buffer for a given Cell, using the nursery if
156 // possible and |owner| is in the nursery. If the buffer isn't allocated in
157 // the nursery, the given arena is used.
158 void* allocateZeroedBuffer(gc::Cell* owner, size_t nbytes, arena_id_t arena);
160 // Resize an existing buffer.
161 void* reallocateBuffer(JS::Zone* zone, gc::Cell* cell, void* oldBuffer,
162 size_t oldBytes, size_t newBytes, arena_id_t arena);
164 // Free an object buffer.
165 void freeBuffer(void* buffer, size_t nbytes);
167 // The maximum number of bytes allowed to reside in nursery buffers.
168 static const size_t MaxNurseryBufferSize = 1024;
170 // Do a minor collection.
171 void collect(JS::GCOptions options, JS::GCReason reason);
173 // If the thing at |*ref| in the Nursery has been forwarded, set |*ref| to
174 // the new location and return true. Otherwise return false and leave
175 // |*ref| unset.
176 [[nodiscard]] MOZ_ALWAYS_INLINE static bool getForwardedPointer(
177 js::gc::Cell** ref);
179 // Forward a slots/elements pointer stored in an Ion frame.
180 void forwardBufferPointer(uintptr_t* pSlotsElems);
182 inline void maybeSetForwardingPointer(JSTracer* trc, void* oldData,
183 void* newData, bool direct);
184 inline void setForwardingPointerWhileTenuring(void* oldData, void* newData,
185 bool direct);
187 // Handle an external buffer when a cell is promoted. Updates the pointer to
188 // the (possibly moved) buffer and returns whether it was moved.
189 enum WasBufferMoved : bool { BufferNotMoved = false, BufferMoved = true };
190 WasBufferMoved maybeMoveRawBufferOnPromotion(void** bufferp, gc::Cell* owner,
191 size_t nbytes, MemoryUse use,
192 arena_id_t arena);
193 template <typename T>
194 WasBufferMoved maybeMoveBufferOnPromotion(T** bufferp, gc::Cell* owner,
195 size_t nbytes, MemoryUse use,
196 arena_id_t arena) {
197 return maybeMoveRawBufferOnPromotion(reinterpret_cast<void**>(bufferp),
198 owner, nbytes, use, arena);
200 template <typename T>
201 WasBufferMoved maybeMoveBufferOnPromotion(T** bufferp, gc::Cell* owner,
202 size_t nbytes, MemoryUse use) {
203 return maybeMoveBufferOnPromotion(bufferp, owner, nbytes, use, MallocArena);
206 // Register a malloced buffer that is held by a nursery object, which
207 // should be freed at the end of a minor GC. Buffers are unregistered when
208 // their owning objects are tenured.
209 [[nodiscard]] bool registerMallocedBuffer(void* buffer, size_t nbytes);
211 // Mark a malloced buffer as no longer needing to be freed.
212 void removeMallocedBuffer(void* buffer, size_t nbytes) {
213 MOZ_ASSERT(!JS::RuntimeHeapIsMinorCollecting());
214 MOZ_ASSERT(toSpace.mallocedBuffers.has(buffer));
215 MOZ_ASSERT(nbytes > 0);
216 MOZ_ASSERT(toSpace.mallocedBufferBytes >= nbytes);
217 toSpace.mallocedBuffers.remove(buffer);
218 toSpace.mallocedBufferBytes -= nbytes;
221 // Mark a malloced buffer as no longer needing to be freed during minor
222 // GC. There's no need to account for the size here since all remaining
223 // buffers will soon be freed.
224 void removeMallocedBufferDuringMinorGC(void* buffer) {
225 MOZ_ASSERT(JS::RuntimeHeapIsMinorCollecting());
226 MOZ_ASSERT(fromSpace.mallocedBuffers.has(buffer));
227 fromSpace.mallocedBuffers.remove(buffer);
230 [[nodiscard]] bool addedUniqueIdToCell(gc::Cell* cell) {
231 MOZ_ASSERT(IsInsideNursery(cell));
232 MOZ_ASSERT(isEnabled());
233 return cellsWithUid_.append(cell);
236 size_t sizeOfMallocedBuffers(mozilla::MallocSizeOf mallocSizeOf) const;
238 // Wasm "trailer" (C++-heap-allocated) blocks.
240 // All involved blocks are allocated/deallocated via this nursery's
241 // `mallocedBlockCache_`. Hence we must store both the block address and
242 // its freelist ID, wrapped up in a PointerAndUint7.
244 // Trailer blocks registered here are added to `trailersAdded_`. Those that
245 // are later deregistered as a result of `obj_moved` calls that indicate
246 // tenuring, should be added to `trailersRemoved_`.
248 // Unfortunately ::unregisterTrailer cannot be allowed to OOM. To get
249 // around this we rely on the observation that all deregistered blocks
250 // should previously have been registered, so the deregistered set can never
251 // be larger than the registered set. Hence ::registerTrailer effectively
252 // preallocates space in `trailersRemoved_` so as to ensure that, in the
253 // worst case, all registered blocks can be handed to ::unregisterTrailer
254 // without needing to resize `trailersRemoved_` in ::unregisterTrailer.
256 // The downside is that most of the space in `trailersRemoved_` is wasted in
257 // the case where there are few blocks deregistered. This is unfortunate
258 // but it's hard to see how to avoid it.
260 // At the end of a minor collection, all blocks in the set `trailersAdded_ -
261 // trailersRemoved_[0 .. trailersRemovedUsed_ - 1]` are handed back to the
262 // `mallocedBlockCache_`.
263 [[nodiscard]] inline bool registerTrailer(PointerAndUint7 blockAndListID,
264 size_t nBytes);
265 inline void unregisterTrailer(void* block);
266 size_t sizeOfTrailerBlockSets(mozilla::MallocSizeOf mallocSizeOf) const;
268 size_t totalCapacity() const;
269 size_t totalCommitted() const;
271 #ifdef JS_GC_ZEAL
272 void enterZealMode();
273 void leaveZealMode();
274 #endif
276 // Write profile time JSON on JSONPrinter.
277 void renderProfileJSON(JSONPrinter& json) const;
279 // Print header line for profile times.
280 void printProfileHeader();
282 // Print total profile times on shutdown.
283 void printTotalProfileTimes();
285 void* addressOfPosition() const { return (void**)&toSpace.position_; }
286 static constexpr int32_t offsetOfCurrentEndFromPosition() {
287 return offsetof(Nursery, toSpace.currentEnd_) -
288 offsetof(Nursery, toSpace.position_);
291 void* addressOfNurseryAllocatedSites() {
292 return pretenuringNursery.addressOfAllocatedSites();
295 void requestMinorGC(JS::GCReason reason);
297 bool minorGCRequested() const {
298 return minorGCTriggerReason_ != JS::GCReason::NO_REASON;
300 JS::GCReason minorGCTriggerReason() const { return minorGCTriggerReason_; }
302 bool wantEagerCollection() const;
304 bool enableProfiling() const { return enableProfiling_; }
306 bool addMapWithNurseryMemory(MapObject* obj) {
307 MOZ_ASSERT_IF(!mapsWithNurseryMemory_.empty(),
308 mapsWithNurseryMemory_.back() != obj);
309 return mapsWithNurseryMemory_.append(obj);
311 bool addSetWithNurseryMemory(SetObject* obj) {
312 MOZ_ASSERT_IF(!setsWithNurseryMemory_.empty(),
313 setsWithNurseryMemory_.back() != obj);
314 return setsWithNurseryMemory_.append(obj);
317 void joinDecommitTask();
319 mozilla::TimeStamp collectionStartTime() {
320 return startTimes_[ProfileKey::Total];
323 bool canCreateAllocSite() { return pretenuringNursery.canCreateAllocSite(); }
324 void noteAllocSiteCreated() { pretenuringNursery.noteAllocSiteCreated(); }
325 bool reportPretenuring() const { return reportPretenuring_; }
326 void maybeStopPretenuring(gc::GCRuntime* gc) {
327 pretenuringNursery.maybeStopPretenuring(gc);
330 void setAllocFlagsForZone(JS::Zone* zone);
332 bool shouldTenureEverything(JS::GCReason reason);
334 inline bool inCollectedRegion(gc::Cell* cell) const;
335 inline bool inCollectedRegion(void* ptr) const;
337 void trackMallocedBufferOnPromotion(void* buffer, gc::Cell* owner,
338 size_t nbytes, MemoryUse use);
339 void trackTrailerOnPromotion(void* buffer, gc::Cell* owner, size_t nbytes,
340 size_t overhead, MemoryUse use);
342 // Round a size in bytes to the nearest valid nursery size.
343 static size_t roundSize(size_t size);
345 // The malloc'd block cache.
346 gc::MallocedBlockCache& mallocedBlockCache() { return mallocedBlockCache_; }
347 size_t sizeOfMallocedBlockCache(mozilla::MallocSizeOf mallocSizeOf) const {
348 return mallocedBlockCache_.sizeOfExcludingThis(mallocSizeOf);
351 mozilla::TimeStamp lastCollectionEndTime() const;
353 private:
354 struct Space;
356 enum class ProfileKey {
357 #define DEFINE_TIME_KEY(name, text) name,
358 FOR_EACH_NURSERY_PROFILE_TIME(DEFINE_TIME_KEY)
359 #undef DEFINE_TIME_KEY
360 KeyCount
363 using ProfileTimes = mozilla::EnumeratedArray<ProfileKey, mozilla::TimeStamp,
364 size_t(ProfileKey::KeyCount)>;
365 using ProfileDurations =
366 mozilla::EnumeratedArray<ProfileKey, mozilla::TimeDuration,
367 size_t(ProfileKey::KeyCount)>;
369 size_t capacity() const { return capacity_; }
371 // Total number of chunks and the capacity of the current nursery
372 // space. Chunks will be lazily allocated and added to the chunks array up to
373 // this limit. After that the nursery must be collected. This limit may be
374 // changed at the end of collection by maybeResizeNursery.
375 uint32_t maxChunkCount() const {
376 MOZ_ASSERT(toSpace.maxChunkCount_);
377 return toSpace.maxChunkCount_;
380 // Number of allocated (ready to use) chunks.
381 unsigned allocatedChunkCount() const { return toSpace.chunks_.length(); }
383 uint32_t currentChunk() const { return toSpace.currentChunk_; }
384 uint32_t startChunk() const { return toSpace.startChunk_; }
385 uintptr_t startPosition() const { return toSpace.startPosition_; }
387 // Used and free space both include chunk headers for that part of the
388 // nursery.
389 MOZ_ALWAYS_INLINE size_t usedSpace() const {
390 return capacity() - freeSpace();
392 MOZ_ALWAYS_INLINE size_t freeSpace() const {
393 MOZ_ASSERT(isEnabled());
394 MOZ_ASSERT(currentChunk() < maxChunkCount());
395 return (currentEnd() - position()) +
396 (maxChunkCount() - currentChunk() - 1) * gc::ChunkSize;
399 // Calculate the promotion rate of the most recent minor GC.
400 // The valid_for_tenuring parameter is used to return whether this
401 // promotion rate is accurate enough (the nursery was full enough) to be
402 // used for tenuring and other decisions.
404 // Must only be called if the previousGC data is initialised.
405 double calcPromotionRate(bool* validForTenuring) const;
407 void freeTrailerBlocks(JS::GCOptions options, JS::GCReason reason);
409 NurseryChunk& chunk(unsigned index) const { return *toSpace.chunks_[index]; }
411 // Set the allocation position to the start of a chunk. This sets
412 // currentChunk_, position_ and currentEnd_ values as appropriate.
413 void moveToStartOfChunk(unsigned chunkno);
415 bool initFirstChunk(AutoLockGCBgAlloc& lock);
416 void setCapacity(size_t newCapacity);
418 void poisonAndInitCurrentChunk();
420 void setCurrentEnd();
421 void setStartToCurrentPosition();
423 // Allocate another chunk.
424 [[nodiscard]] bool allocateNextChunk(AutoLockGCBgAlloc& lock);
426 uintptr_t position() const { return toSpace.position_; }
427 uintptr_t currentEnd() const { return toSpace.currentEnd_; }
429 MOZ_ALWAYS_INLINE bool isSubChunkMode() const;
431 JSRuntime* runtime() const;
432 gcstats::Statistics& stats() const;
434 const js::gc::GCSchedulingTunables& tunables() const;
436 void getAllocFlagsForZone(JS::Zone* zone, bool* allocObjectsOut,
437 bool* allocStringsOut, bool* allocBigIntsOut);
438 void updateAllZoneAllocFlags();
439 void updateAllocFlagsForZone(JS::Zone* zone);
440 void discardCodeAndSetJitFlagsForZone(JS::Zone* zone);
442 void* allocate(size_t size);
444 // Common internal allocator function. If this fails, call
445 // handleAllocationFailure to see whether it's possible to retry.
446 inline void* tryAllocate(size_t size);
448 [[nodiscard]] bool moveToNextChunk();
450 bool freeSpaceIsBelowEagerThreshold() const;
451 bool isUnderused() const;
453 struct CollectionResult {
454 size_t tenuredBytes;
455 size_t tenuredCells;
457 CollectionResult doCollection(gc::AutoGCSession& session,
458 JS::GCOptions options, JS::GCReason reason);
459 void swapSpaces();
460 void traceRoots(gc::AutoGCSession& session, gc::TenuringTracer& mover);
462 size_t doPretenuring(JSRuntime* rt, JS::GCReason reason,
463 bool validPromotionRate, double promotionRate);
465 // Handle relocation of slots/elements pointers stored in Ion frames.
466 inline void setForwardingPointer(void* oldData, void* newData, bool direct);
468 inline void setDirectForwardingPointer(void* oldData, void* newData);
469 void setIndirectForwardingPointer(void* oldData, void* newData);
471 inline void setSlotsForwardingPointer(HeapSlot* oldSlots, HeapSlot* newSlots,
472 uint32_t nslots);
473 inline void setElementsForwardingPointer(ObjectElements* oldHeader,
474 ObjectElements* newHeader,
475 uint32_t capacity);
477 #ifdef DEBUG
478 bool checkForwardingPointerInsideNursery(void* ptr);
479 #endif
481 // Updates pointers to nursery objects that have been tenured and discards
482 // pointers to objects that have been freed.
483 void sweep();
485 // In a minor GC, resets the start and end positions, the current chunk and
486 // current position.
487 void setNewExtentAndPosition();
489 // the nursery on debug & nightly builds.
490 void clear();
492 void clearMapAndSetNurseryRanges();
493 void sweepMapAndSetObjects();
495 // Allocate a buffer for a given zone, using the nursery if possible.
496 void* allocateBuffer(JS::Zone* zone, size_t nbytes);
498 // Get per-space size limits.
499 size_t maxSpaceSize() const;
500 size_t minSpaceSize() const;
502 // Change the allocable space provided by the nursery.
503 void maybeResizeNursery(JS::GCOptions options, JS::GCReason reason);
504 size_t targetSize(JS::GCOptions options, JS::GCReason reason);
505 void clearRecentGrowthData();
506 void growAllocableSpace(size_t newCapacity);
507 void shrinkAllocableSpace(size_t newCapacity);
508 void minimizeAllocableSpace();
510 // Free the chunks starting at firstFreeChunk until the end of the chunks
511 // vector. Shrinks the vector but does not update maxChunkCount().
512 void freeChunksFrom(Space& space, unsigned firstFreeChunk);
514 inline bool shouldTenure(gc::Cell* cell);
516 void sendTelemetry(JS::GCReason reason, mozilla::TimeDuration totalTime,
517 bool wasEmpty, double promotionRate,
518 size_t sitesPretenured);
520 void printCollectionProfile(JS::GCReason reason, double promotionRate);
521 void printDeduplicationData(js::StringStats& prev, js::StringStats& curr);
523 // Profile recording and printing.
524 void maybeClearProfileDurations();
525 void startProfile(ProfileKey key);
526 void endProfile(ProfileKey key);
527 static void printProfileDurations(const ProfileDurations& times,
528 Sprinter& sprinter);
530 mozilla::TimeStamp collectionStartTime() const;
532 private:
533 using BufferRelocationOverlay = void*;
534 using BufferSet = HashSet<void*, PointerHasher<void*>, SystemAllocPolicy>;
536 struct Space {
537 // Fields used during allocation fast path go first:
539 // Pointer to the first unallocated byte in the nursery.
540 uintptr_t position_ = 0;
542 // Pointer to the last byte of space in the current chunk.
543 uintptr_t currentEnd_ = 0;
545 // Vector of allocated chunks to allocate from.
546 Vector<NurseryChunk*, 0, SystemAllocPolicy> chunks_;
548 // The index of the chunk that is currently being allocated from.
549 uint32_t currentChunk_ = 0;
551 // The maximum number of chunks to allocate based on capacity_.
552 uint32_t maxChunkCount_ = 0;
554 // These fields refer to the beginning of the nursery. They're normally 0
555 // and chunk(0).start() respectively. Except when a generational GC zeal
556 // mode is active, then they may be arbitrary (see Nursery::clear()).
557 uint32_t startChunk_ = 0;
558 uintptr_t startPosition_ = 0;
560 // The set of malloced-allocated buffers owned by nursery objects. Any
561 // buffers that do not belong to a promoted thing at the end of a minor GC
562 // must be freed.
563 BufferSet mallocedBuffers;
564 size_t mallocedBufferBytes = 0;
566 // Wasm "trailer" (C++-heap-allocated) blocks. See comments above on
567 // ::registerTrailer and ::unregisterTrailer.
568 Vector<PointerAndUint7, 0, SystemAllocPolicy> trailersAdded_;
569 Vector<void*, 0, SystemAllocPolicy> trailersRemoved_;
570 size_t trailersRemovedUsed_ = 0;
571 size_t trailerBytes_ = 0;
573 gc::ChunkKind kind;
575 explicit Space(gc::ChunkKind kind);
577 inline bool isEmpty() const;
578 inline bool isInside(const void* p) const;
580 // Return the logical offset within the nursery of an address in a nursery
581 // chunk (chunks are discontiguous in memory).
582 inline size_t offsetFromAddress(uintptr_t addr) const;
583 inline size_t offsetFromExclusiveAddress(uintptr_t addr) const;
585 void setKind(gc::ChunkKind newKind);
587 void clear(Nursery* nursery);
588 void moveToStartOfChunk(Nursery* nursery, unsigned chunkno);
589 void setCurrentEnd(Nursery* nursery);
590 void setStartToCurrentPosition();
591 bool commitSubChunkRegion(size_t oldCapacity, size_t newCapacity);
592 void decommitSubChunkRegion(Nursery* nursery, size_t oldCapacity,
593 size_t newCapacity);
594 void freeTrailerBlocks(gc::MallocedBlockCache& mallocedBlockCache);
596 #ifdef DEBUG
597 void checkKind(gc::ChunkKind expected) const;
598 size_t findChunkIndex(uintptr_t chunkAddr) const;
599 #endif
602 Space toSpace;
603 Space fromSpace;
605 gc::GCRuntime* const gc;
607 // The current nursery capacity measured in bytes. It may grow up to this
608 // value without a collection, allocating chunks on demand. This limit may be
609 // changed by maybeResizeNursery() each collection. It includes chunk headers.
610 size_t capacity_;
612 uintptr_t tenureThreshold_ = 0;
614 gc::PretenuringNursery pretenuringNursery;
616 mozilla::TimeDuration timeInChunkAlloc_;
618 // Report minor collections taking at least this long, if enabled.
619 bool enableProfiling_ = false;
620 bool profileWorkers_ = false;
622 mozilla::TimeDuration profileThreshold_;
624 // Whether to use semispace collection.
625 bool semispaceEnabled_;
627 // Whether we will nursery-allocate strings.
628 bool canAllocateStrings_;
630 // Whether we will nursery-allocate BigInts.
631 bool canAllocateBigInts_;
633 // Report how many strings were deduplicated.
634 bool reportDeduplications_;
636 // Whether to report information on pretenuring, and if so the allocation
637 // threshold at which to report details of each allocation site.
638 bool reportPretenuring_;
639 size_t reportPretenuringThreshold_;
641 // Whether and why a collection of this nursery has been requested. When this
642 // happens |prevPosition_| is set to the current position and |position_| set
643 // to the end of the chunk to force the next allocation to fail.
644 JS::GCReason minorGCTriggerReason_;
645 uintptr_t prevPosition_;
647 // Profiling data.
649 ProfileTimes startTimes_;
650 ProfileDurations profileDurations_;
651 ProfileDurations totalDurations_;
653 // Data about the previous collection.
654 struct PreviousGC {
655 JS::GCReason reason = JS::GCReason::NO_REASON;
656 size_t nurseryCapacity = 0;
657 size_t nurseryCommitted = 0;
658 size_t nurseryUsedBytes = 0;
659 size_t nurseryUsedChunkCount = 0;
660 size_t tenuredBytes = 0;
661 size_t tenuredCells = 0;
662 mozilla::TimeStamp endTime;
664 PreviousGC previousGC;
666 bool hasRecentGrowthData;
667 double smoothedTargetSize;
669 // During a collection most hoisted slot and element buffers indicate their
670 // new location with a forwarding pointer at the base. This does not work
671 // for buffers whose length is less than pointer width, or when different
672 // buffers might overlap each other. For these, an entry in the following
673 // table is used.
674 using ForwardedBufferMap =
675 HashMap<void*, void*, PointerHasher<void*>, SystemAllocPolicy>;
676 ForwardedBufferMap forwardedBuffers;
678 // When we assign a unique id to cell in the nursery, that almost always
679 // means that the cell will be in a hash table, and thus, held live,
680 // automatically moving the uid from the nursery to its new home in
681 // tenured. It is possible, if rare, for an object that acquired a uid to
682 // be dead before the next collection, in which case we need to know to
683 // remove it when we sweep.
685 // Note: we store the pointers as Cell* here, resulting in an ugly cast in
686 // sweep. This is because this structure is used to help implement
687 // stable object hashing and we have to break the cycle somehow.
688 using CellsWithUniqueIdVector = JS::GCVector<gc::Cell*, 8, SystemAllocPolicy>;
689 CellsWithUniqueIdVector cellsWithUid_;
691 // Lists of map and set objects allocated in the nursery or with iterators
692 // allocated there. Such objects need to be swept after minor GC.
693 using MapObjectVector = Vector<MapObject*, 0, SystemAllocPolicy>;
694 MapObjectVector mapsWithNurseryMemory_;
695 using SetObjectVector = Vector<SetObject*, 0, SystemAllocPolicy>;
696 SetObjectVector setsWithNurseryMemory_;
698 UniquePtr<NurseryDecommitTask> decommitTask;
700 // A cache of small C++-heap allocated blocks associated with this Nursery.
701 // This provided so as to provide cheap allocation/deallocation of
702 // out-of-line storage areas as used by WasmStructObject and
703 // WasmArrayObject, although the mechanism is general and not specific to
704 // these object types. Regarding lifetimes, because the cache holds only
705 // blocks that are not currently in use, it can be flushed at any point with
706 // no correctness impact, only a performance impact.
707 gc::MallocedBlockCache mallocedBlockCache_;
709 // Whether the previous collection tenured everything. This may be false if
710 // semispace is in use.
711 bool tenuredEverything;
713 friend class gc::GCRuntime;
714 friend class gc::TenuringTracer;
715 friend struct NurseryChunk;
718 MOZ_ALWAYS_INLINE bool Nursery::isInside(const void* p) const {
719 // TODO: Split this into separate methods.
720 // TODO: Do we ever need to check both?
721 return toSpace.isInside(p) || fromSpace.isInside(p);
724 MOZ_ALWAYS_INLINE bool Nursery::Space::isInside(const void* p) const {
725 for (auto* chunk : chunks_) {
726 if (uintptr_t(p) - uintptr_t(chunk) < gc::ChunkSize) {
727 return true;
730 return false;
733 } // namespace js
735 #endif // gc_Nursery_h