Changeset 98937 in webkit

Timestamp:
Oct 31, 2011, 11:43:37 PM (14 years ago)
Author:
fpizlo@apple.com
Message:

The GC should be parallel
https://bugs.webkit.org/show_bug.cgi?id=70995

Source/JavaScriptCore:

Reviewed by Geoff Garen.

Added parallel tracing to the GC. This works by having local mark
stacks per thread, and a global shared one. Threads sometimes
donate cells from the mark stack to the global one if the heuristics
tell them that it's affordable to do so. Threads that have depleted
their local mark stacks try to steal some from the shared one.

Marking is now done using an atomic weak relaxed CAS (compare-and-swap).

This is a 23% speed-up on V8-splay when I use 4 marking threads,
leading to a 3.5% speed-up on V8.

It also appears that this reduces GC pause times on real websites by
more than half.

(JSC::Heap::Heap):
(JSC::Heap::~Heap):
(JSC::Heap::markRoots):

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

(JSC::MarkStackSegmentAllocator::MarkStackSegmentAllocator):
(JSC::MarkStackSegmentAllocator::~MarkStackSegmentAllocator):
(JSC::MarkStackSegmentAllocator::allocate):
(JSC::MarkStackSegmentAllocator::release):
(JSC::MarkStackSegmentAllocator::shrinkReserve):
(JSC::MarkStackArray::MarkStackArray):
(JSC::MarkStackArray::~MarkStackArray):
(JSC::MarkStackArray::expand):
(JSC::MarkStackArray::refill):
(JSC::MarkStackArray::donateSomeCellsTo):
(JSC::MarkStackArray::stealSomeCellsFrom):
(JSC::MarkStackThreadSharedData::markingThreadMain):
(JSC::MarkStackThreadSharedData::markingThreadStartFunc):
(JSC::MarkStackThreadSharedData::MarkStackThreadSharedData):
(JSC::MarkStackThreadSharedData::~MarkStackThreadSharedData):
(JSC::MarkStackThreadSharedData::reset):
(JSC::MarkStack::reset):
(JSC::SlotVisitor::donateSlow):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::MarkStack::mergeOpaqueRoots):
(JSC::SlotVisitor::harvestWeakReferences):

  • heap/MarkStack.h:

(JSC::MarkStackSegment::data):
(JSC::MarkStackSegment::capacityFromSize):
(JSC::MarkStackSegment::sizeFromCapacity):
(JSC::MarkStackArray::postIncTop):
(JSC::MarkStackArray::preDecTop):
(JSC::MarkStackArray::setTopForFullSegment):
(JSC::MarkStackArray::setTopForEmptySegment):
(JSC::MarkStackArray::top):
(JSC::MarkStackArray::validatePrevious):
(JSC::MarkStack::addWeakReferenceHarvester):
(JSC::MarkStack::mergeOpaqueRootsIfNecessary):
(JSC::MarkStack::mergeOpaqueRootsIfProfitable):
(JSC::MarkStack::MarkStack):
(JSC::MarkStack::addOpaqueRoot):
(JSC::MarkStack::containsOpaqueRoot):
(JSC::MarkStack::opaqueRootCount):
(JSC::MarkStackArray::append):
(JSC::MarkStackArray::canRemoveLast):
(JSC::MarkStackArray::removeLast):
(JSC::MarkStackArray::isEmpty):
(JSC::MarkStackArray::canDonateSomeCells):
(JSC::MarkStackArray::size):
(JSC::ParallelModeEnabler::ParallelModeEnabler):
(JSC::ParallelModeEnabler::~ParallelModeEnabler):

  • heap/MarkedBlock.h:

(JSC::MarkedBlock::testAndSetMarked):

  • heap/SlotVisitor.h:

(JSC::SlotVisitor::donate):
(JSC::SlotVisitor::donateAndDrain):
(JSC::SlotVisitor::donateKnownParallel):
(JSC::SlotVisitor::SlotVisitor):

  • heap/WeakReferenceHarvester.h:
  • runtime/Heuristics.cpp:

(JSC::Heuristics::initializeHeuristics):

  • runtime/Heuristics.h:
  • wtf/Atomics.h:

(WTF::weakCompareAndSwap):

  • wtf/Bitmap.h:

(WTF::::Bitmap):
(WTF::::get):
(WTF::::set):
(WTF::::testAndSet):
(WTF::::testAndClear):
(WTF::::concurrentTestAndSet):
(WTF::::concurrentTestAndClear):
(WTF::::clear):
(WTF::::clearAll):
(WTF::::nextPossiblyUnset):
(WTF::::findRunOfZeros):
(WTF::::count):
(WTF::::isEmpty):
(WTF::::isFull):

  • wtf/MainThread.h:

(WTF::isMainThreadOrGCThread):

  • wtf/Platform.h:
  • wtf/ThreadSpecific.h:

(WTF::::isSet):

  • wtf/mac/MainThreadMac.mm:

(WTF::initializeGCThreads):
(WTF::initializeMainThreadPlatform):
(WTF::initializeMainThreadToProcessMainThreadPlatform):
(WTF::registerGCThread):
(WTF::isMainThreadOrGCThread):

Source/WebCore:

Reviewed by Geoff Garen.

Added parallel tracing to the GC. This required loosening some assertions,
since some code may now be called from outside the main thread.

No new tests, since no behavior was changed.

  • platform/TreeShared.h:

(WebCore::TreeShared::parent):

Location:
trunk/Source
Files:
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r98932 r98937  
     1
     2
     3
     4
     5
     6
     7
     8
     9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
     100
     101
     102
     103
     104
     105
     106
     107
     108
     109
     110
     111
     112
     113
     114
     115
     116
    11172011-10-31  Mark Hahnenberg  <mhahnenberg@apple.com>
    2118
  • trunk/Source/JavaScriptCore/JavaScriptCore.exp

    r98932 r98937  
    103103__ZN3JSC10HandleHeap12writeBarrierEPNS_7JSValueERKS1_
    104104__ZN3JSC10HandleHeap4growEv
     105
     106
    105107__ZN3JSC10Identifier11addSlowCaseEPNS_12JSGlobalDataEPN3WTF10StringImplE
    106108__ZN3JSC10Identifier11addSlowCaseEPNS_9ExecStateEPN3WTF10StringImplE
     
    337339__ZN3JSC9CodeBlockD1Ev
    338340__ZN3JSC9CodeBlockD2Ev
     341
    339342__ZN3JSC9MarkStack8validateEPNS_6JSCellE
    340343__ZN3JSC9Structure21addPropertyTransitionERNS_12JSGlobalDataEPS0_RKNS_10IdentifierEjPNS_6JSCellERm
     
    456459__ZN3WTF22cancelCallOnMainThreadEPFvPvES0_
    457460__ZN3WTF22charactersToUIntStrictEPKtmPbi
     461
    458462__ZN3WTF23callOnMainThreadAndWaitEPFvPvES0_
    459463__ZN3WTF23dayInMonthFromDayInYearEib
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def

    r98932 r98937  
    163163    ?evaluate@JSC@@YA?AVJSValue@1@PAVExecState@1@PAVScopeChainNode@1@ABVSourceCode@1@V21@PAV21@@Z
    164164    ?exclude@Profile@JSC@@QAEXPBVProfileNode@2@@Z
    165     ?expand@MarkStackArray@JSC@@QAEXXZ
     165    ?expand@MarkStackArray@JSC@@AEXXZ
    166166    ?fastCalloc@WTF@@YAPAXII@Z
    167167    ?fastFree@WTF@@YAXPAX@Z
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r98365 r98937  
    3333#include "Tracing.h"
    3434#include <algorithm>
     35
    3536
    3637
     
    316317    , m_activityCallback(DefaultGCActivityCallback::create(this))
    317318    , m_machineThreads(this)
    318     , m_slotVisitor(globalData->jsArrayVPtr, globalData->jsFinalObjectVPtr, globalData->jsStringVPtr)
     319    , m_sharedData(globalData)
     320    , m_slotVisitor(m_sharedData, globalData->jsArrayVPtr, globalData->jsFinalObjectVPtr, globalData->jsStringVPtr)
    319321    , m_handleHeap(globalData)
    320322    , m_isSafeToCollect(false)
     
    325327    m_numberOfFreeBlocks = 0;
    326328    m_blockFreeingThread = createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree");
     329
    327330    ASSERT(m_blockFreeingThread);
    328331}
     
    330333Heap::~Heap()
    331334{
    332     // destroy our thread
     335    //
    333336    {
    334337        MutexLocker locker(m_freeBlockLock);
     
    337340    }
    338341    waitForThreadCompletion(m_blockFreeingThread, 0);
    339    
     342
    340343    // The destroy function must already have been called, so assert this.
    341344    ASSERT(!m_globalData);
     
    590593    HeapRootVisitor heapRootVisitor(visitor);
    591594
     595
     596
    592597#if ENABLE(GGC)
    593     {
    594         size_t dirtyCellCount = dirtyCells.size();
    595         GCPHASE(VisitDirtyCells);
    596         GCCOUNTER(DirtyCellCount, dirtyCellCount);
    597         for (size_t i = 0; i < dirtyCellCount; i++) {
    598             heapRootVisitor.visitChildren(dirtyCells[i]);
    599             visitor.drain();
    600         }
    601     }
     598    {
     599        size_t dirtyCellCount = dirtyCells.size();
     600        GCPHASE(VisitDirtyCells);
     601        GCCOUNTER(DirtyCellCount, dirtyCellCount);
     602        for (size_t i = 0; i < dirtyCellCount; i++) {
     603            heapRootVisitor.visitChildren(dirtyCells[i]);
     604            rain();
     605        }
     606    }
    602607#endif
    603608   
    604     if (m_globalData->codeBlocksBeingCompiled.size()) {
    605         GCPHASE(VisitActiveCodeBlock);
    606         for (size_t i = 0; i < m_globalData->codeBlocksBeingCompiled.size(); i++)
    607             m_globalData->codeBlocksBeingCompiled[i]->visitAggregate(visitor);
    608     }
    609    
    610     {
    611         GCPHASE(VisitMachineRoots);
    612         visitor.append(machineThreadRoots);
    613         visitor.drain();
    614     }
    615     {
    616         GCPHASE(VisitRegisterFileRoots);
    617         visitor.append(registerFileRoots);
    618         visitor.drain();
    619     }
    620     {
    621         GCPHASE(VisitProtectedObjects);
    622         markProtectedObjects(heapRootVisitor);
    623         visitor.drain();
    624     }
    625     {
    626         GCPHASE(VisitTempSortVectors);
    627         markTempSortVectors(heapRootVisitor);
    628         visitor.drain();
    629     }
    630 
    631     {
    632         GCPHASE(MarkingArgumentBuffers);
    633         if (m_markListSet && m_markListSet->size()) {
    634             MarkedArgumentBuffer::markLists(heapRootVisitor, *m_markListSet);
    635             visitor.drain();
    636         }
    637     }
    638     if (m_globalData->exception) {
    639         GCPHASE(MarkingException);
    640         heapRootVisitor.visit(&m_globalData->exception);
    641         visitor.drain();
    642     }
    643    
    644     {
    645         GCPHASE(VisitStrongHandles);
    646         m_handleHeap.visitStrongHandles(heapRootVisitor);
    647         visitor.drain();
    648     }
    649    
    650     {
    651         GCPHASE(HandleStack);
    652         m_handleStack.visit(heapRootVisitor);
    653         visitor.drain();
    654     }
    655    
    656     {
    657         GCPHASE(TraceCodeBlocks);
    658         m_jettisonedCodeBlocks.traceCodeBlocks(visitor);
    659         visitor.drain();
     609        if (m_globalData->codeBlocksBeingCompiled.size()) {
     610            GCPHASE(VisitActiveCodeBlock);
     611            for (size_t i = 0; i < m_globalData->codeBlocksBeingCompiled.size(); i++)
     612                m_globalData->codeBlocksBeingCompiled[i]->visitAggregate(visitor);
     613        }
     614   
     615        {
     616            GCPHASE(VisitMachineRoots);
     617            visitor.append(machineThreadRoots);
     618            visitor.donateAndDrain();
     619        }
     620        {
     621            GCPHASE(VisitRegisterFileRoots);
     622            visitor.append(registerFileRoots);
     623            visitor.donateAndDrain();
     624        }
     625        {
     626            GCPHASE(VisitProtectedObjects);
     627            markProtectedObjects(heapRootVisitor);
     628            visitor.donateAndDrain();
     629        }
     630        {
     631            GCPHASE(VisitTempSortVectors);
     632            markTempSortVectors(heapRootVisitor);
     633            visitor.donateAndDrain();
     634        }
     635
     636        {
     637            GCPHASE(MarkingArgumentBuffers);
     638            if (m_markListSet && m_markListSet->size()) {
     639                MarkedArgumentBuffer::markLists(heapRootVisitor, *m_markListSet);
     640                visitor.donateAndDrain();
     641            }
     642        }
     643        if (m_globalData->exception) {
     644            GCPHASE(MarkingException);
     645            heapRootVisitor.visit(&m_globalData->exception);
     646            visitor.donateAndDrain();
     647        }
     648   
     649        {
     650            GCPHASE(VisitStrongHandles);
     651            m_handleHeap.visitStrongHandles(heapRootVisitor);
     652            visitor.donateAndDrain();
     653        }
     654   
     655        {
     656            GCPHASE(HandleStack);
     657            m_handleStack.visit(heapRootVisitor);
     658            visitor.donateAndDrain();
     659        }
     660   
     661        {
     662            GCPHASE(TraceCodeBlocks);
     663            m_jettisonedCodeBlocks.traceCodeBlocks(visitor);
     664            visitor.donateAndDrain();
     665        }
     666   
     667#if ENABLE(PARALLEL_GC)
     668        {
     669            GCPHASE(Convergence);
     670            visitor.drainFromShared(SlotVisitor::MasterDrain);
     671        }
     672#endif
    660673    }
    661674
     
    668681            lastOpaqueRootCount = visitor.opaqueRootCount();
    669682            m_handleHeap.visitWeakHandles(heapRootVisitor);
    670             visitor.drain();
     683            {
     684                ParallelModeEnabler enabler(visitor);
     685                visitor.donateAndDrain();
     686#if ENABLE(PARALLEL_GC)
     687                visitor.drainFromShared(SlotVisitor::MasterDrain);
     688#endif
     689            }
    671690            // If the set of opaque roots has grown, more weak handles may have become reachable.
    672691        } while (lastOpaqueRootCount != visitor.opaqueRootCount());
     
    674693    GCCOUNTER(VisitedValueCount, visitor.visitCount());
    675694    visitor.reset();
     695
    676696
    677697    m_operationInProgress = NoOperation;
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r96760 r98937  
    131131        friend class MarkedBlock;
    132132        friend class AllocationSpace;
     133
    133134
    134135        static const size_t minExtraCost = 256;
     
    168169        void blockFreeingThreadMain();
    169170        static void* blockFreeingThreadStartFunc(void* heap);
    170 
     171       
    171172        const HeapSize m_heapSize;
    172173        const size_t m_minBytesPerCycle;
     
    197198       
    198199        MachineThreads m_machineThreads;
     200
     201
    199202        SlotVisitor m_slotVisitor;
     203
    200204        HandleHeap m_handleHeap;
    201205        HandleStack m_handleStack;
  • trunk/Source/JavaScriptCore/heap/MarkStack.cpp

    r97827 r98937  
    2929#include "ConservativeRoots.h"
    3030#include "Heap.h"
     31
    3132#include "JSArray.h"
    3233#include "JSCell.h"
     
    3536#include "Structure.h"
    3637#include "WriteBarrier.h"
     38
    3739
    3840namespace JSC {
    3941
    40 MarkStackArray::MarkStackArray()
    41     : m_top(0)
    42     , m_allocated(pageSize())
    43 {
    44     m_data = static_cast<const JSCell**>(MarkStack::allocateStack(m_allocated));
    45     m_capacity = m_allocated / sizeof(JSCell*);
     42MarkStackSegmentAllocator::MarkStackSegmentAllocator()
     43    : m_nextFreeSegment(0)
     44{
     45}
     46
     47MarkStackSegmentAllocator::~MarkStackSegmentAllocator()
     48{
     49    shrinkReserve();
     50}
     51
     52MarkStackSegment* MarkStackSegmentAllocator::allocate()
     53{
     54    {
     55        MutexLocker locker(m_lock);
     56        if (m_nextFreeSegment) {
     57            MarkStackSegment* result = m_nextFreeSegment;
     58            m_nextFreeSegment = result->m_previous;
     59            return result;
     60        }
     61    }
     62
     63    return static_cast<MarkStackSegment*>(OSAllocator::reserveAndCommit(Heuristics::gcMarkStackSegmentSize));
     64}
     65
     66void MarkStackSegmentAllocator::release(MarkStackSegment* segment)
     67{
     68    MutexLocker locker(m_lock);
     69    segment->m_previous = m_nextFreeSegment;
     70    m_nextFreeSegment = segment;
     71}
     72
     73void MarkStackSegmentAllocator::shrinkReserve()
     74{
     75    MarkStackSegment* segments;
     76    {
     77        MutexLocker locker(m_lock);
     78        segments = m_nextFreeSegment;
     79        m_nextFreeSegment = 0;
     80    }
     81    while (segments) {
     82        MarkStackSegment* toFree = segments;
     83        segments = segments->m_previous;
     84        OSAllocator::decommitAndRelease(toFree, Heuristics::gcMarkStackSegmentSize);
     85    }
     86}
     87
     88MarkStackArray::MarkStackArray(MarkStackSegmentAllocator& allocator)
     89    : m_allocator(allocator)
     90    , m_segmentCapacity(MarkStackSegment::capacityFromSize(Heuristics::gcMarkStackSegmentSize))
     91    , m_top(0)
     92    , m_numberOfPreviousSegments(0)
     93{
     94    m_topSegment = m_allocator.allocate();
     95#if !ASSERT_DISABLED
     96    m_topSegment->m_top = 0;
     97#endif
     98    m_topSegment->m_previous = 0;
    4699}
    47100
    48101MarkStackArray::~MarkStackArray()
    49102{
    50     MarkStack::releaseStack(m_data, m_allocated);
     103    ASSERT(!m_topSegment->m_previous);
     104    m_allocator.release(m_topSegment);
    51105}
    52106
    53107void MarkStackArray::expand()
    54108{
    55     size_t oldAllocation = m_allocated;
    56     m_allocated *= 2;
    57     m_capacity = m_allocated / sizeof(JSCell*);
    58     void* newData = MarkStack::allocateStack(m_allocated);
    59     memcpy(newData, m_data, oldAllocation);
    60     MarkStack::releaseStack(m_data, oldAllocation);
    61     m_data = static_cast<const JSCell**>(newData);
    62 }
    63 
    64 void MarkStackArray::shrinkAllocation(size_t size)
    65 {
    66     ASSERT(size <= m_allocated);
    67     ASSERT(isPageAligned(size));
    68     if (size == m_allocated)
    69         return;
    70 #if OS(WINDOWS)
    71     // We cannot release a part of a region with VirtualFree. To get around this,
    72     // we'll release the entire region and reallocate the size that we want.
    73     MarkStack::releaseStack(m_data, m_allocated);
    74     m_data = static_cast<const JSCell**>(MarkStack::allocateStack(size));
     109    ASSERT(m_topSegment->m_top == m_segmentCapacity);
     110   
     111    m_numberOfPreviousSegments++;
     112   
     113    MarkStackSegment* nextSegment = m_allocator.allocate();
     114#if !ASSERT_DISABLED
     115    nextSegment->m_top = 0;
     116#endif
     117    nextSegment->m_previous = m_topSegment;
     118    m_topSegment = nextSegment;
     119    setTopForEmptySegment();
     120    validatePrevious();
     121}
     122
     123bool MarkStackArray::refill()
     124{
     125    validatePrevious();
     126    if (top())
     127        return true;
     128    MarkStackSegment* toFree = m_topSegment;
     129    MarkStackSegment* previous = m_topSegment->m_previous;
     130    if (!previous)
     131        return false;
     132    ASSERT(m_numberOfPreviousSegments);
     133    m_numberOfPreviousSegments--;
     134    m_topSegment = previous;
     135    m_allocator.release(toFree);
     136    setTopForFullSegment();
     137    validatePrevious();
     138    return true;
     139}
     140
     141bool MarkStackArray::donateSomeCellsTo(MarkStackArray& other)
     142{
     143    ASSERT(m_segmentCapacity == other.m_segmentCapacity);
     144    validatePrevious();
     145    other.validatePrevious();
     146       
     147    // Fast check: see if the other mark stack already has enough segments.
     148    if (other.m_numberOfPreviousSegments + 1 >= Heuristics::maximumNumberOfSharedSegments)
     149        return false;
     150       
     151    size_t numberOfCellsToKeep = Heuristics::minimumNumberOfCellsToKeep;
     152    ASSERT(m_top > numberOfCellsToKeep || m_topSegment->m_previous);
     153       
     154    // Looks like we should donate! Give the other mark stack all of our
     155    // previous segments, and then top it off.
     156    MarkStackSegment* previous = m_topSegment->m_previous;
     157    while (previous) {
     158        ASSERT(m_numberOfPreviousSegments);
     159
     160        MarkStackSegment* current = previous;
     161        previous = current->m_previous;
     162           
     163        current->m_previous = other.m_topSegment->m_previous;
     164        other.m_topSegment->m_previous = current;
     165           
     166        m_numberOfPreviousSegments--;
     167        other.m_numberOfPreviousSegments++;
     168    }
     169    ASSERT(!m_numberOfPreviousSegments);
     170    m_topSegment->m_previous = 0;
     171    validatePrevious();
     172    other.validatePrevious();
     173       
     174    // Now top off. We want to keep at a minimum numberOfCellsToKeep, but if
     175    // we really have a lot of work, we give up half.
     176    if (m_top > numberOfCellsToKeep * 2)
     177        numberOfCellsToKeep = m_top / 2;
     178    while (m_top > numberOfCellsToKeep)
     179        other.append(removeLast());
     180       
     181    return true;
     182}
     183
     184void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other)
     185{
     186    ASSERT(m_segmentCapacity == other.m_segmentCapacity);
     187    validatePrevious();
     188    other.validatePrevious();
     189       
     190    // If other has an entire segment, steal it and return.
     191    if (other.m_topSegment->m_previous) {
     192        ASSERT(other.m_topSegment->m_previous->m_top == m_segmentCapacity);
     193           
     194        // First remove a segment from other.
     195        MarkStackSegment* current = other.m_topSegment->m_previous;
     196        other.m_topSegment->m_previous = current->m_previous;
     197        other.m_numberOfPreviousSegments--;
     198           
     199        ASSERT(!!other.m_numberOfPreviousSegments == !!other.m_topSegment->m_previous);
     200           
     201        // Now add it to this.
     202        current->m_previous = m_topSegment->m_previous;
     203        m_topSegment->m_previous = current;
     204        m_numberOfPreviousSegments++;
     205           
     206        validatePrevious();
     207        other.validatePrevious();
     208        return;
     209    }
     210       
     211    // Otherwise drain 1/Nth of the shared array where N is the number of
     212    // workers, or Heuristics::minimumNumberOfCellsToKeep, whichever is bigger.
     213    size_t numberOfCellsToSteal = std::max((size_t)Heuristics::minimumNumberOfCellsToKeep, other.size() / Heuristics::numberOfGCMarkers);
     214    while (numberOfCellsToSteal-- > 0 && other.canRemoveLast())
     215        append(other.removeLast());
     216}
     217
     218#if ENABLE(PARALLEL_GC)
     219void MarkStackThreadSharedData::markingThreadMain()
     220{
     221    WTF::registerGCThread();
     222    SlotVisitor slotVisitor(*this, m_globalData->jsArrayVPtr, m_globalData->jsFinalObjectVPtr, m_globalData->jsStringVPtr);
     223    ParallelModeEnabler enabler(slotVisitor);
     224    slotVisitor.drainFromShared(SlotVisitor::SlaveDrain);
     225}
     226
     227void* MarkStackThreadSharedData::markingThreadStartFunc(void* shared)
     228{
     229    static_cast<MarkStackThreadSharedData*>(shared)->markingThreadMain();
     230    return 0;
     231}
     232#endif
     233
     234MarkStackThreadSharedData::MarkStackThreadSharedData(JSGlobalData* globalData)
     235    : m_globalData(globalData)
     236    , m_sharedMarkStack(m_segmentAllocator)
     237    , m_numberOfActiveParallelMarkers(0)
     238    , m_parallelMarkersShouldExit(false)
     239    , m_firstWeakReferenceHarvester(0)
     240{
     241#if ENABLE(PARALLEL_GC)
     242    for (unsigned i = 1; i < Heuristics::numberOfGCMarkers; ++i) {
     243        m_markingThreads.append(createThread(markingThreadStartFunc, this, "JavaScriptCore::Marking"));
     244        ASSERT(m_markingThreads.last());
     245    }
     246#endif
     247}
     248
     249MarkStackThreadSharedData::~MarkStackThreadSharedData()
     250{
     251#if ENABLE(PARALLEL_GC)   
     252    // Destroy our marking threads.
     253    {
     254        MutexLocker locker(m_markingLock);
     255        m_parallelMarkersShouldExit = true;
     256        m_markingCondition.broadcast();
     257    }
     258    for (unsigned i = 0; i < m_markingThreads.size(); ++i)
     259        waitForThreadCompletion(m_markingThreads[i], 0);
     260#endif
     261}
     262   
     263void MarkStackThreadSharedData::reset()
     264{
     265    ASSERT(!m_numberOfActiveParallelMarkers);
     266    ASSERT(!m_parallelMarkersShouldExit);
     267    ASSERT(m_sharedMarkStack.isEmpty());
     268   
     269#if ENABLE(PARALLEL_GC)
     270    m_segmentAllocator.shrinkReserve();
     271    m_opaqueRoots.clear();
    75272#else
    76     MarkStack::releaseStack(reinterpret_cast<char*>(m_data) + size, m_allocated - size);
    77 #endif
    78     m_allocated = size;
    79     m_capacity = m_allocated / sizeof(JSCell*);
     273    ASSERT(m_opaqueRoots.isEmpty());
     274#endif
    80275}
    81276
     
    83278{
    84279    m_visitCount = 0;
    85     m_stack.shrinkAllocation(pageSize());
     280    ASSERT(m_stack.isEmpty());
     281#if ENABLE(PARALLEL_GC)
     282    ASSERT(m_opaqueRoots.isEmpty()); // Should have merged by now.
     283#else
    86284    m_opaqueRoots.clear();
     285
    87286}
    88287
     
    121320}
    122321
     322
     323
     324
     325
     326
     327
     328
     329
     330
     331
     332
     333
     334
     335
    123336void SlotVisitor::drain()
    124337{
     338
     339
    125340    void* jsFinalObjectVPtr = m_jsFinalObjectVPtr;
    126341    void* jsArrayVPtr = m_jsArrayVPtr;
    127342    void* jsStringVPtr = m_jsStringVPtr;
    128343
    129     while (!m_stack.isEmpty())
    130         visitChildren(*this, m_stack.removeLast(), jsFinalObjectVPtr, jsArrayVPtr, jsStringVPtr);
     344#if ENABLE(PARALLEL_GC)
     345    if (Heuristics::numberOfGCMarkers > 1) {
     346        while (!m_stack.isEmpty()) {
     347            m_stack.refill();
     348            for (unsigned countdown = Heuristics::minimumNumberOfScansBetweenRebalance; m_stack.canRemoveLast() && countdown--;)
     349                visitChildren(*this, m_stack.removeLast(), jsFinalObjectVPtr, jsArrayVPtr, jsStringVPtr);
     350            donateKnownParallel();
     351        }
     352       
     353        mergeOpaqueRootsIfNecessary();
     354        return;
     355    }
     356#endif
     357   
     358    while (!m_stack.isEmpty()) {
     359        m_stack.refill();
     360        while (m_stack.canRemoveLast())
     361            visitChildren(*this, m_stack.removeLast(), jsFinalObjectVPtr, jsArrayVPtr, jsStringVPtr);
     362    }
     363}
     364
     365void SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode)
     366{
     367    ASSERT(m_isInParallelMode);
     368   
     369    ASSERT(Heuristics::numberOfGCMarkers);
     370   
     371    bool shouldBeParallel;
     372
     373#if ENABLE(PARALLEL_GC)
     374    shouldBeParallel = Heuristics::numberOfGCMarkers > 1;
     375#else
     376    ASSERT(Heuristics::numberOfGCMarkers == 1);
     377    shouldBeParallel = false;
     378#endif
     379   
     380    if (!shouldBeParallel) {
     381        // This call should be a no-op.
     382        ASSERT_UNUSED(sharedDrainMode, sharedDrainMode == MasterDrain);
     383        ASSERT(m_stack.isEmpty());
     384        ASSERT(m_shared.m_sharedMarkStack.isEmpty());
     385        return;
     386    }
     387   
     388#if ENABLE(PARALLEL_GC)
     389    {
     390        MutexLocker locker(m_shared.m_markingLock);
     391        m_shared.m_numberOfActiveParallelMarkers++;
     392    }
     393    while (true) {
     394        {
     395            MutexLocker locker(m_shared.m_markingLock);
     396            m_shared.m_numberOfActiveParallelMarkers--;
     397
     398            // How we wait differs depending on drain mode.
     399            if (sharedDrainMode == MasterDrain) {
     400                // Wait until either termination is reached, or until there is some work
     401                // for us to do.
     402                while (true) {
     403                    // Did we reach termination?
     404                    if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty())
     405                        return;
     406                   
     407                    // Is there work to be done?
     408                    if (!m_shared.m_sharedMarkStack.isEmpty())
     409                        break;
     410                   
     411                    // Otherwise wait.
     412                    m_shared.m_markingCondition.wait(m_shared.m_markingLock);
     413                }
     414            } else {
     415                ASSERT(sharedDrainMode == SlaveDrain);
     416               
     417                // Did we detect termination? If so, let the master know.
     418                if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty())
     419                    m_shared.m_markingCondition.broadcast();
     420               
     421                while (m_shared.m_sharedMarkStack.isEmpty() && !m_shared.m_parallelMarkersShouldExit)
     422                    m_shared.m_markingCondition.wait(m_shared.m_markingLock);
     423               
     424                // Is the VM exiting? If so, exit this thread.
     425                if (m_shared.m_parallelMarkersShouldExit)
     426                    return;
     427            }
     428           
     429            m_stack.stealSomeCellsFrom(m_shared.m_sharedMarkStack);
     430            m_shared.m_numberOfActiveParallelMarkers++;
     431        }
     432       
     433        drain();
     434    }
     435#endif
     436}
     437
     438void MarkStack::mergeOpaqueRoots()
     439{
     440    ASSERT(!m_opaqueRoots.isEmpty()); // Should only be called when opaque roots are non-empty.
     441    {
     442        MutexLocker locker(m_shared.m_opaqueRootsLock);
     443        HashSet<void*>::iterator begin = m_opaqueRoots.begin();
     444        HashSet<void*>::iterator end = m_opaqueRoots.end();
     445        for (HashSet<void*>::iterator iter = begin; iter != end; ++iter)
     446            m_shared.m_opaqueRoots.add(*iter);
     447    }
     448    m_opaqueRoots.clear();
    131449}
    132450
    133451void SlotVisitor::harvestWeakReferences()
    134452{
    135     while (m_firstWeakReferenceHarvester) {
    136         WeakReferenceHarvester* current = m_firstWeakReferenceHarvester;
     453    while (m_firstWeakReferenceHarvester) {
     454        WeakReferenceHarvester* current = m_firstWeakReferenceHarvester;
    137455        WeakReferenceHarvester* next = reinterpret_cast<WeakReferenceHarvester*>(current->m_nextAndFlag & ~1);
    138456        current->m_nextAndFlag = 0;
    139         m_firstWeakReferenceHarvester = next;
     457        m_firstWeakReferenceHarvester = next;
    140458        current->visitWeakReferences(*this);
    141459    }
  • trunk/Source/JavaScriptCore/heap/MarkStack.h

    r97642 r98937  
    2828
    2929#include "HandleTypes.h"
     30
    3031#include "JSValue.h"
    3132#include "Register.h"
     
    4445    class JSGlobalData;
    4546    class MarkStack;
     47
    4648    class Register;
     49
    4750    template<typename T> class WriteBarrierBase;
    4851    template<typename T> class JITWriteBarrier;
    4952   
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
    5090    class MarkStackArray {
    5191    public:
    52         MarkStackArray();
     92        MarkStackArray();
    5393        ~MarkStackArray();
    5494
     95
     96
     97
     98
     99
     100
     101
     102
     103
     104
     105
     106
     107
     108
     109
     110
     111
     112
    55113        void expand();
    56         void append(const JSCell*);
    57 
    58         const JSCell* removeLast();
    59 
    60         bool isEmpty();
    61 
    62         void shrinkAllocation(size_t);
    63 
     114       
     115        MarkStackSegmentAllocator& m_allocator;
     116
     117        size_t m_segmentCapacity;
     118        size_t m_top;
     119        size_t m_numberOfPreviousSegments;
     120       
     121        size_t postIncTop()
     122        {
     123            size_t result = m_top++;
     124            ASSERT(result == m_topSegment->m_top++);
     125            return result;
     126        }
     127       
     128        size_t preDecTop()
     129        {
     130            size_t result = --m_top;
     131            ASSERT(result == --m_topSegment->m_top);
     132            return result;
     133        }
     134       
     135        void setTopForFullSegment()
     136        {
     137            ASSERT(m_topSegment->m_top == m_segmentCapacity);
     138            m_top = m_segmentCapacity;
     139        }
     140       
     141        void setTopForEmptySegment()
     142        {
     143            ASSERT(!m_topSegment->m_top);
     144            m_top = 0;
     145        }
     146       
     147        size_t top()
     148        {
     149            ASSERT(m_top == m_topSegment->m_top);
     150            return m_top;
     151        }
     152       
     153#if ASSERT_DISABLED
     154        void validatePrevious() { }
     155#else
     156        void validatePrevious()
     157        {
     158            unsigned count = 0;
     159            for (MarkStackSegment* current = m_topSegment->m_previous; current; current = current->m_previous)
     160                count++;
     161            ASSERT(count == m_numberOfPreviousSegments);
     162        }
     163#endif
     164    };
     165
     166    class MarkStackThreadSharedData {
     167    public:
     168        MarkStackThreadSharedData(JSGlobalData*);
     169        ~MarkStackThreadSharedData();
     170       
     171        void reset();
     172   
    64173    private:
    65         const JSCell** m_data;
    66         size_t m_top;
    67         size_t m_capacity;
    68         size_t m_allocated;
     174        friend class MarkStack;
     175        friend class SlotVisitor;
     176
     177#if ENABLE(PARALLEL_GC)
     178        void markingThreadMain();
     179        static void* markingThreadStartFunc(void* heap);
     180#endif
     181
     182        JSGlobalData* m_globalData;
     183       
     184        MarkStackSegmentAllocator m_segmentAllocator;
     185       
     186        Vector<ThreadIdentifier> m_markingThreads;
     187       
     188        Mutex m_markingLock;
     189        ThreadCondition m_markingCondition;
     190        MarkStackArray m_sharedMarkStack;
     191        unsigned m_numberOfActiveParallelMarkers;
     192        bool m_parallelMarkersShouldExit;
     193
     194        Mutex m_opaqueRootsLock;
     195        HashSet<void*> m_opaqueRoots;
     196
     197        Mutex m_weakReferenceHarvesterLock;
     198        WeakReferenceHarvester* m_firstWeakReferenceHarvester;
    69199    };
    70200
     
    74204
    75205    public:
    76         static void* allocateStack(size_t);
    77         static void releaseStack(void*, size_t);
    78 
    79         MarkStack(void* jsArrayVPtr, void* jsFinalObjectVPtr, void* jsStringVPtr);
     206        MarkStack(MarkStackThreadSharedData&, void* jsArrayVPtr, void* jsFinalObjectVPtr, void* jsStringVPtr);
    80207        ~MarkStack();
    81208
     
    89216        void appendUnbarrieredPointer(T**);
    90217       
    91         bool addOpaqueRoot(void*);
     218        addOpaqueRoot(void*);
    92219        bool containsOpaqueRoot(void*);
    93220        int opaqueRootCount();
     
    103230        void addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester)
    104231        {
     232
    105233            if (weakReferenceHarvester->m_nextAndFlag & 1)
    106234                return;
    107             weakReferenceHarvester->m_nextAndFlag = reinterpret_cast<uintptr_t>(m_firstWeakReferenceHarvester) | 1;
    108             m_firstWeakReferenceHarvester = weakReferenceHarvester;
     235            weakReferenceHarvester->m_nextAndFlag = reinterpret_cast<uintptr_t>(m_firstWeakReferenceHarvester) | 1;
     236            m_firstWeakReferenceHarvester = weakReferenceHarvester;
    109237        }
    110238
     
    118246        void internalAppend(JSCell*);
    119247        void internalAppend(JSValue);
    120 
     248       
     249        void mergeOpaqueRoots();
     250       
     251        void mergeOpaqueRootsIfNecessary()
     252        {
     253            if (m_opaqueRoots.isEmpty())
     254                return;
     255            mergeOpaqueRoots();
     256        }
     257       
     258        void mergeOpaqueRootsIfProfitable()
     259        {
     260            if (static_cast<unsigned>(m_opaqueRoots.size()) < Heuristics::opaqueRootMergeThreshold)
     261                return;
     262            mergeOpaqueRoots();
     263        }
     264       
    121265        MarkStackArray m_stack;
    122266        void* m_jsArrayVPtr;
     
    124268        void* m_jsStringVPtr;
    125269        HashSet<void*> m_opaqueRoots; // Handle-owning data structures not visible to the garbage collector.
    126         WeakReferenceHarvester* m_firstWeakReferenceHarvester;
    127270       
    128271#if !ASSERT_DISABLED
     
    132275#endif
    133276    protected:
     277
     278
    134279        size_t m_visitCount;
    135     };
    136 
    137     inline MarkStack::MarkStack(void* jsArrayVPtr, void* jsFinalObjectVPtr, void* jsStringVPtr)
    138         : m_jsArrayVPtr(jsArrayVPtr)
     280        bool m_isInParallelMode;
     281       
     282        MarkStackThreadSharedData& m_shared;
     283    };
     284
     285    inline MarkStack::MarkStack(MarkStackThreadSharedData& shared, void* jsArrayVPtr, void* jsFinalObjectVPtr, void* jsStringVPtr)
     286        : m_stack(shared.m_segmentAllocator)
     287        , m_jsArrayVPtr(jsArrayVPtr)
    139288        , m_jsFinalObjectVPtr(jsFinalObjectVPtr)
    140289        , m_jsStringVPtr(jsStringVPtr)
    141         , m_firstWeakReferenceHarvester(0)
    142290#if !ASSERT_DISABLED
    143291        , m_isCheckingForDefaultMarkViolation(false)
     
    145293#endif
    146294        , m_visitCount(0)
     295
     296
    147297    {
    148298    }
     
    153303    }
    154304
    155     inline bool MarkStack::addOpaqueRoot(void* root)
    156     {
    157         return m_opaqueRoots.add(root).second;
     305    inline void MarkStack::addOpaqueRoot(void* root)
     306    {
     307#if ENABLE(PARALLEL_GC)
     308        if (Heuristics::numberOfGCMarkers == 1) {
     309            // Put directly into the shared HashSet.
     310            m_shared.m_opaqueRoots.add(root);
     311            return;
     312        }
     313        // Put into the local set, but merge with the shared one every once in
     314        // a while to make sure that the local sets don't grow too large.
     315        mergeOpaqueRootsIfProfitable();
     316        m_opaqueRoots.add(root);
     317#else
     318        m_opaqueRoots.add(root);
     319#endif
    158320    }
    159321
    160322    inline bool MarkStack::containsOpaqueRoot(void* root)
    161323    {
     324
     325
     326
     327
     328
    162329        return m_opaqueRoots.contains(root);
     330
    163331    }
    164332
    165333    inline int MarkStack::opaqueRootCount()
    166334    {
     335
     336
     337
     338
     339
    167340        return m_opaqueRoots.size();
    168     }
    169 
    170     inline void* MarkStack::allocateStack(size_t size)
    171     {
    172         return OSAllocator::reserveAndCommit(size);
    173     }
    174 
    175     inline void MarkStack::releaseStack(void* addr, size_t size)
    176     {
    177         OSAllocator::decommitAndRelease(addr, size);
     341#endif
    178342    }
    179343
    180344    inline void MarkStackArray::append(const JSCell* cell)
    181345    {
    182         if (m_top == m_capacity)
     346        if (m_top == m_apacity)
    183347            expand();
    184         m_data[m_top++] = cell;
     348        m_topSegment->data()[postIncTop()] = cell;
     349    }
     350
     351    inline bool MarkStackArray::canRemoveLast()
     352    {
     353        return !!m_top;
    185354    }
    186355
    187356    inline const JSCell* MarkStackArray::removeLast()
    188357    {
    189         ASSERT(m_top);
    190         return m_data[--m_top];
    191     }
    192    
     358        return m_topSegment->data()[preDecTop()];
     359    }
     360
    193361    inline bool MarkStackArray::isEmpty()
    194362    {
    195         return !m_top;
     363        if (m_top)
     364            return false;
     365        if (m_topSegment->m_previous) {
     366            ASSERT(m_topSegment->m_previous->m_top == m_segmentCapacity);
     367            return false;
     368        }
     369        return true;
     370    }
     371
     372    inline bool MarkStackArray::canDonateSomeCells()
     373    {
     374        size_t numberOfCellsToKeep = Heuristics::minimumNumberOfCellsToKeep;
     375        // Another check: see if we have enough cells to warrant donation.
     376        if (m_top <= numberOfCellsToKeep) {
     377            // This indicates that we might not want to donate anything; check if we have
     378            // another full segment. If not, then don't donate.
     379            if (!m_topSegment->m_previous)
     380                return false;
     381           
     382            ASSERT(m_topSegment->m_previous->m_top == m_segmentCapacity);
     383        }
     384       
     385        return true;
     386    }
     387
     388    inline size_t MarkStackArray::size()
     389    {
     390        return m_top + m_segmentCapacity * m_numberOfPreviousSegments;
    196391    }
    197392
     
    235430    }
    236431
    237     class SlotVisitor;
     432    class ParallelModeEnabler {
     433    public:
     434        ParallelModeEnabler(MarkStack& stack)
     435            : m_stack(stack)
     436        {
     437            ASSERT(!m_stack.m_isInParallelMode);
     438            m_stack.m_isInParallelMode = true;
     439        }
     440       
     441        ~ParallelModeEnabler()
     442        {
     443            ASSERT(m_stack.m_isInParallelMode);
     444            m_stack.m_isInParallelMode = false;
     445        }
     446       
     447    private:
     448        MarkStack& m_stack;
     449    };
    238450
    239451} // namespace JSC
  • trunk/Source/JavaScriptCore/heap/MarkedBlock.h

    r97203 r98937  
    175175        size_t m_atomsPerCell;
    176176        size_t m_endAtom; // This is a fuzzy end. Always test for < m_endAtom.
    177         WTF::Bitmap<atomsPerBlock> m_marks;
     177#if ENABLE(PARALLEL_GC)
     178        WTF::Bitmap<atomsPerBlock, WTF::BitmapAtomic> m_marks;
     179#else
     180        WTF::Bitmap<atomsPerBlock, WTF::BitmapNotAtomic> m_marks;
     181#endif
    178182        BlockState m_state;
    179183        PageAllocationAligned m_allocation;
     
    265269    inline bool MarkedBlock::testAndSetMarked(const void* p)
    266270    {
    267         return m_marks.testAndSet(atomNumber(p));
     271        return m_marks.estAndSet(atomNumber(p));
    268272    }
    269273
  • trunk/Source/JavaScriptCore/heap/SlotVisitor.h

    r97642 r98937  
    3131namespace JSC {
    3232
     33
     34
    3335class SlotVisitor : public MarkStack {
    3436    friend class HeapRootVisitor;
    3537public:
    36     SlotVisitor(void* jsArrayVPtr, void* jsFinalObjectVPtr, void* jsStringVPtr);
     38    SlotVisitor(void* jsArrayVPtr, void* jsFinalObjectVPtr, void* jsStringVPtr);
    3739
     40
     41
     42
     43
     44
     45
     46
     47
     48
    3849    void drain();
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
    3960    void harvestWeakReferences();
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
    4071};
    4172
    42 inline SlotVisitor::SlotVisitor(void* jsArrayVPtr, void* jsFinalObjectVPtr, void* jsStringVPtr)
    43     : MarkStack(jsArrayVPtr, jsFinalObjectVPtr, jsStringVPtr)
     73inline SlotVisitor::SlotVisitor(void* jsArrayVPtr, void* jsFinalObjectVPtr, void* jsStringVPtr)
     74    : MarkStack(jsArrayVPtr, jsFinalObjectVPtr, jsStringVPtr)
    4475{
    4576}
  • trunk/Source/JavaScriptCore/heap/WeakReferenceHarvester.h

    r95901 r98937  
    2626
    2727class MarkStack;
     28
    2829class SlotVisitor;
    2930
     
    4243private:
    4344    friend class MarkStack;
     45
    4446    friend class SlotVisitor;
    4547   
  • trunk/Source/JavaScriptCore/runtime/Heuristics.cpp

    r98912 r98937  
    2626#include "config.h"
    2727#include "Heuristics.h"
     28
    2829
    2930#include <limits>
     31
     32
     33
     34
    3035
    3136// Set to 1 to control the heuristics using environment variables.
     
    7378double desiredProfileLivenessRate;
    7479double desiredProfileFullnessRate;
     80
     81
     82
     83
     84
     85
     86
     87
    7588
    7689#if ENABLE(RUN_TIME_HEURISTICS)
     
    149162    SET(desiredProfileFullnessRate, 0.35);
    150163   
     164
     165
     166
     167
     168
     169
     170
     171
     172
     173
     174
     175
     176
     177
     178
     179
     180
     181
     182
     183
     184
     185
     186
     187
    151188    ASSERT(executionCounterValueForDontOptimizeAnytimeSoon <= executionCounterValueForOptimizeAfterLongWarmUp);
    152189    ASSERT(executionCounterValueForOptimizeAfterLongWarmUp <= executionCounterValueForOptimizeAfterWarmUp);
  • trunk/Source/JavaScriptCore/runtime/Heuristics.h

    r98214 r98937  
    6565extern double desiredProfileFullnessRate;
    6666
     67
     68
     69
     70
     71
     72
     73
     74
    6775void initializeHeuristics();
    6876
  • trunk/Source/JavaScriptCore/wtf/Atomics.h

    r97557 r98937  
    6161
    6262#include "Platform.h"
     63
    6364
    6465#if OS(WINDOWS)
     
    117118#endif
    118119
     120
     121
     122
     123
     124
     125
     126
     127
     128
     129
     130
     131
     132
     133
     134
     135
     136
     137
     138
     139
     140
     141
     142
    119143} // namespace WTF
    120144
  • trunk/Source/JavaScriptCore/wtf/Bitmap.h

    r95901 r98937  
    2020#define Bitmap_h
    2121
     22
    2223#include "FixedArray.h"
    2324#include "StdLibExtras.h"
     
    2728namespace WTF {
    2829
    29 template<size_t size>
     30enum BitmapAtomicMode {
     31    // This makes concurrentTestAndSet behave just like testAndSet.
     32    BitmapNotAtomic,
     33
     34    // This makes concurrentTestAndSet use compareAndSwap, so that it's
     35    // atomic even when used concurrently.
     36    BitmapAtomic
     37};
     38
     39template<size_t size, BitmapAtomicMode atomicMode = BitmapNotAtomic>
    3040class Bitmap {
    3141private:
     
    3949    bool testAndSet(size_t);
    4050    bool testAndClear(size_t);
     51
     52
    4153    size_t nextPossiblyUnset(size_t) const;
    4254    void clear(size_t);
     
    6173};
    6274
    63 template<size_t size>
    64 inline Bitmap<size>::Bitmap()
     75template<size_t size>
     76inline Bitmap<size>::Bitmap()
    6577{
    6678    clearAll();
    6779}
    6880
    69 template<size_t size>
    70 inline bool Bitmap<size>::get(size_t n) const
     81template<size_t size>
     82inline bool Bitmap<size>::get(size_t n) const
    7183{
    7284    return !!(bits[n / wordSize] & (one << (n % wordSize)));
    7385}
    7486
    75 template<size_t size>
    76 inline void Bitmap<size>::set(size_t n)
     87template<size_t size>
     88inline void Bitmap<size>::set(size_t n)
    7789{
    7890    bits[n / wordSize] |= (one << (n % wordSize));
    7991}
    8092
    81 template<size_t size>
    82 inline bool Bitmap<size>::testAndSet(size_t n)
     93template<size_t size>
     94inline bool Bitmap<size>::testAndSet(size_t n)
    8395{
    8496    WordType mask = one << (n % wordSize);
     
    89101}
    90102
    91 template<size_t size>
    92 inline bool Bitmap<size>::testAndClear(size_t n)
     103template<size_t size>
     104inline bool Bitmap<size>::testAndClear(size_t n)
    93105{
    94106    WordType mask = one << (n % wordSize);
     
    99111}
    100112
    101 template<size_t size>
    102 inline void Bitmap<size>::clear(size_t n)
     113template<size_t size, BitmapAtomicMode atomicMode>
     114inline bool Bitmap<size, atomicMode>::concurrentTestAndSet(size_t n)
     115{
     116    if (atomicMode == BitmapNotAtomic)
     117        return testAndSet(n);
     118
     119    ASSERT(atomicMode == BitmapAtomic);
     120   
     121    WordType mask = one << (n % wordSize);
     122    size_t index = n / wordSize;
     123    WordType* wordPtr = bits.data() + index;
     124    WordType oldValue;
     125    do {
     126        oldValue = *wordPtr;
     127        if (oldValue & mask)
     128            return true;
     129    } while (!weakCompareAndSwap(wordPtr, oldValue, oldValue | mask));
     130    return false;
     131}
     132
     133template<size_t size, BitmapAtomicMode atomicMode>
     134inline bool Bitmap<size, atomicMode>::concurrentTestAndClear(size_t n)
     135{
     136    if (atomicMode == BitmapNotAtomic)
     137        return testAndClear(n);
     138
     139    ASSERT(atomicMode == BitmapAtomic);
     140   
     141    WordType mask = one << (n % wordSize);
     142    size_t index = n / wordSize;
     143    WordType* wordPtr = bits.data() + index;
     144    WordType oldValue;
     145    do {
     146        oldValue = *wordPtr;
     147        if (!(oldValue & mask))
     148            return false;
     149    } while (!weakCompareAndSwap(wordPtr, oldValue, oldValue & ~mask));
     150    return true;
     151}
     152
     153template<size_t size, BitmapAtomicMode atomicMode>
     154inline void Bitmap<size, atomicMode>::clear(size_t n)
    103155{
    104156    bits[n / wordSize] &= ~(one << (n % wordSize));
    105157}
    106158
    107 template<size_t size>
    108 inline void Bitmap<size>::clearAll()
     159template<size_t size>
     160inline void Bitmap<size>::clearAll()
    109161{
    110162    memset(bits.data(), 0, sizeof(bits));
    111163}
    112164
    113 template<size_t size>
    114 inline size_t Bitmap<size>::nextPossiblyUnset(size_t start) const
     165template<size_t size>
     166inline size_t Bitmap<size>::nextPossiblyUnset(size_t start) const
    115167{
    116168    if (!~bits[start / wordSize])
     
    119171}
    120172
    121 template<size_t size>
    122 inline int64_t Bitmap<size>::findRunOfZeros(size_t runLength) const
     173template<size_t size>
     174inline int64_t Bitmap<size>::findRunOfZeros(size_t runLength) const
    123175{
    124176    if (!runLength)
     
    139191}
    140192
    141 template<size_t size>
    142 inline size_t Bitmap<size>::count(size_t start) const
     193template<size_t size>
     194inline size_t Bitmap<size>::count(size_t start) const
    143195{
    144196    size_t result = 0;
     
    152204}
    153205
    154 template<size_t size>
    155 inline size_t Bitmap<size>::isEmpty() const
     206template<size_t size>
     207inline size_t Bitmap<size>::isEmpty() const
    156208{
    157209    for (size_t i = 0; i < words; ++i)
     
    161213}
    162214
    163 template<size_t size>
    164 inline size_t Bitmap<size>::isFull() const
     215template<size_t size>
     216inline size_t Bitmap<size>::isFull() const
    165217{
    166218    for (size_t i = 0; i < words; ++i)
  • trunk/Source/JavaScriptCore/wtf/MainThread.h

    r97073 r98937  
    5050
    5151bool isMainThread();
     52
     53
     54
     55
     56
     57
     58
     59
    5260
    5361// NOTE: these functions are internal to the callOnMainThread implementation.
     
    7179using WTF::setMainThreadCallbacksPaused;
    7280using WTF::isMainThread;
     81
    7382#endif // MainThread_h
  • trunk/Source/JavaScriptCore/wtf/Platform.h

    r98629 r98937  
    10751075#endif
    10761076
     1077
     1078
     1079
     1080
     1081
     1082
     1083
     1084
    10771085#ifndef NDEBUG
    10781086#ifndef ENABLE_GC_VALIDATION
  • trunk/Source/JavaScriptCore/wtf/ThreadSpecific.h

    r94890 r98937  
    6666public:
    6767    ThreadSpecific();
     68
    6869    T* operator->();
    6970    operator T*();
     
    276277
    277278template<typename T>
     279
     280
     281
     282
     283
     284
    278285inline ThreadSpecific<T>::operator T*()
    279286{
  • trunk/Source/JavaScriptCore/wtf/mac/MainThreadMac.mm

    r95448 r98937  
    3434#import <stdio.h>
    3535#import <wtf/Assertions.h>
     36
    3637#import <wtf/Threading.h>
     38
    3739
    3840@interface JSWTFMainThreadCaller : NSObject {
     
    5860static NSThread* mainThreadNSThread;
    5961
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
    6073void initializeMainThreadPlatform()
    6174{
     
    6679    mainThreadPthread = pthread_self();
    6780    mainThreadNSThread = [[NSThread currentThread] retain];
     81
     82
    6883}
    6984
     
    7994    mainThreadPthread = 0;
    8095    mainThreadNSThread = nil;
     96
     97
    8198}
    8299
     
    129146}
    130147
     148
     149
     150
     151
     152
     153
     154
     155
     156
     157
     158
     159
     160
     161
     162
     163
     164
     165
     166
     167
     168
     169
     170
     171
     172
     173
     174
    131175} // namespace WTF
  • trunk/Source/WebCore/ChangeLog

    r98936 r98937  
     1
     2
     3
     4
     5
     6
     7
     8
     9
     10
     11
     12
     13
     14
     15
    1162011-10-31  Andy Estes  <aestes@apple.com>
    217
  • trunk/Source/WebCore/platform/TreeShared.h

    r97137 r98937  
    101101    T* parent() const
    102102    {
    103         ASSERT(isMainThread());
     103        ASSERT(isMainThread());
    104104        return m_parent;
    105105    }
Note: See TracChangeset for help on using the changeset viewer.