summaryrefslogtreecommitdiffstats
path: root/js/src/gc/Nursery-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/gc/Nursery-inl.h')
-rw-r--r--js/src/gc/Nursery-inl.h92
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;