Changeset 124123 in webkit


Ignore:
Timestamp:
Jul 30, 2012 5:33:53 PM (12 years ago)
Author:
mhahnenberg@apple.com
Message:

Structures should be swept after all other objects
https://bugs.webkit.org/show_bug.cgi?id=92679

Reviewed by Filip Pizlo.

In order to get rid of ClassInfo from our objects, we need to be able to safely get the
ClassInfo during the destruction of objects. We'd like to get the ClassInfo out of the
Structure, but currently it is not safe to do so because the order of destruction of objects
is not guaranteed to sweep objects before their corresponding Structure. We can fix this by
sweeping Structures after everything else.

  • heap/Heap.cpp:

(JSC::Heap::isSafeToSweepStructures): Add a function that checks if it is safe to sweep Structures.
If the Heap's IncrementalSweeper member is null, that means we're shutting down this VM and it is
safe to sweep structures since we'll always do Structures last anyways due to the ordering of
MarkedSpace::forEachBlock.
(JSC):
(JSC::Heap::didStartVMShutdown): Add this intermediate function to the Heap that ~JSGlobalData now
calls rather than calling the two HeapTimer objects individually. This allows the Heap to null out
these pointers after it has invalidated them to prevent accidental use-after-free in the sweep()
calls during lastChanceToFinalize().

  • heap/Heap.h:

(Heap):

  • heap/HeapTimer.h:

(HeapTimer):

  • heap/IncrementalSweeper.cpp:

(JSC::IncrementalSweeper::structuresCanBeSwept): Determines if it is currently safe to sweep Structures.
This decision is based on whether we have gotten to the end of the vector of blocks that need sweeping
the first time.
(JSC):
(JSC::IncrementalSweeper::doSweep): We add a second pass over the vector to sweep Structures after we
make our first pass. We now null out the slots as we sweep them so that we can quickly find the
Structures during the second pass.
(JSC::IncrementalSweeper::startSweeping): Initialize our new Structure sweeping index.
(JSC::IncrementalSweeper::willFinishSweeping): Callback that is called by MarkedSpace::sweep to notify
the IncrementalSweeper that we are going to sweep all of the remaining blocks in the Heap so it can
assume that everything is taken care of in the correct order. Since MarkedSpace::forEachBlock
iterates over the Structure blocks after all other blocks, the ordering property for sweeping Structures holds.
(JSC::IncrementalSweeper::IncrementalSweeper): Initialize Structure sweeping index.

  • heap/IncrementalSweeper.h: Add declarations for new stuff.

(IncrementalSweeper):

  • heap/MarkedAllocator.cpp:

(JSC::MarkedAllocator::tryAllocateHelper): We now check if the current block only contains structures and
if so and it isn't safe to sweep Structures according to the Heap, we just return early instead of doing
the normal lazy sweep. If this proves to be too much of a waste in the future we can add an extra clause that
will sweep some number of other blocks in place of the current block to mitigate the cost of the floating
Structure garbage.
(JSC::MarkedAllocator::addBlock):

  • heap/MarkedAllocator.h:

(JSC::MarkedAllocator::zapFreeList): When we zap the free list in the MarkedAllocator, the current block is no
longer valid to allocate from, so we set the current block to null.

  • heap/MarkedBlock.cpp:

(JSC::MarkedBlock::sweepHelper): Added a couple assertions to make sure that we weren't trying to sweep Structures
at an unsafe time.

  • heap/MarkedSpace.cpp:

(JSC::MarkedSpace::sweep): Notify the IncrementalSweeper that the MarkedSpace will finish all currently remaining sweeping.
(JSC):

  • heap/MarkedSpace.h:

(JSC):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::~JSGlobalData): Call the new Heap::didStartVMShutdown.

Location:
trunk/Source/JavaScriptCore
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r123989 r124123  
     12012-07-30  Mark Hahnenberg  <mhahnenberg@apple.com>
     2
     3        Structures should be swept after all other objects
     4        https://bugs.webkit.org/show_bug.cgi?id=92679
     5
     6        Reviewed by Filip Pizlo.
     7
     8        In order to get rid of ClassInfo from our objects, we need to be able to safely get the
     9        ClassInfo during the destruction of objects. We'd like to get the ClassInfo out of the
     10        Structure, but currently it is not safe to do so because the order of destruction of objects
     11        is not guaranteed to sweep objects before their corresponding Structure. We can fix this by
     12        sweeping Structures after everything else.
     13
     14        * heap/Heap.cpp:
     15        (JSC::Heap::isSafeToSweepStructures): Add a function that checks if it is safe to sweep Structures.
     16        If the Heap's IncrementalSweeper member is null, that means we're shutting down this VM and it is
     17        safe to sweep structures since we'll always do Structures last anyways due to the ordering of
     18        MarkedSpace::forEachBlock.
     19        (JSC):
     20        (JSC::Heap::didStartVMShutdown): Add this intermediate function to the Heap that ~JSGlobalData now
     21        calls rather than calling the two HeapTimer objects individually. This allows the Heap to null out
     22        these pointers after it has invalidated them to prevent accidental use-after-free in the sweep()
     23        calls during lastChanceToFinalize().
     24        * heap/Heap.h:
     25        (Heap):
     26        * heap/HeapTimer.h:
     27        (HeapTimer):
     28        * heap/IncrementalSweeper.cpp:
     29        (JSC::IncrementalSweeper::structuresCanBeSwept): Determines if it is currently safe to sweep Structures.
     30        This decision is based on whether we have gotten to the end of the vector of blocks that need sweeping
     31        the first time.
     32        (JSC):
     33        (JSC::IncrementalSweeper::doSweep): We add a second pass over the vector to sweep Structures after we
     34        make our first pass. We now null out the slots as we sweep them so that we can quickly find the
     35        Structures during the second pass.
     36        (JSC::IncrementalSweeper::startSweeping): Initialize our new Structure sweeping index.
     37        (JSC::IncrementalSweeper::willFinishSweeping): Callback that is called by MarkedSpace::sweep to notify
     38        the IncrementalSweeper that we are going to sweep all of the remaining blocks in the Heap so it can
     39        assume that everything is taken care of in the correct order. Since MarkedSpace::forEachBlock
     40        iterates over the Structure blocks after all other blocks, the ordering property for sweeping Structures holds.
     41        (JSC::IncrementalSweeper::IncrementalSweeper): Initialize Structure sweeping index.
     42        * heap/IncrementalSweeper.h: Add declarations for new stuff.
     43        (IncrementalSweeper):
     44        * heap/MarkedAllocator.cpp:
     45        (JSC::MarkedAllocator::tryAllocateHelper): We now check if the current block only contains structures and
     46        if so and it isn't safe to sweep Structures according to the Heap, we just return early instead of doing
     47        the normal lazy sweep. If this proves to be too much of a waste in the future we can add an extra clause that
     48        will sweep some number of other blocks in place of the current block to mitigate the cost of the floating
     49        Structure garbage.
     50        (JSC::MarkedAllocator::addBlock):
     51        * heap/MarkedAllocator.h:
     52        (JSC::MarkedAllocator::zapFreeList): When we zap the free list in the MarkedAllocator, the current block is no
     53        longer valid to allocate from, so we set the current block to null.
     54        * heap/MarkedBlock.cpp:
     55        (JSC::MarkedBlock::sweepHelper): Added a couple assertions to make sure that we weren't trying to sweep Structures
     56        at an unsafe time.
     57        * heap/MarkedSpace.cpp:
     58        (JSC::MarkedSpace::sweep): Notify the IncrementalSweeper that the MarkedSpace will finish all currently remaining sweeping.
     59        (JSC):
     60        * heap/MarkedSpace.h:
     61        (JSC):
     62        * runtime/JSGlobalData.cpp:
     63        (JSC::JSGlobalData::~JSGlobalData): Call the new Heap::didStartVMShutdown.
     64
    1652012-07-29  Filip Pizlo  <fpizlo@apple.com>
    266
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r122166 r124123  
    831831}
    832832
     833bool Heap::isSafeToSweepStructures()
     834{
     835    return !m_sweeper || m_sweeper->structuresCanBeSwept();
     836}
     837
     838void Heap::didStartVMShutdown()
     839{
     840    m_activityCallback->didStartVMShutdown();
     841    m_activityCallback = 0;
     842    m_sweeper->didStartVMShutdown();
     843    m_sweeper = 0;
     844    lastChanceToFinalize();
     845}
     846
    833847} // namespace JSC
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r123813 r124123  
    169169
    170170        bool isPagedOut(double deadline);
     171        bool isSafeToSweepStructures();
     172        void didStartVMShutdown();
    171173
    172174    private:
  • trunk/Source/JavaScriptCore/heap/IncrementalSweeper.cpp

    r121381 r124123  
    7070}
    7171
     72bool IncrementalSweeper::structuresCanBeSwept()
     73{
     74    ASSERT(m_currentBlockToSweepIndex <= m_blocksToSweep.size());
     75    return !m_blocksToSweep.size() || m_currentBlockToSweepIndex >= m_blocksToSweep.size();
     76}
     77
    7278void IncrementalSweeper::doSweep(double sweepBeginTime)
    7379{
    7480    while (m_currentBlockToSweepIndex < m_blocksToSweep.size()) {
    75         MarkedBlock* block = m_blocksToSweep[m_currentBlockToSweepIndex++];
     81        MarkedBlock* block = m_blocksToSweep[m_currentBlockToSweepIndex];
     82        if (block->onlyContainsStructures()) {
     83            m_currentBlockToSweepIndex++;
     84            continue;
     85        }
     86
     87        m_blocksToSweep[m_currentBlockToSweepIndex++] = 0;
     88
     89        if (!block->needsSweeping())
     90            continue;
     91
     92        block->sweep();
     93        m_globalData->heap.objectSpace().freeOrShrinkBlock(block);
     94
     95        CFTimeInterval elapsedTime = WTF::monotonicallyIncreasingTime() - sweepBeginTime;
     96        if (elapsedTime < sweepTimeSlice)
     97            continue;
     98
     99        scheduleTimer();
     100        return;
     101    }
     102
     103    while (m_currentStructureBlockToSweepIndex < m_blocksToSweep.size()) {
     104        MarkedBlock* block = m_blocksToSweep[m_currentStructureBlockToSweepIndex];
     105        if (!block) {
     106            m_currentStructureBlockToSweepIndex++;
     107            continue;
     108        }
     109
     110        m_blocksToSweep[m_currentStructureBlockToSweepIndex++] = 0;
     111
    76112        if (!block->needsSweeping())
    77113            continue;
     
    96132    WTF::copyToVector(blockSnapshot, m_blocksToSweep);
    97133    m_currentBlockToSweepIndex = 0;
     134    m_currentStructureBlockToSweepIndex = 0;
    98135    scheduleTimer();
     136}
     137
     138void IncrementalSweeper::willFinishSweeping()
     139{
     140    m_currentBlockToSweepIndex = m_currentStructureBlockToSweepIndex = 0;
     141    m_blocksToSweep.clear();
     142    if (m_globalData)
     143        cancelTimer();
    99144}
    100145
     
    103148IncrementalSweeper::IncrementalSweeper(JSGlobalData* globalData)
    104149    : HeapTimer(globalData)
     150    , m_structuresCanBeSwept(false)
    105151{
    106152}
     
    115161}
    116162
     163bool IncrementalSweeper::structuresCanBeSwept()
     164{
     165    return m_structuresCanBeSwept;
     166}
     167
    117168void IncrementalSweeper::startSweeping(const HashSet<MarkedBlock*>&)
    118169{
     170    m_structuresCanBeSwept = false;
    119171}
    120    
     172
     173void IncrementalSweeper::willFinishSweeping()
     174{
     175    m_structuresCanBeSwept = true;
     176}
     177
    121178#endif
    122179
  • trunk/Source/JavaScriptCore/heap/IncrementalSweeper.h

    r121381 r124123  
    4343    void startSweeping(const HashSet<MarkedBlock*>& blockSnapshot);
    4444    virtual void doWork();
     45    bool structuresCanBeSwept();
     46    void willFinishSweeping();
    4547
    4648private:
     49
    4750#if USE(CF)
    4851    IncrementalSweeper(Heap*, CFRunLoopRef);
     
    5356   
    5457    unsigned m_currentBlockToSweepIndex;
     58    unsigned m_currentStructureBlockToSweepIndex;
    5559    Vector<MarkedBlock*> m_blocksToSweep;
    5660#else
    5761   
    5862    IncrementalSweeper(JSGlobalData*);
    59    
     63   
     64    bool m_structuresCanBeSwept;
     65
    6066#endif
    6167};
  • trunk/Source/JavaScriptCore/heap/MarkedAllocator.cpp

    r123931 r124123  
    44#include "GCActivityCallback.h"
    55#include "Heap.h"
     6#include "IncrementalSweeper.h"
    67#include "JSGlobalData.h"
    78#include <wtf/CurrentTime.h>
     
    3031{
    3132    if (!m_freeList.head) {
     33        if (m_onlyContainsStructures && !m_heap->isSafeToSweepStructures()) {
     34            if (m_currentBlock) {
     35                m_currentBlock->didConsumeFreeList();
     36                m_currentBlock = 0;
     37            }
     38            return 0;
     39        }
     40
    3241        for (MarkedBlock*& block = m_blocksToSweep; block; block = static_cast<MarkedBlock*>(block->next())) {
    3342            m_freeList = block->sweep(MarkedBlock::SweepToFreeList);
     
    105114{
    106115    ASSERT(!m_currentBlock);
    107     ASSERT(!m_blocksToSweep);
    108116    ASSERT(!m_freeList.head);
    109117   
  • trunk/Source/JavaScriptCore/heap/MarkedAllocator.h

    r123931 r124123  
    102102   
    103103    m_currentBlock->zapFreeList(m_freeList);
     104    m_currentBlock = 0;
    104105    m_freeList = MarkedBlock::FreeList();
    105106}
  • trunk/Source/JavaScriptCore/heap/MarkedBlock.cpp

    r123813 r124123  
    2727#include "MarkedBlock.h"
    2828
     29#include "IncrementalSweeper.h"
    2930#include "JSCell.h"
    3031#include "JSObject.h"
     
    141142        return FreeList();
    142143    case Marked:
     144        ASSERT(!m_onlyContainsStructures || heap()->isSafeToSweepStructures());
    143145        return sweepMode == SweepToFreeList
    144146            ? specializedSweep<Marked, SweepToFreeList, destructorCallNeeded>()
    145147            : specializedSweep<Marked, SweepOnly, destructorCallNeeded>();
    146148    case Zapped:
     149        ASSERT(!m_onlyContainsStructures || heap()->isSafeToSweepStructures());
    147150        return sweepMode == SweepToFreeList
    148151            ? specializedSweep<Zapped, SweepToFreeList, destructorCallNeeded>()
  • trunk/Source/JavaScriptCore/heap/MarkedSpace.cpp

    r123813 r124123  
    2222#include "MarkedSpace.h"
    2323
     24#include "IncrementalSweeper.h"
    2425#include "JSGlobalObject.h"
    2526#include "JSLock.h"
     
    107108    canonicalizeCellLivenessData();
    108109    forEachBlock<LastChanceToFinalize>();
     110}
     111
     112void MarkedSpace::sweep()
     113{
     114    m_heap->sweeper()->willFinishSweeping();
     115    forEachBlock<Sweep>();
    109116}
    110117
  • trunk/Source/JavaScriptCore/heap/MarkedSpace.h

    r123813 r124123  
    236236}
    237237
    238 inline void MarkedSpace::sweep()
    239 {
    240     forEachBlock<Sweep>();
    241 }
    242 
    243238inline size_t MarkedSpace::objectCount()
    244239{
  • trunk/Source/JavaScriptCore/runtime/JSGlobalData.cpp

    r121806 r124123  
    224224{
    225225    ASSERT(!m_apiLock.currentThreadIsHoldingLock());
    226     heap.activityCallback()->didStartVMShutdown();
    227     heap.sweeper()->didStartVMShutdown();
    228     heap.lastChanceToFinalize();
     226    heap.didStartVMShutdown();
    229227
    230228    delete interpreter;
Note: See TracChangeset for help on using the changeset viewer.