inline void* MarkedAllocator::tryAllocateHelper(size_t bytes) { // We need a while loop to check the free list because the DelayedReleaseScope // could cause arbitrary code to execute and exhaust the free list that we // thought had elements in it. while (!m_freeList.head) { DelayedReleaseScope delayedReleaseScope(*m_markedSpace); if (m_currentBlock) { ASSERT(m_currentBlock == m_nextBlockToSweep); m_currentBlock->didConsumeFreeList(); m_nextBlockToSweep = m_currentBlock->next(); } MarkedBlock* next; for (MarkedBlock*& block = m_nextBlockToSweep; block; block = next) { next = block->next(); MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList); if (!freeList.head) { block->didConsumeEmptyFreeList(); m_blockList.remove(block); m_blockList.push(block); if (!m_lastFullBlock) m_lastFullBlock = block; continue; } if (bytes > block->cellSize()) { block->stopAllocating(freeList); continue; } m_currentBlock = block; m_freeList = freeList; break; } if (!m_freeList.head) { m_currentBlock = 0; return 0; } } ASSERT(m_freeList.head); void* head = tryPopFreeList(bytes); ASSERT(head); m_markedSpace->didAllocateInBlock(m_currentBlock); return head; }
inline void* MarkedAllocator::tryAllocateHelper(size_t bytes) { if (m_currentBlock) { ASSERT(m_currentBlock == m_nextBlockToSweep); m_currentBlock->didConsumeFreeList(); m_nextBlockToSweep = m_currentBlock->next(); } MarkedBlock* next; for (MarkedBlock*& block = m_nextBlockToSweep; block; block = next) { next = block->next(); MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList); double utilization = ((double)MarkedBlock::blockSize - (double)freeList.bytes) / (double)MarkedBlock::blockSize; if (utilization >= Options::minMarkedBlockUtilization()) { ASSERT(freeList.bytes || !freeList.head); m_blockList.remove(block); m_retiredBlocks.push(block); block->didRetireBlock(freeList); continue; } if (bytes > block->cellSize()) { block->stopAllocating(freeList); continue; } m_currentBlock = block; m_freeList = freeList; break; } if (!m_freeList.head) { m_currentBlock = 0; return 0; } ASSERT(m_freeList.head); void* head = tryPopFreeList(bytes); ASSERT(head); m_markedSpace->didAllocateInBlock(m_currentBlock); return head; }
inline void* MarkedAllocator::tryAllocate(size_t bytes) { ASSERT(!m_heap->isBusy()); m_heap->m_operationInProgress = Allocation; void* result = tryAllocateHelper(bytes); // Due to the DelayedReleaseScope in tryAllocateHelper, some other thread might have // created a new block after we thought we didn't find any free cells. while (!result && m_currentBlock) { // A new block was added by another thread so try popping the free list. result = tryPopFreeList(bytes); if (result) break; // The free list was empty, so call tryAllocateHelper to do the normal sweeping stuff. result = tryAllocateHelper(bytes); } m_heap->m_operationInProgress = NoOperation; ASSERT(result || !m_currentBlock); return result; }