Changeset 207263 in webkit


Ignore:
Timestamp:
Oct 12, 2016 4:56:34 PM (8 years ago)
Author:
fpizlo@apple.com
Message:

The blackening of CellState is a bad way of tracking if the object is being marked for the first time
https://bugs.webkit.org/show_bug.cgi?id=163343

Reviewed by Mark Lam.

When I first added the concept of NewGrey/OldGrey, I had the SlotVisitor store the old cell
state in itself, so that it could use it to decide what to do for reportExtraMemoryVisited().

Then I changed it in a recent commit, because I wanted the freedom to have SlotVisitor visit
multiple objects in tandem. But I never ended up using this capability. Still, I liked the
new way better: instead of the SlotVisitor rembemering the state-before-blackening, we would
make the object's state reflect whether it was black for the first time or not. That seemed
convenient.

Unfortunately it's wrong. After we blacken the object, a concurrent barrier could instantly
grey it. Then we would forget that we are visiting this object for the first time.
Subsequent visits will think that they are not the first. So, we will fail to do the right
thing in reportExtraMemoryVisited().

So, this reverts that change. This is a little more than just a revert, though. I've changed
the terminology a bit. For example, I got tired of reading Black and having to remind myself
that it really means that the object has begun being visited, instead of the more strict
meaning that implies that it has already been visited. We want to say that it's Black or
currently being scanned. I'm going to adopt Siebert's term for this: Anthracite [1]. So, our
black CellState is now called AnthraciteOrBlack.

[1] https://pdfs.semanticscholar.org/7ae4/633265aead1f8835cf7966e179d02c2c8a4b.pdf

  • heap/CellState.h:

(JSC::isBlack): Deleted.
(JSC::blacken): Deleted.

  • heap/Heap.cpp:

(JSC::Heap::addToRememberedSet):
(JSC::Heap::writeBarrierSlowPath):

  • heap/Heap.h:
  • heap/HeapInlines.h:

(JSC::Heap::reportExtraMemoryVisited):
(JSC::Heap::reportExternalMemoryVisited):

  • heap/SlotVisitor.cpp:

(JSC::SlotVisitor::appendToMarkStack):
(JSC::SlotVisitor::visitChildren):

  • heap/SlotVisitor.h:
  • heap/SlotVisitorInlines.h:

(JSC::SlotVisitor::reportExtraMemoryVisited):
(JSC::SlotVisitor::reportExternalMemoryVisited):

  • llint/LLIntData.cpp:

(JSC::LLInt::Data::performAssertions):

  • llint/LowLevelInterpreter.asm:
Location:
trunk/Source/JavaScriptCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r207241 r207263  
     12016-10-12  Filip Pizlo  <fpizlo@apple.com>
     2
     3        The blackening of CellState is a bad way of tracking if the object is being marked for the first time
     4        https://bugs.webkit.org/show_bug.cgi?id=163343
     5
     6        Reviewed by Mark Lam.
     7       
     8        When I first added the concept of NewGrey/OldGrey, I had the SlotVisitor store the old cell
     9        state in itself, so that it could use it to decide what to do for reportExtraMemoryVisited().
     10       
     11        Then I changed it in a recent commit, because I wanted the freedom to have SlotVisitor visit
     12        multiple objects in tandem. But I never ended up using this capability. Still, I liked the
     13        new way better: instead of the SlotVisitor rembemering the state-before-blackening, we would
     14        make the object's state reflect whether it was black for the first time or not. That seemed
     15        convenient.
     16       
     17        Unfortunately it's wrong. After we blacken the object, a concurrent barrier could instantly
     18        grey it. Then we would forget that we are visiting this object for the first time.
     19        Subsequent visits will think that they are not the first. So, we will fail to do the right
     20        thing in reportExtraMemoryVisited().
     21       
     22        So, this reverts that change. This is a little more than just a revert, though. I've changed
     23        the terminology a bit. For example, I got tired of reading Black and having to remind myself
     24        that it really means that the object has begun being visited, instead of the more strict
     25        meaning that implies that it has already been visited. We want to say that it's Black or
     26        currently being scanned. I'm going to adopt Siebert's term for this: Anthracite [1]. So, our
     27        black CellState is now called AnthraciteOrBlack.
     28       
     29        [1] https://pdfs.semanticscholar.org/7ae4/633265aead1f8835cf7966e179d02c2c8a4b.pdf
     30
     31        * heap/CellState.h:
     32        (JSC::isBlack): Deleted.
     33        (JSC::blacken): Deleted.
     34        * heap/Heap.cpp:
     35        (JSC::Heap::addToRememberedSet):
     36        (JSC::Heap::writeBarrierSlowPath):
     37        * heap/Heap.h:
     38        * heap/HeapInlines.h:
     39        (JSC::Heap::reportExtraMemoryVisited):
     40        (JSC::Heap::reportExternalMemoryVisited):
     41        * heap/SlotVisitor.cpp:
     42        (JSC::SlotVisitor::appendToMarkStack):
     43        (JSC::SlotVisitor::visitChildren):
     44        * heap/SlotVisitor.h:
     45        * heap/SlotVisitorInlines.h:
     46        (JSC::SlotVisitor::reportExtraMemoryVisited):
     47        (JSC::SlotVisitor::reportExternalMemoryVisited):
     48        * llint/LLIntData.cpp:
     49        (JSC::LLInt::Data::performAssertions):
     50        * llint/LowLevelInterpreter.asm:
     51
    1522016-10-12  Mark Lam  <mark.lam@apple.com>
    253
  • trunk/Source/JavaScriptCore/heap/CellState.h

    r206555 r207263  
    3131
    3232enum class CellState : uint8_t {
    33     // The object is black for the first time during this GC.
    34     NewBlack = 0,
    35    
    36     // The object is black for the Nth time during this full GC cycle (N > 1). An object may get to
    37     // this state if it transitions from black back to grey during a concurrent GC, or because it
    38     // wound up in the remembered set because of a generational barrier.
    39     OldBlack = 1,
     33    // The object is either currently being scanned (anthracite) or it has finished being scanned
     34    // (black). It could be scanned for the first time this GC, or the Nth time - if it's anthracite
     35    // then the SlotVisitor knows. We explicitly say "anthracite or black" to emphasize the fact that
     36    // this is no guarantee that we have finished scanning the object, unless you also know that all
     37    // SlotVisitors are done.
     38    AnthraciteOrBlack = 0,
    4039   
    4140    // The object is in eden. During GC, this means that the object has not been marked yet.
    42     NewWhite = 2,
     41    NewWhite = 1,
    4342
    4443    // The object is grey - i.e. it will be scanned - and this is the first time in this GC that we are
    4544    // going to scan it. If this is an eden GC, this also means that the object is in eden.
    46     NewGrey = 3,
     45    NewGrey = 2,
    4746
    4847    // The object is grey - i.e. it will be scanned - but it either belongs to old gen (if this is eden
    4948    // GC) or it is grey a second time in this current GC (because a concurrent store barrier requested
    5049    // re-greying).
    51     OldGrey = 4
     50    OldGrey = 3
    5251};
    5352
    54 static const unsigned blackThreshold = 1; // x <= blackThreshold means x is black.
     53static const unsigned blackThreshold = 0; // x <= blackThreshold means x is AnthraciteOrBlack.
    5554static const unsigned tautologicalThreshold = 100; // x <= tautologicalThreshold is always true.
    5655
     
    6059}
    6160
    62 inline bool isBlack(CellState cellState)
    63 {
    64     return isWithinThreshold(cellState, blackThreshold);
    65 }
    66 
    67 inline CellState blacken(CellState cellState)
    68 {
    69     if (cellState == CellState::NewGrey)
    70         return CellState::NewBlack;
    71     ASSERT(cellState == CellState::NewBlack || cellState == CellState::OldBlack || cellState == CellState::OldGrey);
    72     return CellState::OldBlack;
    73 }
    74 
    7561} // namespace JSC
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r207179 r207263  
    917917    ASSERT(cell);
    918918    ASSERT(!Options::useConcurrentJIT() || !isCompilationThread());
    919     ASSERT(isBlack(cell->cellState()));
     919    ASSERT(cell->cellState() == CellState::AnthraciteOrBlack);
    920920    // Indicate that this object is grey and that it's one of the following:
    921921    // - A re-greyed object during a concurrent collection.
     
    15531553        // not black. But we can't know for sure until we fire off a fence.
    15541554        WTF::storeLoadFence();
    1555         if (!isBlack(from->cellState()))
     1555        if (from->cellState() != CellState::AnthraciteOrBlack)
    15561556            return;
    15571557    }
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r207179 r207263  
    182182    // memory growth.
    183183    void reportExtraMemoryAllocated(size_t);
    184     void reportExtraMemoryVisited(JSCell*, size_t);
     184    void reportExtraMemoryVisited(CellState oldState, size_t);
    185185
    186186#if ENABLE(RESOURCE_USAGE)
    187187    // Use this API to report the subset of extra memory that lives outside this process.
    188     void reportExternalMemoryVisited(JSCell*, size_t);
     188    void reportExternalMemoryVisited(CellState oldState, size_t);
    189189    size_t externalMemorySize() { return m_externalMemorySize; }
    190190#endif
  • trunk/Source/JavaScriptCore/heap/HeapInlines.h

    r206555 r207263  
    159159}
    160160
    161 inline void Heap::reportExtraMemoryVisited(JSCell* cell, size_t size)
     161inline void Heap::reportExtraMemoryVisited(CellState oldState, size_t size)
    162162{
    163163    // We don't want to double-count the extra memory that was reported in previous collections.
    164     if (operationInProgress() == EdenCollection && cell->cellState() == CellState::OldBlack)
     164    if (operationInProgress() == EdenCollection && oldState == CellState::OldGrey)
    165165        return;
    166166
     
    175175
    176176#if ENABLE(RESOURCE_USAGE)
    177 inline void Heap::reportExternalMemoryVisited(JSCell* cell, size_t size)
     177inline void Heap::reportExternalMemoryVisited(CellState oldState, size_t size)
    178178{
    179179    // We don't want to double-count the external memory that was reported in previous collections.
    180     if (operationInProgress() == EdenCollection && cell->cellState() == CellState::OldBlack)
     180    if (operationInProgress() == EdenCollection && oldState == CellState::OldGrey)
    181181        return;
    182182
  • trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp

    r207230 r207263  
    229229    ASSERT(Heap::isMarkedConcurrently(cell));
    230230    ASSERT(!cell->isZapped());
     231    ASSERT(cell->cellState() == CellState::NewGrey || cell->cellState() == CellState::OldGrey);
    231232   
    232233    container.noteMarked();
     
    294295    SetCurrentCellScope currentCellScope(*this, cell);
    295296   
    296     cell->setCellState(blacken(cell->cellState()));
     297    m_oldCellState = cell->cellState();
     298   
     299    // There is no race here - the cell state cannot change right now. Grey objects can only be
     300    // visited by one marking thread. Neither the barrier nor marking will change the state of an
     301    // object that is already grey.
     302    ASSERT(m_oldCellState == CellState::OldGrey || m_oldCellState == CellState::NewGrey);
     303   
     304    cell->setCellState(CellState::AnthraciteOrBlack);
    297305   
    298306    WTF::storeLoadFence();
     
    319327   
    320328    if (UNLIKELY(m_heapSnapshotBuilder)) {
    321         if (cell->cellState() != CellState::OldBlack)
     329        if (m_oldCellState == CellState::NewGrey)
    322330            m_heapSnapshotBuilder->appendNode(const_cast<JSCell*>(cell));
    323331    }
  • trunk/Source/JavaScriptCore/heap/SlotVisitor.h

    r207222 r207263  
    166166    HeapSnapshotBuilder* m_heapSnapshotBuilder { nullptr };
    167167    JSCell* m_currentCell { nullptr };
     168    CellState m_oldCellState;
    168169
    169170public:
  • trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h

    r206525 r207263  
    106106inline void SlotVisitor::reportExtraMemoryVisited(size_t size)
    107107{
    108     heap()->reportExtraMemoryVisited(m_currentCell, size);
     108    heap()->reportExtraMemoryVisited(m_oldCellState, size);
    109109}
    110110
     
    112112inline void SlotVisitor::reportExternalMemoryVisited(size_t size)
    113113{
    114     heap()->reportExternalMemoryVisited(m_currentCell, size);
     114    heap()->reportExternalMemoryVisited(m_oldCellState, size);
    115115}
    116116#endif
  • trunk/Source/JavaScriptCore/llint/LLIntData.cpp

    r207239 r207263  
    215215
    216216    STATIC_ASSERT(MarkedBlock::blockSize == 16 * 1024);
    217     STATIC_ASSERT(blackThreshold == 1);
     217    STATIC_ASSERT(blackThreshold == 0);
    218218
    219219    ASSERT(bitwise_cast<uintptr_t>(ShadowChicken::Packet::tailMarker()) == static_cast<uintptr_t>(0x7a11));
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm

    r207239 r207263  
    410410const MarkedBlockMask = ~(MarkedBlockSize - 1)
    411411
    412 const BlackThreshold = 1
     412const BlackThreshold = 0
    413413
    414414# Allocation constants
Note: See TracChangeset for help on using the changeset viewer.