Changeset 128563 in webkit


Ignore:
Timestamp:
Sep 14, 2012 12:06:23 AM (12 years ago)
Author:
mhahnenberg@apple.com
Message:

Remove the Zapped BlockState
https://bugs.webkit.org/show_bug.cgi?id=96708

Reviewed by Geoffrey Garen.

The Zapped block state is rather confusing. It indicates that a block is in one of two different states that we
can't tell the difference between:

1) I have run all destructors of things that are zapped, and I have not allocated any more objects. This block

is ready for reclaiming if you so choose.

2) I have run all the destructors of things that are zapped, but I have allocated more stuff since then, so it

is not safe to reclaim this block.

This state adds a lot of complexity to our state transition model for MarkedBlocks. We should get rid of it.
We can replace this state by making sure mark bits represent all of the liveness information we need when running
our conservative stack scan. Instead of zapping the free list when canonicalizing cell liveness data prior to
a conservative scan, we can instead mark all objects in the block except for those in the free list. This should
incur no performance penalty since we're doing it on a very small O(1) number of blocks at the beginning of the collection.

For the time being we still need to use zapping to determine whether we have run an object's destructor or not.

  • heap/MarkedAllocator.cpp:

(JSC::MarkedAllocator::tryAllocateHelper): Renaming stuff.

  • heap/MarkedAllocator.h: Renamed zapFreeList to canonicalizeCellLivenessData to match.

(MarkedAllocator):
(JSC::MarkedAllocator::canonicalizeCellLivenessData): Same as old zapFreeList, but just call canonicalize instead.

  • heap/MarkedBlock.cpp:

(JSC::MarkedBlock::specializedSweep): Remove the check for Zapped block stuff. Also change the block state to Marked
instead of Zapped if we're not producing a FreeList since that's the only other state that really makes any sense.
(JSC::MarkedBlock::sweepHelper): Remove Zapped related code.
(SetAllMarksFunctor): Functor to set all the mark bits in the block since there's not a simple function to call on
the Bitmap itself.
(JSC::SetAllMarksFunctor::operator()):
(JSC):
(JSC::MarkedBlock::canonicalizeCellLivenessData): Remove all the stuff for Zapped. For FreeListed, set all the mark bits
and then clear the ones for the objects in the FreeList. This ensures that only the things that were in the FreeList
are considered to be dead by the conservative scan, just like if we were to have zapped the FreeList like before.

  • heap/MarkedBlock.h:

(MarkedBlock):
(JSC::MarkedBlock::clearMarked): Add function to clear individual mark bits, since we need that functionality now.
(JSC):
(JSC::MarkedBlock::isLive): Remove code for Zapped stuff. Marked handles all interesting cases now.
(JSC::MarkedBlock::forEachCell): Add new iterator function that iterates over all cells in the block, regardless of
whether they're live or a dead.

  • heap/MarkedSpace.cpp:

(JSC::MarkedSpace::canonicalizeCellLivenessData): Change to call the renamed canonicalize function.

Location:
trunk/Source/JavaScriptCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r128558 r128563  
     12012-09-14  Mark Hahnenberg  <mhahnenberg@apple.com>
     2
     3        Remove the Zapped BlockState
     4        https://bugs.webkit.org/show_bug.cgi?id=96708
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        The Zapped block state is rather confusing. It indicates that a block is in one of two different states that we
     9        can't tell the difference between:
     10
     11        1) I have run all destructors of things that are zapped, and I have not allocated any more objects. This block
     12           is ready for reclaiming if you so choose.
     13        2) I have run all the destructors of things that are zapped, but I have allocated more stuff since then, so it
     14           is not safe to reclaim this block.
     15
     16        This state adds a lot of complexity to our state transition model for MarkedBlocks. We should get rid of it.
     17        We can replace this state by making sure mark bits represent all of the liveness information we need when running
     18        our conservative stack scan. Instead of zapping the free list when canonicalizing cell liveness data prior to
     19        a conservative scan, we can instead mark all objects in the block except for those in the free list. This should
     20        incur no performance penalty since we're doing it on a very small O(1) number of blocks at the beginning of the collection.
     21
     22        For the time being we still need to use zapping to determine whether we have run an object's destructor or not.
     23
     24        * heap/MarkedAllocator.cpp:
     25        (JSC::MarkedAllocator::tryAllocateHelper): Renaming stuff.
     26        * heap/MarkedAllocator.h: Renamed zapFreeList to canonicalizeCellLivenessData to match.
     27        (MarkedAllocator):
     28        (JSC::MarkedAllocator::canonicalizeCellLivenessData): Same as old zapFreeList, but just call canonicalize instead.
     29        * heap/MarkedBlock.cpp:
     30        (JSC::MarkedBlock::specializedSweep): Remove the check for Zapped block stuff. Also change the block state to Marked
     31        instead of Zapped if we're not producing a FreeList since that's the only other state that really makes any sense.
     32        (JSC::MarkedBlock::sweepHelper): Remove Zapped related code.
     33        (SetAllMarksFunctor): Functor to set all the mark bits in the block since there's not a simple function to call on
     34        the Bitmap itself.
     35        (JSC::SetAllMarksFunctor::operator()):
     36        (JSC):
     37        (JSC::MarkedBlock::canonicalizeCellLivenessData): Remove all the stuff for Zapped. For FreeListed, set all the mark bits
     38        and then clear the ones for the objects in the FreeList. This ensures that only the things that were in the FreeList
     39        are considered to be dead by the conservative scan, just like if we were to have zapped the FreeList like before.
     40        * heap/MarkedBlock.h:
     41        (MarkedBlock):
     42        (JSC::MarkedBlock::clearMarked): Add function to clear individual mark bits, since we need that functionality now.
     43        (JSC):
     44        (JSC::MarkedBlock::isLive): Remove code for Zapped stuff. Marked handles all interesting cases now.
     45        (JSC::MarkedBlock::forEachCell): Add new iterator function that iterates over all cells in the block, regardless of
     46        whether they're live or a dead.
     47        * heap/MarkedSpace.cpp:
     48        (JSC::MarkedSpace::canonicalizeCellLivenessData): Change to call the renamed canonicalize function.
     49
    1502012-09-13  Kevin Funk  <kevin.funk@kdab.com>
    251
  • trunk/Source/JavaScriptCore/heap/MarkedAllocator.cpp

    r128141 r128563  
    5050
    5151            if (bytes > block->cellSize()) {
    52                 block->zapFreeList(freeList);
     52                block->canonicalizeCellLivenessData(freeList);
    5353                continue;
    5454            }
  • trunk/Source/JavaScriptCore/heap/MarkedAllocator.h

    r128141 r128563  
    2222    MarkedAllocator();
    2323    void reset();
    24     void zapFreeList();
     24    void canonicalizeCellLivenessData();
    2525    size_t cellSize() { return m_cellSize; }
    2626    bool cellsNeedDestruction() { return m_cellsNeedDestruction; }
     
    9393}
    9494
    95 inline void MarkedAllocator::zapFreeList()
     95inline void MarkedAllocator::canonicalizeCellLivenessData()
    9696{
    9797    if (!m_currentBlock) {
     
    100100    }
    101101   
    102     m_currentBlock->zapFreeList(m_freeList);
     102    m_currentBlock->canonicalizeCellLivenessData(m_freeList);
    103103    m_currentBlock = 0;
    104104    m_freeList = MarkedBlock::FreeList();
  • trunk/Source/JavaScriptCore/heap/MarkedBlock.cpp

    r127338 r128563  
    8282
    8383        JSCell* cell = reinterpret_cast_ptr<JSCell*>(&atoms()[i]);
    84         if (blockState == Zapped && !cell->isZapped())
    85             continue;
    8684
    8785        if (destructorCallNeeded && blockState != New)
     
    9694    }
    9795
    98     m_state = ((sweepMode == SweepToFreeList) ? FreeListed : Zapped);
     96    m_state = ((sweepMode == SweepToFreeList) ? FreeListed : Marked);
    9997    return FreeList(head, count * cellSize());
    10098}
     
    133131            ? specializedSweep<Marked, SweepToFreeList, destructorCallNeeded>()
    134132            : specializedSweep<Marked, SweepOnly, destructorCallNeeded>();
    135     case Zapped:
    136         ASSERT(!m_onlyContainsStructures || heap()->isSafeToSweepStructures());
    137         return sweepMode == SweepToFreeList
    138             ? specializedSweep<Zapped, SweepToFreeList, destructorCallNeeded>()
    139             : specializedSweep<Zapped, SweepOnly, destructorCallNeeded>();
    140133    }
    141134
     
    144137}
    145138
    146 void MarkedBlock::zapFreeList(const FreeList& freeList)
     139class SetAllMarksFunctor : public MarkedBlock::VoidFunctor {
     140public:
     141    void operator()(JSCell* cell)
     142    {
     143        MarkedBlock::blockFor(cell)->setMarked(cell);
     144    }
     145};
     146
     147void MarkedBlock::canonicalizeCellLivenessData(const FreeList& freeList)
    147148{
    148149    HEAP_LOG_BLOCK_STATE_TRANSITION(this);
     
    157158       
    158159        ASSERT(!head);
    159        
    160160        return;
    161161    }
    162    
    163     if (m_state == Zapped) {
    164         // If the block is in the Zapped state then we know that someone already
    165         // zapped it for us. This could not have happened during a GC, but might
    166         // be the result of someone having done a GC scan to perform some operation
    167         // over all live objects (or all live blocks). It also means that somebody
    168         // had allocated in this block since the last GC, swept all dead objects
    169         // onto the free list, left the block in the FreeListed state, then the heap
    170         // scan happened, and canonicalized the block, leading to all dead objects
    171         // being zapped. Therefore, it is safe for us to simply do nothing, since
    172         // dead objects will have 0 in their vtables and live objects will have
    173         // non-zero vtables, which is consistent with the block being zapped.
    174        
    175         ASSERT(!head);
    176        
    177         return;
    178     }
    179    
     162   
    180163    ASSERT(m_state == FreeListed);
    181164   
    182165    // Roll back to a coherent state for Heap introspection. Cells newly
    183166    // allocated from our free list are not currently marked, so we need another
    184     // way to tell what's live vs dead. We use zapping for that.
     167    // way to tell what's live vs dead.
    185168   
     169    SetAllMarksFunctor functor;
     170    forEachCell(functor);
     171
    186172    FreeCell* next;
    187173    for (FreeCell* current = head; current; current = next) {
    188174        next = current->next;
    189175        reinterpret_cast<JSCell*>(current)->zap();
     176        clearMarked(current);
    190177    }
    191178   
    192     m_state = Zapped;
     179    m_state = Marked;
    193180}
    194181
  • trunk/Source/JavaScriptCore/heap/MarkedBlock.h

    r128498 r128563  
    137137        // of these functions:
    138138        void didConsumeFreeList(); // Call this once you've allocated all the items in the free list.
    139         void zapFreeList(const FreeList&); // Call this to undo the free list.
     139        void canonicalizeCellLivenessData(const FreeList&);
    140140
    141141        void clearMarks();
     
    155155        bool isLiveCell(const void*);
    156156        void setMarked(const void*);
    157        
     157        void clearMarked(const void*);
     158
    158159        bool needsSweeping();
    159160
     
    186187#endif
    187188
     189        template <typename Functor> void forEachCell(Functor&);
    188190        template <typename Functor> void forEachLiveCell(Functor&);
    189191        template <typename Functor> void forEachDeadCell(Functor&);
     
    192194        static const size_t atomAlignmentMask = atomSize - 1; // atomSize must be a power of two.
    193195
    194         enum BlockState { New, FreeListed, Allocated, Marked, Zapped };
     196        enum BlockState { New, FreeListed, Allocated, Marked };
    195197        template<bool destructorCallNeeded> FreeList sweepHelper(SweepMode = SweepOnly);
    196198
     
    365367    }
    366368
     369    inline void MarkedBlock::clearMarked(const void* p)
     370    {
     371        ASSERT(m_marks.get(atomNumber(p)));
     372        m_marks.clear(atomNumber(p));
     373    }
     374
    367375    inline bool MarkedBlock::isLive(const JSCell* cell)
    368376    {
     
    370378        case Allocated:
    371379            return true;
    372         case Zapped:
    373             if (isZapped(cell)) {
    374                 // Object dead in previous collection, not allocated since previous collection: mark bit should not be set.
    375                 ASSERT(!m_marks.get(atomNumber(cell)));
    376                 return false;
    377             }
    378            
    379             // Newly allocated objects: mark bit not set.
    380             // Objects that survived prior collection: mark bit set.
    381             return true;
     380
    382381        case Marked:
    383382            return m_marks.get(atomNumber(cell));
     
    406405
    407406        return isLive(static_cast<const JSCell*>(p));
     407    }
     408
     409    template <typename Functor> inline void MarkedBlock::forEachCell(Functor& functor)
     410    {
     411        for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) {
     412            JSCell* cell = reinterpret_cast_ptr<JSCell*>(&atoms()[i]);
     413            functor(cell);
     414        }
    408415    }
    409416
  • trunk/Source/JavaScriptCore/heap/MarkedSpace.cpp

    r128141 r128563  
    147147{
    148148    for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) {
    149         allocatorFor(cellSize).zapFreeList();
    150         destructorAllocatorFor(cellSize).zapFreeList();
    151     }
    152 
    153     for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) {
    154         allocatorFor(cellSize).zapFreeList();
    155         destructorAllocatorFor(cellSize).zapFreeList();
    156     }
    157 
    158     m_largeAllocator.zapFreeList();
    159     m_structureAllocator.zapFreeList();
     149        allocatorFor(cellSize).canonicalizeCellLivenessData();
     150        destructorAllocatorFor(cellSize).canonicalizeCellLivenessData();
     151    }
     152
     153    for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) {
     154        allocatorFor(cellSize).canonicalizeCellLivenessData();
     155        destructorAllocatorFor(cellSize).canonicalizeCellLivenessData();
     156    }
     157
     158    m_largeAllocator.canonicalizeCellLivenessData();
     159    m_structureAllocator.canonicalizeCellLivenessData();
    160160}
    161161
Note: See TracChangeset for help on using the changeset viewer.