summaryrefslogtreecommitdiffstats
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/public/HeapAPI.h37
-rw-r--r--js/src/gc/Marking.cpp5
2 files changed, 42 insertions, 0 deletions
diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h
index fef6c0c78..d033d3706 100644
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -51,6 +51,7 @@ const size_t ChunkMarkBitmapBits = 129024;
const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*);
const size_t ChunkTrailerSize = 2 * sizeof(uintptr_t) + sizeof(uint64_t);
const size_t ChunkLocationOffset = ChunkSize - ChunkTrailerSize;
+const size_t ChunkStoreBufferOffset = ChunkSize - ChunkTrailerSize + sizeof(uint64_t);
const size_t ArenaZoneOffset = sizeof(size_t);
const size_t ArenaHeaderSize = sizeof(size_t) + 2 * sizeof(uintptr_t) +
sizeof(size_t) + sizeof(uintptr_t);
@@ -326,6 +327,20 @@ CellIsMarkedGray(const Cell* cell)
extern JS_PUBLIC_API(bool)
CellIsMarkedGrayIfKnown(const Cell* cell);
+MOZ_ALWAYS_INLINE ChunkLocation GetCellLocation(const void* cell) {
+ uintptr_t addr = uintptr_t(cell);
+ addr &= ~js::gc::ChunkMask;
+ addr |= js::gc::ChunkLocationOffset;
+ return *reinterpret_cast<ChunkLocation*>(addr);
+}
+
+MOZ_ALWAYS_INLINE bool NurseryCellHasStoreBuffer(const void* cell) {
+ uintptr_t addr = uintptr_t(cell);
+ addr &= ~js::gc::ChunkMask;
+ addr |= js::gc::ChunkStoreBufferOffset;
+ return *reinterpret_cast<void**>(addr) != nullptr;
+}
+
} /* namespace detail */
MOZ_ALWAYS_INLINE bool
@@ -341,6 +356,28 @@ IsInsideNursery(const js::gc::Cell* cell)
return location == ChunkLocation::Nursery;
}
+MOZ_ALWAYS_INLINE bool IsCellPointerValid(const void* cell) {
+ auto addr = uintptr_t(cell);
+ if (addr < ChunkSize || addr % CellSize != 0) {
+ return false;
+ }
+ auto location = detail::GetCellLocation(cell);
+ if (location == ChunkLocation::TenuredHeap) {
+ return !!detail::GetGCThingZone(addr);
+ }
+ if (location == ChunkLocation::Nursery) {
+ return detail::NurseryCellHasStoreBuffer(cell);
+ }
+ return false;
+}
+
+MOZ_ALWAYS_INLINE bool IsCellPointerValidOrNull(const void* cell) {
+ if (!cell) {
+ return true;
+ }
+ return IsCellPointerValid(cell);
+}
+
} /* namespace gc */
} /* namespace js */
diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
index 43e325394..b4db0297a 100644
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2267,6 +2267,8 @@ void
js::gc::StoreBuffer::SlotsEdge::trace(TenuringTracer& mover) const
{
NativeObject* obj = object();
+ if(!IsCellPointerValid(obj))
+ return;
// Beware JSObject::swap exchanging a native object for a non-native one.
if (!obj->isNative())
@@ -2336,6 +2338,8 @@ js::gc::StoreBuffer::traceWholeCells(TenuringTracer& mover)
{
for (ArenaCellSet* cells = bufferWholeCell; cells; cells = cells->next) {
Arena* arena = cells->arena;
+ if(!IsCellPointerValid(arena))
+ continue;
MOZ_ASSERT(arena->bufferedCells == cells);
arena->bufferedCells = &ArenaCellSet::Empty;
@@ -2364,6 +2368,7 @@ js::gc::StoreBuffer::CellPtrEdge::trace(TenuringTracer& mover) const
{
if (!*edge)
return;
+ // XXX: We should check if the cell pointer is valid here too
MOZ_ASSERT((*edge)->getTraceKind() == JS::TraceKind::Object);
mover.traverse(reinterpret_cast<JSObject**>(edge));