Ignore:
Timestamp:
Jan 9, 2014, 6:28:27 PM (11 years ago)
Author:
[email protected]
Message:

Marking should be generational
https://bugs.webkit.org/show_bug.cgi?id=126552

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Re-marking the same objects over and over is a waste of effort. This patch implements
the sticky mark bit algorithm (along with our already-present write barriers) to reduce
overhead during garbage collection caused by rescanning objects.

There are now two collection modes, EdenCollection and FullCollection. EdenCollections
only visit new objects or objects that were added to the remembered set by a write barrier.
FullCollections are normal collections that visit all objects regardless of their
generation.

In this patch EdenCollections do not do anything in CopiedSpace. This will be fixed in
https://bugs.webkit.org/show_bug.cgi?id=126555.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::visitAggregate):

  • bytecode/CodeBlock.h:

(JSC::CodeBlockSet::mark):

  • dfg/DFGOperations.cpp:
  • heap/CodeBlockSet.cpp:

(JSC::CodeBlockSet::add):
(JSC::CodeBlockSet::traceMarked):
(JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks):

  • heap/CodeBlockSet.h:
  • heap/CopiedBlockInlines.h:

(JSC::CopiedBlock::reportLiveBytes):

  • heap/CopiedSpace.cpp:

(JSC::CopiedSpace::didStartFullCollection):

  • heap/CopiedSpace.h:

(JSC::CopiedSpace::heap):

  • heap/Heap.cpp:

(JSC::Heap::Heap):
(JSC::Heap::didAbandon):
(JSC::Heap::markRoots):
(JSC::Heap::copyBackingStores):
(JSC::Heap::addToRememberedSet):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collect):
(JSC::Heap::didAllocate):
(JSC::Heap::writeBarrier):

  • heap/Heap.h:

(JSC::Heap::isInRememberedSet):
(JSC::Heap::operationInProgress):
(JSC::Heap::shouldCollect):
(JSC::Heap::isCollecting):
(JSC::Heap::isWriteBarrierEnabled):
(JSC::Heap::writeBarrier):

  • heap/HeapOperation.h:
  • heap/MarkStack.cpp:

(JSC::MarkStackArray::~MarkStackArray):
(JSC::MarkStackArray::clear):
(JSC::MarkStackArray::fillVector):

  • heap/MarkStack.h:
  • heap/MarkedAllocator.cpp:

(JSC::isListPagedOut):
(JSC::MarkedAllocator::isPagedOut):
(JSC::MarkedAllocator::tryAllocateHelper):
(JSC::MarkedAllocator::addBlock):
(JSC::MarkedAllocator::removeBlock):
(JSC::MarkedAllocator::reset):

  • heap/MarkedAllocator.h:

(JSC::MarkedAllocator::MarkedAllocator):

  • heap/MarkedBlock.cpp:

(JSC::MarkedBlock::clearMarks):
(JSC::MarkedBlock::clearRememberedSet):
(JSC::MarkedBlock::clearMarksWithCollectionType):
(JSC::MarkedBlock::lastChanceToFinalize):

  • heap/MarkedBlock.h: Changed atomSize to 16 bytes because we have no objects smaller

than 16 bytes. This is also to pay for the additional Bitmap for the remembered set.
(JSC::MarkedBlock::didConsumeEmptyFreeList):
(JSC::MarkedBlock::setRemembered):
(JSC::MarkedBlock::clearRemembered):
(JSC::MarkedBlock::atomicClearRemembered):
(JSC::MarkedBlock::isRemembered):

  • heap/MarkedSpace.cpp:

(JSC::MarkedSpace::~MarkedSpace):
(JSC::MarkedSpace::resetAllocators):
(JSC::MarkedSpace::visitWeakSets):
(JSC::MarkedSpace::reapWeakSets):
(JSC::VerifyMarked::operator()):
(JSC::MarkedSpace::clearMarks):

  • heap/MarkedSpace.h:

(JSC::ClearMarks::operator()):
(JSC::ClearRememberedSet::operator()):
(JSC::MarkedSpace::didAllocateInBlock):
(JSC::MarkedSpace::clearRememberedSet):

  • heap/SlotVisitor.cpp:

(JSC::SlotVisitor::~SlotVisitor):
(JSC::SlotVisitor::clearMarkStack):

  • heap/SlotVisitor.h:

(JSC::SlotVisitor::markStack):
(JSC::SlotVisitor::sharedData):

  • heap/SlotVisitorInlines.h:

(JSC::SlotVisitor::internalAppend):
(JSC::SlotVisitor::unconditionallyAppend):
(JSC::SlotVisitor::copyLater):
(JSC::SlotVisitor::reportExtraMemoryUsage):
(JSC::SlotVisitor::heap):

  • jit/Repatch.cpp:
  • runtime/JSGenericTypedArrayViewInlines.h:

(JSC::JSGenericTypedArrayView<Adaptor>::visitChildren):

  • runtime/JSPropertyNameIterator.h:

(JSC::StructureRareData::setEnumerationCache):

  • runtime/JSString.cpp:

(JSC::JSString::visitChildren):

  • runtime/StructureRareDataInlines.h:

(JSC::StructureRareData::setPreviousID):
(JSC::StructureRareData::setObjectToStringValue):

  • runtime/WeakMapData.cpp:

(JSC::WeakMapData::visitChildren):

Source/WTF:

  • wtf/Bitmap.h:

(WTF::WordType>::count): Added a cast that became necessary when Bitmap
is used with smaller types than int32_t.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r161557 r161615  
    254254    , m_minBytesPerCycle(minHeapSize(m_heapType, m_ramSize))
    255255    , m_sizeAfterLastCollect(0)
    256     , m_bytesAllocatedLimit(m_minBytesPerCycle)
    257     , m_bytesAllocated(0)
    258     , m_bytesAbandoned(0)
     256    , m_bytesAllocatedThisCycle(0)
     257    , m_bytesAbandonedThisCycle(0)
     258    , m_maxEdenSize(m_minBytesPerCycle)
     259    , m_maxHeapSize(m_minBytesPerCycle)
     260    , m_shouldDoFullCollection(false)
    259261    , m_totalBytesVisited(0)
    260262    , m_totalBytesCopied(0)
     
    270272    , m_handleSet(vm)
    271273    , m_isSafeToCollect(false)
    272     , m_writeBarrierBuffer(128)
     274    , m_writeBarrierBuffer(256)
    273275    , m_vm(vm)
    274276    , m_lastGCLength(0)
     
    333335{
    334336    if (m_activityCallback)
    335         m_activityCallback->didAllocate(m_bytesAllocated + m_bytesAbandoned);
    336     m_bytesAbandoned += bytes;
     337        m_activityCallback->didAllocate(m_bytesAllocatedThisCycle + m_bytesAbandonedThisCycle);
     338    m_bytesAbandonedThisCycle += bytes;
    337339}
    338340
     
    487489    visitor.setup();
    488490    HeapRootVisitor heapRootVisitor(visitor);
     491
     492    Vector<const JSCell*> rememberedSet(m_slotVisitor.markStack().size());
     493    m_slotVisitor.markStack().fillVector(rememberedSet);
    489494
    490495    {
     
    591596    }
    592597
     598    {
     599        GCPHASE(ClearRememberedSet);
     600        for (unsigned i = 0; i < rememberedSet.size(); ++i) {
     601            const JSCell* cell = rememberedSet[i];
     602            MarkedBlock::blockFor(cell)->clearRemembered(cell);
     603        }
     604    }
     605
    593606    GCCOUNTER(VisitedValueCount, visitor.visitCount());
    594607
     
    602615#endif
    603616
    604     m_totalBytesVisited = visitor.bytesVisited();
    605     m_totalBytesCopied = visitor.bytesCopied();
     617    if (m_operationInProgress == EdenCollection) {
     618        m_totalBytesVisited += visitor.bytesVisited();
     619        m_totalBytesCopied += visitor.bytesCopied();
     620    } else {
     621        ASSERT(m_operationInProgress == FullCollection);
     622        m_totalBytesVisited = visitor.bytesVisited();
     623        m_totalBytesCopied = visitor.bytesCopied();
     624    }
    606625#if ENABLE(PARALLEL_GC)
    607626    m_totalBytesVisited += m_sharedData.childBytesVisited();
     
    616635}
    617636
     637template <HeapOperation collectionType>
    618638void Heap::copyBackingStores()
    619639{
     640    if (collectionType == EdenCollection)
     641        return;
     642
    620643    m_storageSpace.startedCopying();
    621644    if (m_storageSpace.shouldDoCopyPhase()) {
     
    628651        m_storageSpace.doneCopying();
    629652        m_sharedData.didFinishCopying();
    630     } else 
     653    } else
    631654        m_storageSpace.doneCopying();
    632655}
     
    724747}
    725748
     749void Heap::addToRememberedSet(const JSCell* cell)
     750{
     751    ASSERT(cell);
     752    ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread());
     753    if (isInRememberedSet(cell))
     754        return;
     755    MarkedBlock::blockFor(cell)->setRemembered(cell);
     756    m_slotVisitor.unconditionallyAppend(const_cast<JSCell*>(cell));
     757}
     758
    726759void Heap::collectAllGarbage()
    727760{
     
    729762        return;
    730763
     764    m_shouldDoFullCollection = true;
    731765    collect();
    732766
     
    765799        m_vm->prepareToDiscardCode();
    766800    }
    767    
    768     m_operationInProgress = Collection;
    769     m_extraMemoryUsage = 0;
     801
     802    bool isFullCollection = m_shouldDoFullCollection;
     803    if (isFullCollection) {
     804        m_operationInProgress = FullCollection;
     805        m_slotVisitor.clearMarkStack();
     806        m_shouldDoFullCollection = false;
     807        if (Options::logGC())
     808            dataLog("FullCollection, ");
     809    } else {
     810#if ENABLE(GGC)
     811        m_operationInProgress = EdenCollection;
     812        if (Options::logGC())
     813            dataLog("EdenCollection, ");
     814#else
     815        m_operationInProgress = FullCollection;
     816        m_slotVisitor.clearMarkStack();
     817        if (Options::logGC())
     818            dataLog("FullCollection, ");
     819#endif
     820    }
     821    if (m_operationInProgress == FullCollection)
     822        m_extraMemoryUsage = 0;
    770823
    771824    if (m_activityCallback)
     
    781834        GCPHASE(StopAllocation);
    782835        m_objectSpace.stopAllocating();
     836        if (m_operationInProgress == FullCollection)
     837            m_storageSpace.didStartFullCollection();
     838    }
     839
     840    {
     841        GCPHASE(FlushWriteBarrierBuffer);
     842        if (m_operationInProgress == EdenCollection)
     843            m_writeBarrierBuffer.flush(*this);
     844        else
     845            m_writeBarrierBuffer.reset();
    783846    }
    784847
     
    797860    }
    798861
    799     {
     862    if (m_operationInProgress == FullCollection) {
    800863        m_blockSnapshot.resize(m_objectSpace.blocks().set().size());
    801864        MarkedBlockSnapshotFunctor functor(m_blockSnapshot);
     
    803866    }
    804867
    805     copyBackingStores();
     868    if (m_operationInProgress == FullCollection)
     869        copyBackingStores<FullCollection>();
     870    else
     871        copyBackingStores<EdenCollection>();
    806872
    807873    {
     
    820886    }
    821887
    822     m_sweeper->startSweeping(m_blockSnapshot);
    823     m_bytesAbandoned = 0;
     888    if (m_operationInProgress == FullCollection)
     889        m_sweeper->startSweeping(m_blockSnapshot);
     890
     891    {
     892        GCPHASE(AddCurrentlyExecutingCodeBlocksToRememberedSet);
     893        m_codeBlocks.rememberCurrentlyExecutingCodeBlocks(this);
     894    }
     895
     896    m_bytesAbandonedThisCycle = 0;
    824897
    825898    {
     
    832905        HeapStatistics::exitWithFailure();
    833906
     907    if (m_operationInProgress == FullCollection) {
     908        // To avoid pathological GC churn in very small and very large heaps, we set
     909        // the new allocation limit based on the current size of the heap, with a
     910        // fixed minimum.
     911        m_maxHeapSize = max(minHeapSize(m_heapType, m_ramSize), proportionalHeapSize(currentHeapSize, m_ramSize));
     912        m_maxEdenSize = m_maxHeapSize - currentHeapSize;
     913    } else {
     914        ASSERT(currentHeapSize >= m_sizeAfterLastCollect);
     915        m_maxEdenSize = m_maxHeapSize - currentHeapSize;
     916        double edenToOldGenerationRatio = (double)m_maxEdenSize / (double)m_maxHeapSize;
     917        double minEdenToOldGenerationRatio = 1.0 / 3.0;
     918        if (edenToOldGenerationRatio < minEdenToOldGenerationRatio)
     919            m_shouldDoFullCollection = true;
     920        m_maxHeapSize += currentHeapSize - m_sizeAfterLastCollect;
     921        m_maxEdenSize = m_maxHeapSize - currentHeapSize;
     922    }
     923
    834924    m_sizeAfterLastCollect = currentHeapSize;
    835925
    836     // To avoid pathological GC churn in very small and very large heaps, we set
    837     // the new allocation limit based on the current size of the heap, with a
    838     // fixed minimum.
    839     size_t maxHeapSize = max(minHeapSize(m_heapType, m_ramSize), proportionalHeapSize(currentHeapSize, m_ramSize));
    840     m_bytesAllocatedLimit = maxHeapSize - currentHeapSize;
    841 
    842     m_bytesAllocated = 0;
     926    m_bytesAllocatedThisCycle = 0;
    843927    double lastGCEndTime = WTF::monotonicallyIncreasingTime();
    844928    m_lastGCLength = lastGCEndTime - lastGCStartTime;
     
    846930    if (Options::recordGCPauseTimes())
    847931        HeapStatistics::recordGCPauseTime(lastGCStartTime, lastGCEndTime);
    848     RELEASE_ASSERT(m_operationInProgress == Collection);
     932    RELEASE_ASSERT(m_operationInProgress == EdenCollection || m_operationInProgress == FullCollection);
    849933
    850934    m_operationInProgress = NoOperation;
     
    864948        dataLog(after - before, " ms, ", currentHeapSize / 1024, " kb]\n");
    865949    }
    866 
    867 #if ENABLE(ALLOCATION_LOGGING)
    868     dataLogF("JSC GC finishing collection.\n");
    869 #endif
    870950}
    871951
     
    917997{
    918998    if (m_activityCallback)
    919         m_activityCallback->didAllocate(m_bytesAllocated + m_bytesAbandoned);
    920     m_bytesAllocated += bytes;
     999        m_activityCallback->didAllocate(m_bytesAllocatedThisCycle + m_bytesAbandonedThisCycle);
     1000    m_bytesAllocatedThisCycle += bytes;
    9211001}
    9221002
     
    9931073    decrementDeferralDepth();
    9941074    collectIfNecessaryOrDefer();
     1075}
     1076
     1077void Heap::writeBarrier(const JSCell* from)
     1078{
     1079    ASSERT_GC_OBJECT_LOOKS_VALID(const_cast<JSCell*>(from));
     1080    if (!from || !isMarked(from))
     1081        return;
     1082    Heap* heap = Heap::heap(from);
     1083    heap->addToRememberedSet(from);
    9951084}
    9961085
Note: See TracChangeset for help on using the changeset viewer.