Ignore:
Timestamp:
Jul 14, 2011, 6:40:25 PM (14 years ago)
Author:
[email protected]
Message:

GC allocation fast path has too many operations.
https://bugs.webkit.org/show_bug.cgi?id=64493

Patch by Filip Pizlo <[email protected]> on 2011-07-14
Reviewed by Darin Adler.

Changed the timing of the lazy sweep so that it occurs when we land on
a previously-unsweeped block, rather than whenever we land on an unsweeped
cell. After the per-block lazy sweep occurs, the block is turned into a
singly linked list of free cells. The allocation fast path is now just a
load-branch-store to remove a cell from the head of the list.

Additionally, this changes the way new blocks are allocated. Previously,
they would be populated with dummy cells. With this patch, they are
turned into a free list, which means that there will never be destructor
calls for allocations in fresh blocks.

These changes result in a 1.9% speed-up on V8, and a 0.6% speed-up on
SunSpider. There are no observed statistically significant slow-downs
on any individual benchmark.

(JSC::Heap::allocateSlowCase):
(JSC::Heap::collect):
(JSC::Heap::canonicalizeBlocks):
(JSC::Heap::resetAllocator):

  • heap/Heap.h:

(JSC::Heap::forEachProtectedCell):
(JSC::Heap::forEachCell):
(JSC::Heap::forEachBlock):
(JSC::Heap::allocate):

  • heap/MarkedBlock.cpp:

(JSC::MarkedBlock::MarkedBlock):
(JSC::MarkedBlock::lazySweep):
(JSC::MarkedBlock::blessNewBlockForFastPath):
(JSC::MarkedBlock::blessNewBlockForSlowPath):
(JSC::MarkedBlock::canonicalizeBlock):

  • heap/MarkedBlock.h:
  • heap/NewSpace.cpp:

(JSC::NewSpace::addBlock):
(JSC::NewSpace::canonicalizeBlocks):

  • heap/NewSpace.h:

(JSC::NewSpace::allocate):
(JSC::NewSpace::SizeClass::SizeClass):
(JSC::NewSpace::SizeClass::canonicalizeBlock):

  • heap/OldSpace.cpp:

(JSC::OldSpace::addBlock):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/heap/NewSpace.h

    r89077 r91039  
    5151            SizeClass();
    5252            void resetAllocator();
    53 
     53            void canonicalizeBlock();
     54
     55            MarkedBlock::FreeCell* firstFreeCell;
     56            MarkedBlock* currentBlock;
    5457            MarkedBlock* nextBlock;
    5558            DoublyLinkedList<MarkedBlock> blockList;
     
    6568        void addBlock(SizeClass&, MarkedBlock*);
    6669        void removeBlock(MarkedBlock*);
     70       
     71        void canonicalizeBlocks();
    6772
    6873        size_t waterMark();
     
    116121    inline void* NewSpace::allocate(SizeClass& sizeClass)
    117122    {
    118         for (MarkedBlock*& block = sizeClass.nextBlock ; block; block = block->next()) {
    119             if (void* result = block->allocate())
    120                 return result;
    121 
    122             m_waterMark += block->capacity();
    123         }
    124 
    125         return 0;
     123        MarkedBlock::FreeCell* firstFreeCell = sizeClass.firstFreeCell;
     124        if (!firstFreeCell) {
     125            // There are two possibilities for why we got here:
     126            // 1) We've exhausted the allocation cache for currentBlock, in which case
     127            //    currentBlock == nextBlock, and we know that there is no reason to
     128            //    repeat a lazy sweep of nextBlock because we won't find anything.
     129            // 2) Allocation caches have been cleared, in which case nextBlock may
     130            //    have (and most likely does have) free cells, so we almost certainly
     131            //    should do a lazySweep for nextBlock. This also implies that
     132            //    currentBlock == 0.
     133           
     134            if (sizeClass.currentBlock) {
     135                ASSERT(sizeClass.currentBlock == sizeClass.nextBlock);
     136                m_waterMark += sizeClass.nextBlock->capacity();
     137                sizeClass.nextBlock = sizeClass.nextBlock->next();
     138                sizeClass.currentBlock = 0;
     139            }
     140           
     141            for (MarkedBlock*& block = sizeClass.nextBlock ; block; block = block->next()) {
     142                firstFreeCell = block->lazySweep();
     143                if (firstFreeCell) {
     144                    sizeClass.firstFreeCell = firstFreeCell;
     145                    sizeClass.currentBlock = block;
     146                    break;
     147                }
     148               
     149                m_waterMark += block->capacity();
     150            }
     151           
     152            if (!firstFreeCell)
     153                return 0;
     154        }
     155       
     156        ASSERT(firstFreeCell);
     157       
     158        sizeClass.firstFreeCell = firstFreeCell->next;
     159        return firstFreeCell;
    126160    }
    127161
     
    156190
    157191    inline NewSpace::SizeClass::SizeClass()
    158         : nextBlock(0)
     192        : firstFreeCell(0)
     193        , currentBlock(0)
     194        , nextBlock(0)
    159195        , cellSize(0)
    160196    {
     
    165201        nextBlock = blockList.head();
    166202    }
     203   
     204    inline void NewSpace::SizeClass::canonicalizeBlock()
     205    {
     206        if (currentBlock) {
     207            currentBlock->canonicalizeBlock(firstFreeCell);
     208            firstFreeCell = 0;
     209        }
     210       
     211        ASSERT(!firstFreeCell);
     212       
     213        currentBlock = 0;
     214        firstFreeCell = 0;
     215    }
    167216
    168217} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.