diff options
Diffstat (limited to 'js/src/gc/Nursery-inl.h')
-rw-r--r-- | js/src/gc/Nursery-inl.h | 92 |
1 files changed, 76 insertions, 16 deletions
diff --git a/js/src/gc/Nursery-inl.h b/js/src/gc/Nursery-inl.h index 3a29d76c07..3be063697a 100644 --- a/js/src/gc/Nursery-inl.h +++ b/js/src/gc/Nursery-inl.h @@ -16,6 +16,12 @@ #include "vm/JSContext.h" #include "vm/NativeObject.h" +namespace js { +namespace gc { +struct Cell; +} // namespace gc +} // namespace js + inline JSRuntime* js::Nursery::runtime() const { return gc->rt; } template <typename T> @@ -23,6 +29,50 @@ bool js::Nursery::isInside(const SharedMem<T>& p) const { return isInside(p.unwrap(/*safe - used for value in comparison above*/)); } +inline bool js::Nursery::shouldTenure(gc::Cell* cell) { + MOZ_ASSERT(semispaceEnabled()); + MOZ_ASSERT(inCollectedRegion(cell)); + + size_t offset = fromSpace.offsetFromAddress(uintptr_t(cell)); + MOZ_ASSERT(offset >= + fromSpace.offsetFromExclusiveAddress(fromSpace.startPosition_)); + return offset <= tenureThreshold_; +} + +inline bool js::Nursery::inCollectedRegion(gc::Cell* cell) const { + gc::ChunkBase* chunk = gc::detail::GetCellChunkBase(cell); + return chunk->getKind() == gc::ChunkKind::NurseryFromSpace; +} + +inline bool js::Nursery::inCollectedRegion(void* ptr) const { + if (!semispaceEnabled()) { + return toSpace.isInside(ptr); + } + + return fromSpace.isInside(ptr); +} + +inline size_t js::Nursery::Space::offsetFromExclusiveAddress( + uintptr_t addr) const { + if ((addr & gc::ChunkMask) == 0) { + // |addr| points one past the end of the previous chunk. + return offsetFromAddress(addr - 1) + 1; + } + + return offsetFromAddress(addr); +} + +inline size_t js::Nursery::Space::offsetFromAddress(uintptr_t addr) const { + gc::ChunkBase* chunk = + gc::detail::GetCellChunkBase(reinterpret_cast<gc::Cell*>(addr)); + MOZ_ASSERT(chunk->getKind() == kind); + MOZ_ASSERT(findChunkIndex(addr & ~gc::ChunkMask) == chunk->nurseryChunkIndex); + + uint32_t offset = addr & gc::ChunkMask; + MOZ_ASSERT(offset >= sizeof(gc::ChunkBase)); + return (chunk->nurseryChunkIndex << gc::ChunkShift) | offset; +} + MOZ_ALWAYS_INLINE /* static */ bool js::Nursery::getForwardedPointer( js::gc::Cell** ref) { js::gc::Cell* cell = (*ref); @@ -80,7 +130,7 @@ inline void js::Nursery::setForwardingPointer(void* oldData, void* newData, inline void js::Nursery::setDirectForwardingPointer(void* oldData, void* newData) { MOZ_ASSERT(isInside(oldData)); - MOZ_ASSERT(!isInside(newData)); + MOZ_ASSERT_IF(isInside(newData), !inCollectedRegion(newData)); new (oldData) BufferRelocationOverlay{newData}; } @@ -123,8 +173,8 @@ inline void* js::Nursery::tryAllocateCell(gc::AllocSite* site, size_t size, inline void* js::Nursery::tryAllocate(size_t size) { MOZ_ASSERT(isEnabled()); - MOZ_ASSERT(!JS::RuntimeHeapIsBusy()); - MOZ_ASSERT_IF(currentChunk_ == startChunk_, position() >= startPosition_); + MOZ_ASSERT_IF(JS::RuntimeHeapIsBusy(), JS::RuntimeHeapIsMinorCollecting()); + MOZ_ASSERT_IF(currentChunk() == startChunk(), position() >= startPosition()); MOZ_ASSERT(size % gc::CellAlignBytes == 0); MOZ_ASSERT(position() % gc::CellAlignBytes == 0); @@ -138,7 +188,7 @@ inline void* js::Nursery::tryAllocate(size_t size) { "Successful allocation cannot result in nullptr"); } - position_ = position() + size; + toSpace.position_ = position() + size; DebugOnlyPoison(ptr, JS_ALLOCATED_NURSERY_PATTERN, size, MemCheckKind::MakeUndefined); @@ -148,30 +198,33 @@ inline void* js::Nursery::tryAllocate(size_t size) { inline bool js::Nursery::registerTrailer(PointerAndUint7 blockAndListID, size_t nBytes) { - MOZ_ASSERT(trailersAdded_.length() == trailersRemoved_.length()); + MOZ_ASSERT(toSpace.trailersAdded_.length() == + toSpace.trailersRemoved_.length()); MOZ_ASSERT(nBytes > 0); - if (MOZ_UNLIKELY(!trailersAdded_.append(blockAndListID))) { + if (MOZ_UNLIKELY(!toSpace.trailersAdded_.append(blockAndListID))) { return false; } - if (MOZ_UNLIKELY(!trailersRemoved_.append(nullptr))) { - trailersAdded_.popBack(); + if (MOZ_UNLIKELY(!toSpace.trailersRemoved_.append(nullptr))) { + toSpace.trailersAdded_.popBack(); return false; } // This is a clone of the logic in ::registerMallocedBuffer. It may be // that some other heuristic is better, once we know more about the // typical behaviour of wasm-GC applications. - trailerBytes_ += nBytes; - if (MOZ_UNLIKELY(trailerBytes_ > capacity() * 8)) { + toSpace.trailerBytes_ += nBytes; + if (MOZ_UNLIKELY(toSpace.trailerBytes_ > capacity() * 8)) { requestMinorGC(JS::GCReason::NURSERY_TRAILERS); } return true; } inline void js::Nursery::unregisterTrailer(void* block) { - MOZ_ASSERT(trailersRemovedUsed_ < trailersRemoved_.length()); - trailersRemoved_[trailersRemovedUsed_] = block; - trailersRemovedUsed_++; + // Unlike removeMallocedBuffer this is only called during minor GC. + MOZ_ASSERT(fromSpace.trailersRemovedUsed_ < + fromSpace.trailersRemoved_.length()); + fromSpace.trailersRemoved_[fromSpace.trailersRemovedUsed_] = block; + fromSpace.trailersRemovedUsed_++; } namespace js { @@ -181,13 +234,20 @@ namespace js { // instead. template <typename T> -static inline T* AllocateCellBuffer(JSContext* cx, gc::Cell* cell, +static inline T* AllocateCellBuffer(Nursery& nursery, gc::Cell* cell, uint32_t count) { size_t nbytes = RoundUp(count * sizeof(T), sizeof(Value)); - auto* buffer = static_cast<T*>(cx->nursery().allocateBuffer( - cell->zone(), cell, nbytes, js::MallocArena)); + return static_cast<T*>( + nursery.allocateBuffer(cell->zone(), cell, nbytes, js::MallocArena)); +} + +template <typename T> +static inline T* AllocateCellBuffer(JSContext* cx, gc::Cell* cell, + uint32_t count) { + T* buffer = AllocateCellBuffer<T>(cx->nursery(), cell, count); if (!buffer) { ReportOutOfMemory(cx); + return nullptr; } return buffer; |