Changeset 96372 in webkit for trunk/Source/JavaScriptCore/heap


Ignore:
Timestamp:
Sep 29, 2011, 3:52:45 PM (14 years ago)
Author:
[email protected]
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/heap
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • 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);
Note: See TracChangeset for help on using the changeset viewer.