X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..2656c66b5b30d5597e842a751c7f19ad6c2fe31a:/heap/CopiedSpace.cpp diff --git a/heap/CopiedSpace.cpp b/heap/CopiedSpace.cpp index 94aa73e..cb1a656 100644 --- a/heap/CopiedSpace.cpp +++ b/heap/CopiedSpace.cpp @@ -26,27 +26,59 @@ #include "config.h" #include "CopiedSpace.h" -#include "CopiedSpaceInlineMethods.h" +#include "CopiedSpaceInlines.h" #include "GCActivityCallback.h" +#include "JSCInlines.h" +#include "Options.h" namespace JSC { CopiedSpace::CopiedSpace(Heap* heap) : m_heap(heap) - , m_toSpace(0) - , m_fromSpace(0) , m_inCopyingPhase(false) + , m_shouldDoCopyPhase(false) , m_numberOfLoanedBlocks(0) { + m_toSpaceLock.Init(); +} + +CopiedSpace::~CopiedSpace() +{ + while (!m_oldGen.toSpace->isEmpty()) + m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_oldGen.toSpace->removeHead())); + + while (!m_oldGen.fromSpace->isEmpty()) + m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_oldGen.fromSpace->removeHead())); + + while (!m_oldGen.oversizeBlocks.isEmpty()) + m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(m_oldGen.oversizeBlocks.removeHead())); + + while (!m_newGen.toSpace->isEmpty()) + m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_newGen.toSpace->removeHead())); + + while (!m_newGen.fromSpace->isEmpty()) + m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_newGen.fromSpace->removeHead())); + + while (!m_newGen.oversizeBlocks.isEmpty()) + m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(m_newGen.oversizeBlocks.removeHead())); + + ASSERT(m_oldGen.toSpace->isEmpty()); + ASSERT(m_oldGen.fromSpace->isEmpty()); + ASSERT(m_oldGen.oversizeBlocks.isEmpty()); + ASSERT(m_newGen.toSpace->isEmpty()); + ASSERT(m_newGen.fromSpace->isEmpty()); + ASSERT(m_newGen.oversizeBlocks.isEmpty()); } void CopiedSpace::init() { - m_toSpace = &m_blocks1; - m_fromSpace = &m_blocks2; + m_oldGen.toSpace = &m_oldGen.blocks1; + m_oldGen.fromSpace = &m_oldGen.blocks2; - if (!addNewBlock()) - CRASH(); + m_newGen.toSpace = &m_newGen.blocks1; + m_newGen.fromSpace = &m_newGen.blocks2; + + allocateBlock(); } CheckedBoolean CopiedSpace::tryAllocateSlowCase(size_t bytes, void** outPtr) @@ -54,15 +86,12 @@ CheckedBoolean CopiedSpace::tryAllocateSlowCase(size_t bytes, void** outPtr) if (isOversize(bytes)) return tryAllocateOversize(bytes, outPtr); - ASSERT(m_heap->globalData()->apiLock().currentThreadIsHoldingLock()); + ASSERT(m_heap->vm()->currentThreadIsHoldingAPILock()); m_heap->didAllocate(m_allocator.currentCapacity()); - if (!addNewBlock()) { - *outPtr = 0; - return false; - } - *outPtr = m_allocator.allocate(bytes); - ASSERT(*outPtr); + allocateBlock(); + + *outPtr = m_allocator.forceAllocate(bytes); return true; } @@ -70,21 +99,18 @@ CheckedBoolean CopiedSpace::tryAllocateOversize(size_t bytes, void** outPtr) { ASSERT(isOversize(bytes)); - size_t blockSize = WTF::roundUpToMultipleOf(WTF::pageSize(), sizeof(CopiedBlock) + bytes); - - PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, WTF::pageSize(), OSAllocator::JSGCHeapPages); - if (!static_cast(allocation)) { - *outPtr = 0; - return false; - } - - CopiedBlock* block = new (NotNull, allocation.base()) CopiedBlock(allocation); - m_oversizeBlocks.push(block); - m_oversizeFilter.add(reinterpret_cast(block)); + CopiedBlock* block = CopiedBlock::create(m_heap->blockAllocator().allocateCustomSize(sizeof(CopiedBlock) + bytes, CopiedBlock::blockSize)); + m_newGen.oversizeBlocks.push(block); + m_newGen.blockFilter.add(reinterpret_cast(block)); + m_blockSet.add(block); + ASSERT(!block->isOld()); - *outPtr = allocateFromBlock(block, bytes); + CopiedAllocator allocator; + allocator.setCurrentBlock(block); + *outPtr = allocator.forceAllocate(bytes); + allocator.resetCurrentBlock(); - m_heap->didAllocate(blockSize); + m_heap->didAllocate(block->region()->blockSize()); return true; } @@ -95,18 +121,13 @@ CheckedBoolean CopiedSpace::tryReallocate(void** ptr, size_t oldSize, size_t new return true; void* oldPtr = *ptr; - ASSERT(!m_heap->globalData()->isInitializingObject()); - - if (isOversize(oldSize) || isOversize(newSize)) + ASSERT(!m_heap->vm()->isInitializingObject()); + + if (CopiedSpace::blockFor(oldPtr)->isOversize() || isOversize(newSize)) return tryReallocateOversize(ptr, oldSize, newSize); - - if (m_allocator.wasLastAllocation(oldPtr, oldSize)) { - size_t delta = newSize - oldSize; - if (m_allocator.fitsInCurrentBlock(delta)) { - (void)m_allocator.allocate(delta); - return true; - } - } + + if (m_allocator.tryReallocate(oldPtr, oldSize, newSize)) + return true; void* result = 0; if (!tryAllocate(newSize, &result)) { @@ -133,43 +154,76 @@ CheckedBoolean CopiedSpace::tryReallocateOversize(void** ptr, size_t oldSize, si memcpy(newPtr, oldPtr, oldSize); - if (isOversize(oldSize)) { - CopiedBlock* oldBlock = oversizeBlockFor(oldPtr); - m_oversizeBlocks.remove(oldBlock); - oldBlock->m_allocation.deallocate(); + CopiedBlock* oldBlock = CopiedSpace::blockFor(oldPtr); + if (oldBlock->isOversize()) { + if (oldBlock->isOld()) + m_oldGen.oversizeBlocks.remove(oldBlock); + else + m_newGen.oversizeBlocks.remove(oldBlock); + m_blockSet.remove(oldBlock); + m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(oldBlock)); } *ptr = newPtr; return true; } -void CopiedSpace::doneFillingBlock(CopiedBlock* block) +void CopiedSpace::doneFillingBlock(CopiedBlock* block, CopiedBlock** exchange) { - ASSERT(block); - ASSERT(block->m_offset < reinterpret_cast(block) + HeapBlock::s_blockSize); ASSERT(m_inCopyingPhase); + + if (exchange) + *exchange = allocateBlockForCopyingPhase(); + + if (!block) + return; - if (block->m_offset == block->payload()) { - recycleBlock(block); + if (!block->dataSize()) { + recycleBorrowedBlock(block); return; } + block->zeroFillWilderness(); + { - MutexLocker locker(m_toSpaceLock); - m_toSpace->push(block); - m_toSpaceSet.add(block); - m_toSpaceFilter.add(reinterpret_cast(block)); + // Always put the block into the old gen because it's being promoted! + SpinLockHolder locker(&m_toSpaceLock); + m_oldGen.toSpace->push(block); + m_blockSet.add(block); + m_oldGen.blockFilter.add(reinterpret_cast(block)); } { MutexLocker locker(m_loanedBlocksLock); ASSERT(m_numberOfLoanedBlocks > 0); + ASSERT(m_inCopyingPhase); m_numberOfLoanedBlocks--; if (!m_numberOfLoanedBlocks) m_loanedBlocksCondition.signal(); } } +void CopiedSpace::didStartFullCollection() +{ + ASSERT(heap()->operationInProgress() == FullCollection); + ASSERT(m_oldGen.fromSpace->isEmpty()); + ASSERT(m_newGen.fromSpace->isEmpty()); + +#ifndef NDEBUG + for (CopiedBlock* block = m_newGen.toSpace->head(); block; block = block->next()) + ASSERT(!block->liveBytes()); + + for (CopiedBlock* block = m_newGen.oversizeBlocks.head(); block; block = block->next()) + ASSERT(!block->liveBytes()); +#endif + + for (CopiedBlock* block = m_oldGen.toSpace->head(); block; block = block->next()) + block->didSurviveGC(); + + for (CopiedBlock* block = m_oldGen.oversizeBlocks.head(); block; block = block->next()) + block->didSurviveGC(); +} + void CopiedSpace::doneCopying() { { @@ -178,92 +232,67 @@ void CopiedSpace::doneCopying() m_loanedBlocksCondition.wait(m_loanedBlocksLock); } - ASSERT(m_inCopyingPhase); + ASSERT(m_inCopyingPhase == m_shouldDoCopyPhase); m_inCopyingPhase = false; - while (!m_fromSpace->isEmpty()) { - CopiedBlock* block = static_cast(m_fromSpace->removeHead()); - if (block->m_isPinned) { - block->m_isPinned = false; - // We don't add the block to the toSpaceSet because it was never removed. - ASSERT(m_toSpaceSet.contains(block)); - m_toSpaceFilter.add(reinterpret_cast(block)); - m_toSpace->push(block); - continue; - } - m_toSpaceSet.remove(block); - m_heap->blockAllocator().deallocate(block); + DoublyLinkedList* toSpace; + DoublyLinkedList* fromSpace; + TinyBloomFilter* blockFilter; + if (heap()->operationInProgress() == FullCollection) { + toSpace = m_oldGen.toSpace; + fromSpace = m_oldGen.fromSpace; + blockFilter = &m_oldGen.blockFilter; + } else { + toSpace = m_newGen.toSpace; + fromSpace = m_newGen.fromSpace; + blockFilter = &m_newGen.blockFilter; } - CopiedBlock* curr = static_cast(m_oversizeBlocks.head()); - while (curr) { - CopiedBlock* next = static_cast(curr->next()); - if (!curr->m_isPinned) { - m_oversizeBlocks.remove(curr); - curr->m_allocation.deallocate(); - } else - curr->m_isPinned = false; - curr = next; + while (!fromSpace->isEmpty()) { + CopiedBlock* block = fromSpace->removeHead(); + // We don't add the block to the blockSet because it was never removed. + ASSERT(m_blockSet.contains(block)); + blockFilter->add(reinterpret_cast(block)); + block->didSurviveGC(); + toSpace->push(block); } - if (!m_toSpace->head()) { - if (!addNewBlock()) - CRASH(); - } else - m_allocator.resetCurrentBlock(static_cast(m_toSpace->head())); -} - -CheckedBoolean CopiedSpace::getFreshBlock(AllocationEffort allocationEffort, CopiedBlock** outBlock) -{ - CopiedBlock* block = 0; - if (allocationEffort == AllocationMustSucceed) { - if (HeapBlock* heapBlock = m_heap->blockAllocator().allocate()) - block = new (NotNull, heapBlock) CopiedBlock(heapBlock->m_allocation); - else if (!allocateNewBlock(&block)) { - *outBlock = 0; - ASSERT_NOT_REACHED(); - return false; - } - } else { - ASSERT(allocationEffort == AllocationCanFail); - if (m_heap->shouldCollect()) - m_heap->collect(Heap::DoNotSweep); - - if (!getFreshBlock(AllocationMustSucceed, &block)) { - *outBlock = 0; - ASSERT_NOT_REACHED(); - return false; - } + if (heap()->operationInProgress() == EdenCollection) { + m_oldGen.toSpace->append(*m_newGen.toSpace); + m_oldGen.oversizeBlocks.append(m_newGen.oversizeBlocks); + m_oldGen.blockFilter.add(m_newGen.blockFilter); + m_newGen.blockFilter.reset(); } - ASSERT(block); - ASSERT(is8ByteAligned(block->m_offset)); - *outBlock = block; - return true; -} -void CopiedSpace::freeAllBlocks() -{ - while (!m_toSpace->isEmpty()) - m_heap->blockAllocator().deallocate(m_toSpace->removeHead()); + ASSERT(m_newGen.toSpace->isEmpty()); + ASSERT(m_newGen.fromSpace->isEmpty()); + ASSERT(m_newGen.oversizeBlocks.isEmpty()); - while (!m_fromSpace->isEmpty()) - m_heap->blockAllocator().deallocate(m_fromSpace->removeHead()); + allocateBlock(); - while (!m_oversizeBlocks.isEmpty()) - m_oversizeBlocks.removeHead()->m_allocation.deallocate(); + m_shouldDoCopyPhase = false; } size_t CopiedSpace::size() { size_t calculatedSize = 0; - for (CopiedBlock* block = static_cast(m_toSpace->head()); block; block = static_cast(block->next())) + for (CopiedBlock* block = m_oldGen.toSpace->head(); block; block = block->next()) + calculatedSize += block->size(); + + for (CopiedBlock* block = m_oldGen.fromSpace->head(); block; block = block->next()) + calculatedSize += block->size(); + + for (CopiedBlock* block = m_oldGen.oversizeBlocks.head(); block; block = block->next()) + calculatedSize += block->size(); + + for (CopiedBlock* block = m_newGen.toSpace->head(); block; block = block->next()) calculatedSize += block->size(); - for (CopiedBlock* block = static_cast(m_fromSpace->head()); block; block = static_cast(block->next())) + for (CopiedBlock* block = m_newGen.fromSpace->head(); block; block = block->next()) calculatedSize += block->size(); - for (CopiedBlock* block = static_cast(m_oversizeBlocks.head()); block; block = static_cast(block->next())) + for (CopiedBlock* block = m_newGen.oversizeBlocks.head(); block; block = block->next()) calculatedSize += block->size(); return calculatedSize; @@ -273,22 +302,31 @@ size_t CopiedSpace::capacity() { size_t calculatedCapacity = 0; - for (CopiedBlock* block = static_cast(m_toSpace->head()); block; block = static_cast(block->next())) + for (CopiedBlock* block = m_oldGen.toSpace->head(); block; block = block->next()) + calculatedCapacity += block->capacity(); + + for (CopiedBlock* block = m_oldGen.fromSpace->head(); block; block = block->next()) + calculatedCapacity += block->capacity(); + + for (CopiedBlock* block = m_oldGen.oversizeBlocks.head(); block; block = block->next()) + calculatedCapacity += block->capacity(); + + for (CopiedBlock* block = m_newGen.toSpace->head(); block; block = block->next()) calculatedCapacity += block->capacity(); - for (CopiedBlock* block = static_cast(m_fromSpace->head()); block; block = static_cast(block->next())) + for (CopiedBlock* block = m_newGen.fromSpace->head(); block; block = block->next()) calculatedCapacity += block->capacity(); - for (CopiedBlock* block = static_cast(m_oversizeBlocks.head()); block; block = static_cast(block->next())) + for (CopiedBlock* block = m_newGen.oversizeBlocks.head(); block; block = block->next()) calculatedCapacity += block->capacity(); return calculatedCapacity; } -static bool isBlockListPagedOut(double deadline, DoublyLinkedList* list) +static bool isBlockListPagedOut(double deadline, DoublyLinkedList* list) { unsigned itersSinceLastTimeCheck = 0; - HeapBlock* current = list->head(); + CopiedBlock* current = list->head(); while (current) { current = current->next(); ++itersSinceLastTimeCheck; @@ -305,9 +343,12 @@ static bool isBlockListPagedOut(double deadline, DoublyLinkedList* li bool CopiedSpace::isPagedOut(double deadline) { - return isBlockListPagedOut(deadline, m_toSpace) - || isBlockListPagedOut(deadline, m_fromSpace) - || isBlockListPagedOut(deadline, &m_oversizeBlocks); + return isBlockListPagedOut(deadline, m_oldGen.toSpace) + || isBlockListPagedOut(deadline, m_oldGen.fromSpace) + || isBlockListPagedOut(deadline, &m_oldGen.oversizeBlocks) + || isBlockListPagedOut(deadline, m_newGen.toSpace) + || isBlockListPagedOut(deadline, m_newGen.fromSpace) + || isBlockListPagedOut(deadline, &m_newGen.oversizeBlocks); } } // namespace JSC