Changeset 96372 in webkit


Ignore:
Timestamp:
Sep 29, 2011 3:52:45 PM (13 years ago)
Author:
oliver@apple.com
Message:

Add logic to collect dirty objects as roots
https://bugs.webkit.org/show_bug.cgi?id=69100

Reviewed by Geoff Garen.

This gives us the ability to walk all the MarkedBlocks in an
AllocationSpace and collect the dirty objects, and then use
them as GC roots.

  • dfg/DFGJITCodeGenerator.cpp:

(JSC::DFG::JITCodeGenerator::markCellCard):

  • dfg/DFGJITCodeGenerator32_64.cpp:

(JSC::DFG::JITCodeGenerator::markCellCard):

  • heap/AllocationSpace.cpp:

Tidy up the write barrier logic a bit

(JSC::MarkedBlock::gatherDirtyObjects):
(JSC::TakeIfDirty::returnValue):
(JSC::TakeIfDirty::TakeIfDirty):
(JSC::TakeIfDirty::operator()):
(JSC::AllocationSpace::gatherDirtyObjects):

  • heap/AllocationSpace.h:
  • heap/CardSet.h:

(JSC::::isCardMarked):
(JSC::::clearCard):

  • heap/Heap.cpp:

(JSC::Heap::markRoots):

  • heap/Heap.h:

(JSC::Heap::writeBarrier):

  • heap/MarkStack.cpp:

(JSC::SlotVisitor::visitChildren):

  • heap/MarkedBlock.h:

(JSC::MarkedBlock::setDirtyObject):
(JSC::MarkedBlock::addressOfCardFor):

  • heap/SlotVisitor.h:
  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emitWriteBarrier):

Tidy the write barrier a bit

Location:
trunk/Source/JavaScriptCore
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r96363 r96372  
     12011-09-29  Oliver Hunt  <oliver@apple.com>
     2
     3        Add logic to collect dirty objects as roots
     4        https://bugs.webkit.org/show_bug.cgi?id=69100
     5
     6        Reviewed by Geoff Garen.
     7
     8        This gives us the ability to walk all the MarkedBlocks in an
     9        AllocationSpace and collect the dirty objects, and then use
     10        them as GC roots.
     11       
     12        I also rearranged the order of these instructions because it
     13        makes them smaller on some platforms with some card sizes.
     14
     15        * dfg/DFGJITCodeGenerator.cpp:
     16        (JSC::DFG::JITCodeGenerator::markCellCard):
     17        * dfg/DFGJITCodeGenerator32_64.cpp:
     18        (JSC::DFG::JITCodeGenerator::markCellCard):
     19        * heap/AllocationSpace.cpp:
     20           Tidy up the write barrier logic a bit.
     21        (JSC::MarkedBlock::gatherDirtyObjects):
     22        (JSC::TakeIfDirty::returnValue):
     23        (JSC::TakeIfDirty::TakeIfDirty):
     24        (JSC::TakeIfDirty::operator()):
     25        (JSC::AllocationSpace::gatherDirtyObjects):
     26        * heap/AllocationSpace.h:
     27        * heap/CardSet.h:
     28        (JSC::::isCardMarked):
     29        (JSC::::clearCard):
     30        * heap/Heap.cpp:
     31        (JSC::Heap::markRoots):
     32        * heap/Heap.h:
     33        (JSC::Heap::writeBarrier):
     34        * heap/MarkStack.cpp:
     35        (JSC::SlotVisitor::visitChildren):
     36        * heap/MarkedBlock.h:
     37        (JSC::MarkedBlock::setDirtyObject):
     38        (JSC::MarkedBlock::addressOfCardFor):
     39        * heap/SlotVisitor.h:
     40        * jit/JITPropertyAccess.cpp:
     41        (JSC::JIT::emitWriteBarrier):
     42           Tidy the write barrier a bit.
     43
    1442011-09-29  Gavin Barraclough  <barraclough@apple.com>
    245
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp

    r95930 r96372  
    12061206    jit.andPtr(TrustedImm32(static_cast<int32_t>(MarkedBlock::blockMask)), scratch1);
    12071207    jit.move(owner, scratch2);
    1208     jit.andPtr(TrustedImm32(static_cast<int32_t>(~MarkedBlock::blockMask)), scratch2);
    1209     jit.rshift32(TrustedImm32(MarkedBlock::log2CardSize), scratch2);
     1208    jit.rshift32(TrustedImm32(MarkedBlock::cardShift), scratch2);
     1209    jit.andPtr(TrustedImm32(MarkedBlock::cardMask), scratch2);
    12101210    jit.store8(TrustedImm32(1), MacroAssembler::BaseIndex(scratch1, scratch2, MacroAssembler::TimesOne, MarkedBlock::offsetOfCards()));
    12111211#endif
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator32_64.cpp

    r96230 r96372  
    12561256    jit.andPtr(TrustedImm32(static_cast<int32_t>(MarkedBlock::blockMask)), scratch1);
    12571257    jit.move(owner, scratch2);
    1258     jit.andPtr(TrustedImm32(static_cast<int32_t>(~MarkedBlock::blockMask)), scratch2);
    1259     jit.rshift32(TrustedImm32(MarkedBlock::log2CardSize), scratch2);
     1258    jit.rshift32(TrustedImm32(MarkedBlock::cardShift), scratch2);
     1259    jit.andPtr(TrustedImm32(MarkedBlock::cardMask), scratch2);
    12601260    jit.store8(TrustedImm32(1), MacroAssembler::BaseIndex(scratch1, scratch2, MacroAssembler::TimesOne, MarkedBlock::offsetOfCards()));
    12611261#endif
  • trunk/Source/JavaScriptCore/heap/AllocationSpace.cpp

    r95912 r96372  
    163163}
    164164
     165#if ENABLE(GGC)
     166class GatherDirtyCells {
     167    WTF_MAKE_NONCOPYABLE(GatherDirtyCells);
     168public:
     169    typedef void* ReturnType;
     170   
     171    explicit GatherDirtyCells(MarkedBlock::DirtyCellVector*);
     172    void operator()(MarkedBlock*);
     173    ReturnType returnValue() { return 0; }
     174   
     175private:
     176    MarkedBlock::DirtyCellVector* m_dirtyCells;
     177};
     178
     179inline GatherDirtyCells::GatherDirtyCells(MarkedBlock::DirtyCellVector* dirtyCells)
     180    : m_dirtyCells(dirtyCells)
     181{
    165182}
     183
     184inline void GatherDirtyCells::operator()(MarkedBlock* block)
     185{
     186    block->gatherDirtyCells(*m_dirtyCells);
     187}
     188
     189void AllocationSpace::gatherDirtyCells(MarkedBlock::DirtyCellVector& dirtyCells)
     190{
     191    GatherDirtyCells gatherDirtyCells(&dirtyCells);
     192    forEachBlock(gatherDirtyCells);
     193}
     194#endif
     195
     196}
  • trunk/Source/JavaScriptCore/heap/AllocationSpace.h

    r95912 r96372  
    5151    void setHighWaterMark(size_t bytes) { m_markedSpace.setHighWaterMark(bytes); }
    5252    size_t highWaterMark() { return m_markedSpace.highWaterMark(); }
    53    
     53
     54    void gatherDirtyCells(MarkedBlock::DirtyCellVector&);
     55
    5456    template<typename Functor> typename Functor::ReturnType forEachCell(Functor&);
    5557    template<typename Functor> typename Functor::ReturnType forEachCell();
  • trunk/Source/JavaScriptCore/heap/CardSet.h

    r95865 r96372  
    3535template <size_t cardSize, size_t blockSize> class CardSet {
    3636    WTF_MAKE_NONCOPYABLE(CardSet);
     37
     38public:
    3739    static const size_t cardCount = (blockSize + cardSize - 1) / cardSize;
    3840
    39 public:
    4041    CardSet()
    4142    {
     
    4647    void markCardForAtom(const void*);
    4748    uint8_t& cardForAtom(const void*);
     49    bool isCardMarked(size_t);
     50    void clearCard(size_t);
    4851
    4952private:
     
    7073}
    7174
     75template <size_t cardSize, size_t blockSize> bool CardSet<cardSize, blockSize>::isCardMarked(size_t i)
     76{
     77    ASSERT(i < cardCount);
     78    return m_cards[i];
     79}
     80
     81template <size_t cardSize, size_t blockSize> void CardSet<cardSize, blockSize>::clearCard(size_t i)
     82{
     83    ASSERT(i < cardCount);
     84    m_cards[i] = 0;
     85}
     86
    7287}
    7388
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r95912 r96372  
    472472    registerFile().gatherConservativeRoots(registerFileRoots, m_jettisonedCodeBlocks);
    473473    m_jettisonedCodeBlocks.deleteUnmarkedCodeBlocks();
    474 
    475     clearMarks();
     474#if ENABLE(GGC)
     475    MarkedBlock::DirtyCellVector dirtyCells;
     476    // Until we have a sensible policy we just random choose to perform
     477    // young generation collections 90% of the time.
     478    if (WTF::randomNumber() > 0.1)
     479        m_objectSpace.gatherDirtyCells(dirtyCells);
     480    else
     481#endif
     482        clearMarks();
     483
    476484
    477485    SlotVisitor& visitor = m_slotVisitor;
    478486    HeapRootVisitor heapRootVisitor(visitor);
    479    
     487
     488#if ENABLE(GGC)
     489    for (size_t i = 0; i < dirtyObjectCount; i++) {
     490        heapRootVisitor.visitChildren(dirtyCells[i]);
     491        visitor.drain();
     492    }
     493#endif
     494
    480495    visitor.append(machineThreadRoots);
    481496    visitor.drain();
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r95912 r96372  
    241241    {
    242242        WriteBarrierCounters::countWriteBarrier();
    243         MarkedBlock::blockFor(owner)->setDirtyObject(owner);
     243        MarkedBlock* block = MarkedBlock::blockFor(owner);
     244        if (block->isMarked(owner))
     245            block->setDirtyObject(owner);
    244246    }
    245247
  • trunk/Source/JavaScriptCore/heap/HeapRootVisitor.h

    r95901 r96372  
    4444        void visit(JSString**);
    4545        void visit(JSCell**);
    46        
     46        void visitChildren(JSCell*);
     47
    4748        SlotVisitor& visitor();
    4849
     
    7677    }
    7778
     79    inline void HeapRootVisitor::visitChildren(JSCell* cell)
     80    {
     81        m_visitor.visitChildren(cell);
     82    }
     83
    7884    inline SlotVisitor& HeapRootVisitor::visitor()
    7985    {
  • trunk/Source/JavaScriptCore/heap/MarkStack.cpp

    r96346 r96372  
    5252}
    5353
    54 inline void SlotVisitor::visitChildren(JSCell* cell)
     54void SlotVisitor::visitChildren(JSCell* cell)
    5555{
    5656#if ENABLE(SIMPLE_HEAP_PROFILING)
  • trunk/Source/JavaScriptCore/heap/MarkedBlock.h

    r96068 r96372  
    3030#include <wtf/PageAllocationAligned.h>
    3131#include <wtf/StdLibExtras.h>
     32#include <wtf/Vector.h>
    3233
    3334// Set to log state transitions of blocks.
     
    7374
    7475        static const size_t atomsPerBlock = blockSize / atomSize; // ~0.4% overhead
    75         static const size_t bytesPerCard = 512; // 1.6% overhead
    76         static const int log2CardSize = 9;
     76        static const int cardShift = 10; // This is log2 of bytes per card.
     77        static const size_t bytesPerCard = 1 << cardShift;
     78        static const int cardCount = blockSize / bytesPerCard;
     79        static const int cardMask = cardCount - 1;
    7780
    7881        struct FreeCell {
     
    124127        void setDirtyObject(const void* atom)
    125128        {
     129            ASSERT(MarkedBlock::blockFor(atom) == this);
    126130            m_cards.markCardForAtom(atom);
    127131        }
     
    129133        uint8_t* addressOfCardFor(const void* atom)
    130134        {
     135            ASSERT(MarkedBlock::blockFor(atom) == this);
    131136            return &m_cards.cardForAtom(atom);
    132137        }
     
    136141            return OBJECT_OFFSETOF(MarkedBlock, m_cards);
    137142        }
     143
     144        typedef Vector<JSCell*, 32> DirtyCellVector;
     145        inline void gatherDirtyCells(DirtyCellVector&);
    138146#endif
    139147
     
    301309    }
    302310
     311#if ENABLE(GGC)
     312void MarkedBlock::gatherDirtyCells(DirtyCellVector& dirtyCells)
     313{
     314    COMPILE_ASSERT(m_cards.cardCount == cardCount, MarkedBlockCardCountsMatch);
     315
     316    ASSERT(m_state != New && m_state != FreeListed);
     317   
     318    // This is an optimisation to avoid having to walk the set of marked
     319    // blocks twice during GC.
     320    m_state = Marked;
     321   
     322    if (markCountIsZero())
     323        return;
     324   
     325    size_t cellSize = this->cellSize();
     326    const size_t firstCellOffset = firstAtom() * atomSize % cellSize;
     327   
     328    for (size_t i = 0; i < m_cards.cardCount; i++) {
     329        if (!m_cards.isCardMarked(i))
     330            continue;
     331        char* ptr = reinterpret_cast<char*>(this);
     332        if (i)
     333            ptr += firstCellOffset + cellSize * ((i * bytesPerCard + cellSize - 1 - firstCellOffset) / cellSize);
     334        else
     335            ptr += firstAtom() * atomSize;
     336        char* end = reinterpret_cast<char*>(this) + std::min((i + 1) * bytesPerCard, m_endAtom * atomSize);
     337       
     338        while (ptr < end) {
     339            JSCell* cell = reinterpret_cast<JSCell*>(ptr);
     340            ASSERT(*addressOfCardFor(cell));
     341            if (isMarked(cell))
     342                dirtyCells.append(cell);
     343            ptr += cellSize;
     344        }
     345        m_cards.clearCard(i);
     346    }
     347}
     348#endif
     349
    303350} // namespace JSC
    304351
  • trunk/Source/JavaScriptCore/heap/SlotVisitor.h

    r95901 r96372  
    3232
    3333class SlotVisitor : public MarkStack {
     34    friend class HeapRootVisitor;
    3435public:
    3536    SlotVisitor(void* jsArrayVPtr);
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp

    r95918 r96372  
    10451045    andPtr(TrustedImm32(static_cast<int32_t>(MarkedBlock::blockMask)), scratch);
    10461046    move(owner, scratch2);
    1047     andPtr(TrustedImm32(static_cast<int32_t>(~MarkedBlock::blockMask)), scratch2);
    1048     rshift32(TrustedImm32(MarkedBlock::log2CardSize), scratch2);
     1047    rshift32(TrustedImm32(MarkedBlock::cardShift), scratch2);
     1048    andPtr(TrustedImm32(MarkedBlock::cardMask), scratch2);
    10491049    store8(TrustedImm32(1), BaseIndex(scratch, scratch2, TimesOne, MarkedBlock::offsetOfCards()));
    10501050    if (mode == ShouldFilterImmediates)
Note: See TracChangeset for help on using the changeset viewer.