#include "config.h"
#include "MarkedBlock.h"
#include "JSCell.h"
#include "JSObject.h"
#include "ScopeChain.h"
namespace JSC {
MarkedBlock* MarkedBlock::create(Heap* heap, size_t cellSize)
{
PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, blockSize, OSAllocator::JSGCHeapPages);
if (!static_cast<bool>(allocation))
CRASH();
return new (allocation.base()) MarkedBlock(allocation, heap, cellSize);
}
MarkedBlock* MarkedBlock::recycle(MarkedBlock* block, size_t cellSize)
{
return new (block) MarkedBlock(block->m_allocation, block->m_heap, cellSize);
}
void MarkedBlock::destroy(MarkedBlock* block)
{
block->m_allocation.deallocate();
}
MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, Heap* heap, size_t cellSize)
: m_atomsPerCell((cellSize + atomSize - 1) / atomSize)
, m_endAtom(atomsPerBlock - m_atomsPerCell + 1)
, m_state(New) , m_allocation(allocation)
, m_heap(heap)
{
HEAP_LOG_BLOCK_STATE_TRANSITION(this);
}
inline void MarkedBlock::callDestructor(JSCell* cell, void* jsFinalObjectVPtr)
{
if (cell->isZapped())
return;
void* vptr = cell->vptr();
#if ENABLE(SIMPLE_HEAP_PROFILING)
m_heap->m_destroyedTypeCounts.countVPtr(vptr);
#endif
if (vptr != jsFinalObjectVPtr)
cell->~JSCell();
cell->zap();
}
template<MarkedBlock::BlockState blockState, MarkedBlock::SweepMode sweepMode>
MarkedBlock::FreeCell* MarkedBlock::specializedSweep()
{
ASSERT(blockState != Allocated && blockState != FreeListed);
FreeCell* head = 0;
void* jsFinalObjectVPtr = m_heap->globalData()->jsFinalObjectVPtr;
for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) {
if (blockState == Marked && m_marks.get(i))
continue;
JSCell* cell = reinterpret_cast<JSCell*>(&atoms()[i]);
if (blockState == Zapped && !cell->isZapped())
continue;
if (blockState != New)
callDestructor(cell, jsFinalObjectVPtr);
if (sweepMode == SweepToFreeList) {
FreeCell* freeCell = reinterpret_cast<FreeCell*>(cell);
freeCell->next = head;
head = freeCell;
}
}
m_state = ((sweepMode == SweepToFreeList) ? FreeListed : Zapped);
return head;
}
MarkedBlock::FreeCell* MarkedBlock::sweep(SweepMode sweepMode)
{
HEAP_LOG_BLOCK_STATE_TRANSITION(this);
switch (m_state) {
case New:
ASSERT(sweepMode == SweepToFreeList);
return specializedSweep<New, SweepToFreeList>();
case FreeListed:
ASSERT(sweepMode == SweepToFreeList);
return 0;
case Allocated:
ASSERT_NOT_REACHED();
return 0;
case Marked:
return sweepMode == SweepToFreeList
? specializedSweep<Marked, SweepToFreeList>()
: specializedSweep<Marked, SweepOnly>();
case Zapped:
return sweepMode == SweepToFreeList
? specializedSweep<Zapped, SweepToFreeList>()
: specializedSweep<Zapped, SweepOnly>();
}
ASSERT_NOT_REACHED();
return 0;
}
void MarkedBlock::zapFreeList(FreeCell* firstFreeCell)
{
HEAP_LOG_BLOCK_STATE_TRANSITION(this);
if (m_state == Marked) {
ASSERT(!firstFreeCell);
return;
}
if (m_state == Zapped) {
ASSERT(!firstFreeCell);
return;
}
ASSERT(m_state == FreeListed);
FreeCell* next;
for (FreeCell* current = firstFreeCell; current; current = next) {
next = current->next;
reinterpret_cast<JSCell*>(current)->zap();
}
m_state = Zapped;
}
}