Ignore:
Timestamp:
Jul 14, 2012, 9:02:16 PM (13 years ago)
Author:
[email protected]
Message:

Rationalize and optimize storage allocation
https://bugs.webkit.org/show_bug.cgi?id=91303

Reviewed by Oliver Hunt.

This implements a backwards bump allocator for copied space storage
allocation, shown in pseudo-code below:

pointer bump(size) {

pointer tmp = allocator->remaining;
tmp -= size;
if (tmp < 0)

fail;

allocator->remaining = tmp;
return allocator->payloadEnd - tmp - size;

}

The advantage of this allocator is that it:

  • Only requires one comparison in the common case where size is known to not be huge, and this comparison can be done by checking the sign bit of the subtraction.


  • Can be implemented even when only one register is available. This register is reused for both temporary storage during allocation and for the result.


  • Preserves the behavior that memory in a block is filled in from lowest address to highest address, which allows for a cheap reallocation fast path.


  • Is resilient against the block used for allocation being the last one in virtual memory, thereby otherwise leading to the risk of overflow in the bump pointer, despite only doing one branch.


In order to implement this allocator using the smallest possible chunk
of code, I refactored the copied space code so that all of the allocation
logic is in CopiedAllocator, and all of the state is in either
CopiedBlock or CopiedAllocator. This should make changing the allocation
fast path easier in the future.

In order to do this, I needed to add some new assembler support,
particularly for various forms of add(address, register) and negPtr().

This is performance neutral. The purpose of this change is to facilitate
further inlining of storage allocation without having to reserve
additional registers or emit too much code.

  • assembler/MacroAssembler.h:

(JSC::MacroAssembler::addPtr):
(MacroAssembler):
(JSC::MacroAssembler::negPtr):

  • assembler/MacroAssemblerARMv7.h:

(MacroAssemblerARMv7):
(JSC::MacroAssemblerARMv7::add32):

  • assembler/MacroAssemblerX86.h:

(JSC::MacroAssemblerX86::add32):
(MacroAssemblerX86):

  • assembler/MacroAssemblerX86_64.h:

(MacroAssemblerX86_64):
(JSC::MacroAssemblerX86_64::addPtr):
(JSC::MacroAssemblerX86_64::negPtr):

  • assembler/X86Assembler.h:

(X86Assembler):
(JSC::X86Assembler::addl_mr):
(JSC::X86Assembler::addq_mr):
(JSC::X86Assembler::negq_r):

  • heap/CopiedAllocator.h:

(CopiedAllocator):
(JSC::CopiedAllocator::isValid):
(JSC::CopiedAllocator::CopiedAllocator):
(JSC::CopiedAllocator::tryAllocate):
(JSC):
(JSC::CopiedAllocator::tryReallocate):
(JSC::CopiedAllocator::forceAllocate):
(JSC::CopiedAllocator::resetCurrentBlock):
(JSC::CopiedAllocator::setCurrentBlock):
(JSC::CopiedAllocator::currentCapacity):

  • heap/CopiedBlock.h:

(CopiedBlock):
(JSC::CopiedBlock::create):
(JSC::CopiedBlock::zeroFillWilderness):
(JSC::CopiedBlock::CopiedBlock):
(JSC::CopiedBlock::payloadEnd):
(JSC):
(JSC::CopiedBlock::payloadCapacity):
(JSC::CopiedBlock::data):
(JSC::CopiedBlock::dataEnd):
(JSC::CopiedBlock::dataSize):
(JSC::CopiedBlock::wilderness):
(JSC::CopiedBlock::wildernessEnd):
(JSC::CopiedBlock::wildernessSize):
(JSC::CopiedBlock::size):

  • heap/CopiedSpace.cpp:

(JSC::CopiedSpace::tryAllocateSlowCase):
(JSC::CopiedSpace::tryAllocateOversize):
(JSC::CopiedSpace::tryReallocate):
(JSC::CopiedSpace::doneFillingBlock):
(JSC::CopiedSpace::doneCopying):

  • heap/CopiedSpace.h:

(CopiedSpace):

  • heap/CopiedSpaceInlineMethods.h:

(JSC::CopiedSpace::startedCopying):
(JSC::CopiedSpace::allocateBlockForCopyingPhase):
(JSC::CopiedSpace::allocateBlock):
(JSC::CopiedSpace::tryAllocate):
(JSC):

  • heap/MarkStack.cpp:

(JSC::SlotVisitor::startCopying):
(JSC::SlotVisitor::allocateNewSpace):
(JSC::SlotVisitor::doneCopying):

  • heap/SlotVisitor.h:

(JSC::SlotVisitor::SlotVisitor):

  • jit/JIT.h:
  • jit/JITInlineMethods.h:

(JSC::JIT::emitAllocateBasicStorage):
(JSC::JIT::emitAllocateJSArray):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp

    r121381 r122677  
    7272    allocateBlock();
    7373
    74     *outPtr = m_allocator.allocate(bytes);
    75     ASSERT(*outPtr);
     74    *outPtr = m_allocator.forceAllocate(bytes);
    7675    return true;
    7776}
     
    9493    m_blockSet.add(block);
    9594   
    96     *outPtr = allocateFromBlock(block, bytes);
     95    CopiedAllocator allocator;
     96    allocator.setCurrentBlock(block);
     97    *outPtr = allocator.forceAllocate(bytes);
     98    allocator.resetCurrentBlock();
    9799
    98100    m_heap->didAllocate(blockSize);
     
    108110    void* oldPtr = *ptr;
    109111    ASSERT(!m_heap->globalData()->isInitializingObject());
    110 
     112   
    111113    if (isOversize(oldSize) || isOversize(newSize))
    112114        return tryReallocateOversize(ptr, oldSize, newSize);
    113 
    114     if (m_allocator.wasLastAllocation(oldPtr, oldSize)) {
    115         size_t delta = newSize - oldSize;
    116         if (m_allocator.fitsInCurrentBlock(delta)) {
    117             (void)m_allocator.allocate(delta);
    118             return true;
    119         }
    120     }
     115   
     116    if (m_allocator.tryReallocate(oldPtr, oldSize, newSize))
     117        return true;
    121118
    122119    void* result = 0;
     
    158155void CopiedSpace::doneFillingBlock(CopiedBlock* block)
    159156{
    160     ASSERT(block);
    161     ASSERT(block->m_offset < reinterpret_cast<char*>(block) + HeapBlock::s_blockSize);
    162157    ASSERT(m_inCopyingPhase);
    163 
    164     if (block->m_offset == block->payload()) {
     158   
     159    if (!block)
     160        return;
     161
     162    if (!block->dataSize()) {
    165163        recycleBlock(block);
    166164        return;
    167165    }
    168166
    169     block->zeroFillToEnd();
     167    block->zeroFillWilderness();
    170168
    171169    {
     
    227225        allocateBlock();
    228226    else
    229         m_allocator.resetCurrentBlock(static_cast<CopiedBlock*>(m_toSpace->head()));
     227        m_allocator.setCurrentBlock(static_cast<CopiedBlock*>(m_toSpace->head()));
    230228}
    231229
Note: See TracChangeset for help on using the changeset viewer.