#pragma once
#include "MarkedBlock.h"
#include "WeakSet.h"
namespace JSC {
class SlotVisitor;
class LargeAllocation : public BasicRawSentinelNode<LargeAllocation> {
public:
static LargeAllocation* tryCreate(Heap&, size_t, Subspace*);
~LargeAllocation();
static LargeAllocation* fromCell(const void* cell)
{
return bitwise_cast<LargeAllocation*>(bitwise_cast<char*>(cell) - headerSize());
}
HeapCell* cell() const
{
return bitwise_cast<HeapCell*>(bitwise_cast<char*>(this) + headerSize());
}
static bool isLargeAllocation(HeapCell* cell)
{
return bitwise_cast<uintptr_t>(cell) & halfAlignment;
}
Subspace* subspace() const { return m_subspace; }
void lastChanceToFinalize();
Heap* heap() const { return m_weakSet.heap(); }
VM* vm() const { return m_weakSet.vm(); }
WeakSet& weakSet() { return m_weakSet; }
void shrink();
void visitWeakSet(SlotVisitor&);
void reapWeakSet();
void clearNewlyAllocated() { m_isNewlyAllocated = false; }
void flip();
bool isNewlyAllocated() const { return m_isNewlyAllocated; }
ALWAYS_INLINE bool isMarked() { return m_isMarked.load(std::memory_order_relaxed); }
ALWAYS_INLINE bool isMarked(HeapCell*) { return isMarked(); }
ALWAYS_INLINE bool isMarked(HeapCell*, Dependency) { return isMarked(); }
ALWAYS_INLINE bool isMarked(HeapVersion, HeapCell*) { return isMarked(); }
bool isLive() { return isMarked() || isNewlyAllocated(); }
bool hasValidCell() const { return m_hasValidCell; }
bool isEmpty();
size_t cellSize() const { return m_cellSize; }
bool aboveLowerBound(const void* rawPtr)
{
char* ptr = bitwise_cast<char*>(rawPtr);
char* begin = bitwise_cast<char*>(cell());
return ptr >= begin;
}
bool belowUpperBound(const void* rawPtr)
{
char* ptr = bitwise_cast<char*>(rawPtr);
char* begin = bitwise_cast<char*>(cell());
char* end = begin + cellSize();
size_t sizeOfIndexingHeader = 8;
return ptr <= end + sizeOfIndexingHeader;
}
bool contains(const void* rawPtr)
{
return aboveLowerBound(rawPtr) && belowUpperBound(rawPtr);
}
const CellAttributes& attributes() const { return m_attributes; }
Dependency aboutToMark(HeapVersion) { return Dependency(); }
ALWAYS_INLINE bool testAndSetMarked()
{
if (isMarked())
return true;
return m_isMarked.compareExchangeStrong(false, true);
}
ALWAYS_INLINE bool testAndSetMarked(HeapCell*, Dependency) { return testAndSetMarked(); }
void clearMarked() { m_isMarked.store(false); }
void noteMarked() { }
#if ASSERT_DISABLED
void assertValidCell(VM&, HeapCell*) const { }
#else
void assertValidCell(VM&, HeapCell*) const;
#endif
void sweep();
void destroy();
void dump(PrintStream&) const;
private:
LargeAllocation(Heap&, size_t, Subspace*);
static const unsigned alignment = MarkedBlock::atomSize;
static const unsigned halfAlignment = alignment / 2;
static unsigned headerSize();
size_t m_cellSize;
bool m_isNewlyAllocated;
bool m_hasValidCell;
Atomic<bool> m_isMarked;
CellAttributes m_attributes;
Subspace* m_subspace;
WeakSet m_weakSet;
};
inline unsigned LargeAllocation::headerSize()
{
return ((sizeof(LargeAllocation) + halfAlignment - 1) & ~(halfAlignment - 1)) | halfAlignment;
}
}