Ignore:
Timestamp:
Jun 19, 2008, 10:29:29 AM (17 years ago)
Author:
[email protected]
Message:

Reviewed by Darin.

Prepare JavaScript heap for being per-thread.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/collector.cpp

    r34597 r34659  
    11/*
    2  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
     2 *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
    33 *  Copyright (C) 2007 Eric Seidel <[email protected]>
    44 *
     
    3636#if USE(MULTIPLE_THREADS)
    3737#include <pthread.h>
     38#include <wtf/Threading.h>
    3839#endif
    3940
     
    8081
    8182const size_t SPARE_EMPTY_BLOCKS = 2;
    82 const size_t MIN_ARRAY_SIZE = 14;
    8383const size_t GROWTH_FACTOR = 2;
    8484const size_t LOW_WATER_FACTOR = 4;
    8585const size_t ALLOCATIONS_PER_COLLECTION = 4000;
    86 
    87 static CollectorHeap primaryHeap = { 0, 0, 0, 0, 0, 0, 0, NoOperation };
    88 static CollectorHeap numberHeap = { 0, 0, 0, 0, 0, 0, 0, NoOperation };
    89 
    90 size_t Collector::mainThreadOnlyObjectCount = 0;
    91 HashSet<ArgList*>* Collector::m_markListSet;
    92 
    93 static CollectorBlock* allocateBlock()
     86// This value has to be a macro to be used in max() without introducing
     87// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
     88#define MIN_ARRAY_SIZE 14UL
     89
     90Heap::Heap()
     91    : m_pagesize(getpagesize())
     92    , mainThreadOnlyObjectCount(0)
     93    , m_markListSet(0)
     94{
     95    memset(&primaryHeap, 0, sizeof(CollectorHeap));
     96    memset(&numberHeap, 0, sizeof(CollectorHeap));
     97}
     98
     99static NEVER_INLINE CollectorBlock* allocateBlock()
    94100{
    95101#if PLATFORM(DARWIN)   
     
    104110    memset(address, 0, BLOCK_SIZE);
    105111#else
    106     static size_t pagesize = getpagesize();
    107112   
    108113    size_t extra = 0;
    109     if (BLOCK_SIZE > pagesize)
    110         extra = BLOCK_SIZE - pagesize;
     114    if (BLOCK_SIZE > m_pagesize)
     115        extra = BLOCK_SIZE - m_pagesize;
    111116
    112117    void* mmapResult = mmap(NULL, BLOCK_SIZE + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
     
    139144    free(block);
    140145#else
    141     munmap(reinterpret_cast<char *>(block), BLOCK_SIZE);
    142 #endif
    143 }
    144 
    145 void Collector::recordExtraCost(size_t cost)
     146    munmap(reinterpret_cast<char*>(block), BLOCK_SIZE);
     147#endif
     148}
     149
     150void Heap::recordExtraCost(size_t cost)
    146151{
    147152    // Our frequency of garbage collection tries to balance memory use against speed
     
    160165}
    161166
    162 template <Collector::HeapType heapType> struct HeapConstants;
    163 
    164 template <> struct HeapConstants<Collector::PrimaryHeap> {
     167template <Heap::HeapType heapType> struct HeapConstants;
     168
     169template <> struct HeapConstants<Heap::PrimaryHeap> {
    165170    static const size_t cellSize = CELL_SIZE;
    166171    static const size_t cellsPerBlock = CELLS_PER_BLOCK;
     
    170175};
    171176
    172 template <> struct HeapConstants<Collector::NumberHeap> {
     177template <> struct HeapConstants<Heap::NumberHeap> {
    173178    static const size_t cellSize = SMALL_CELL_SIZE;
    174179    static const size_t cellsPerBlock = SMALL_CELLS_PER_BLOCK;
     
    178183};
    179184
    180 template <Collector::HeapType heapType> ALWAYS_INLINE void* Collector::heapAllocate(size_t s)
     185template <Heap::HeapType heapType> ALWAYS_INLINE void* Heap::heapAllocate(size_t s)
    181186{
    182187    typedef typename HeapConstants<heapType>::Block Block;
     
    268273        targetBlock = (Block*)allocateBlock();
    269274        targetBlock->freeList = targetBlock->cells;
     275        targetBlock->heap = this;
    270276        targetBlockUsedCells = 0;
    271277        heap.blocks[usedBlocks] = (CollectorBlock*)targetBlock;
     
    291297}
    292298
    293 #ifndef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE
    294 void* Collector::allocate(size_t s)
     299void* Heap::allocate(size_t s)
    295300{
    296301    return heapAllocate<PrimaryHeap>(s);
    297302}
    298 #endif
    299 
    300 void* Collector::allocateNumber(size_t s)
     303
     304void* Heap::allocateNumber(size_t s)
    301305{
    302306    return heapAllocate<NumberHeap>(s);
     
    363367#endif
    364368
    365 void Collector::registerAsMainThread()
     369void Heap::registerAsMainThread()
    366370{
    367371#if USE(MULTIPLE_THREADS)
     
    405409}
    406410
    407 class Collector::Thread {
     411class Heap::Thread {
    408412public:
    409413    Thread(pthread_t pthread, const PlatformThread& platThread, void* base)
     
    422426pthread_key_t registeredThreadKey;
    423427pthread_once_t registeredThreadKeyOnce = PTHREAD_ONCE_INIT;
    424 Collector::Thread* registeredThreads;
     428Heap::Thread* registeredThreads;
    425429
    426430static void destroyRegisteredThread(void* data)
    427431{
    428     Collector::Thread* thread = (Collector::Thread*)data;
     432    Heap::Thread* thread = (Heap::Thread*)data;
    429433
    430434    // Can't use JSLock convenience object here because we don't want to re-register
     
    435439        registeredThreads = registeredThreads->next;
    436440    } else {
    437         Collector::Thread* last = registeredThreads;
    438         Collector::Thread* t;
     441        Heap::Thread* last = registeredThreads;
     442        Heap::Thread* t;
    439443        for (t = registeredThreads->next; t != NULL; t = t->next) {
    440444            if (t == thread) {         
     
    457461}
    458462
    459 void Collector::registerThread()
     463void Heap::registerThread()
    460464{
    461465    ASSERT(JSLock::lockCount() > 0);
     
    465469
    466470    if (!pthread_getspecific(registeredThreadKey)) {
    467 #if PLATFORM(DARWIN)
    468         if (onMainThread())
    469             CollectorHeapIntrospector::init(&primaryHeap, &numberHeap);
    470 #endif
    471 
    472         Collector::Thread* thread = new Collector::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase());
     471        Heap::Thread* thread = new Heap::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase());
    473472
    474473        thread->next = registeredThreads;
     
    478477}
    479478
     479void Heap::initializeHeapIntrospector()
     480{
     481    ASSERT(pthread_main_np());
     482    CollectorHeapIntrospector::init(&primaryHeap, &numberHeap);
     483}
     484
    480485#endif
    481486
     
    485490#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0)
    486491
    487 void Collector::markStackObjectsConservatively(void* start, void* end)
     492void Heap::markStackObjectsConservatively(void* start, void* end)
    488493{
    489494    if (start > end) {
     
    517522            for (size_t block = 0; block < usedNumberBlocks; block++) {
    518523                if ((numberBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
    519                     Collector::markCell(reinterpret_cast<JSCell*>(xAsBits));
     524                    Heap::markCell(reinterpret_cast<JSCell*>(xAsBits));
    520525                    goto endMarkLoop;
    521526                }
     
    539544}
    540545
    541 void NEVER_INLINE Collector::markCurrentThreadConservativelyInternal()
     546void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal()
    542547{
    543548    void* dummy;
     
    547552}
    548553
    549 void Collector::markCurrentThreadConservatively()
     554void Heap::markCurrentThreadConservatively()
    550555{
    551556    // setjmp forces volatile registers onto the stack
     
    692697}
    693698
    694 void Collector::markOtherThreadConservatively(Thread* thread)
    695 {
     699void Heap::markOtherThreadConservatively(Thread* thread)
     700{
     701    ASSERT(this == JSGlobalData::sharedInstance().heap);
     702
    696703    suspendThread(thread->platformThread);
    697704
     
    710717#endif
    711718
    712 void Collector::markStackObjectsConservatively()
     719void Heap::markStackObjectsConservatively()
    713720{
    714721    markCurrentThreadConservatively();
    715722
    716723#if USE(MULTIPLE_THREADS)
    717     for (Thread* thread = registeredThreads; thread != NULL; thread = thread->next) {
    718         if (!pthread_equal(thread->posixThread, pthread_self())) {
    719             markOtherThreadConservatively(thread);
     724
     725    if (this == JSGlobalData::sharedInstance().heap) {
     726
     727#ifndef NDEBUG
     728        // Forbid malloc during the mark phase. Marking a thread suspends it, so
     729        // a malloc inside mark() would risk a deadlock with a thread that had been
     730        // suspended while holding the malloc lock.
     731        fastMallocForbid();
     732#endif
     733        for (Thread* thread = registeredThreads; thread != NULL; thread = thread->next) {
     734            if (!pthread_equal(thread->posixThread, pthread_self()))
     735                markOtherThreadConservatively(thread);
    720736        }
    721     }
    722 #endif
    723 }
    724 
    725 typedef HashCountedSet<JSCell*> ProtectCountSet;
    726 
    727 static ProtectCountSet& protectedValues()
    728 {
    729     static ProtectCountSet staticProtectCountSet;
    730     return staticProtectCountSet;
    731 }
    732 
    733 void Collector::protect(JSValue* k)
     737#ifndef NDEBUG
     738        fastMallocAllow();
     739#endif
     740    }
     741#endif
     742}
     743
     744void Heap::protect(JSValue* k)
    734745{
    735746    ASSERT(k);
     
    740751        return;
    741752
    742     protectedValues().add(k->asCell());
    743 }
    744 
    745 void Collector::unprotect(JSValue* k)
     753    protectedValues.add(k->asCell());
     754}
     755
     756void Heap::unprotect(JSValue* k)
    746757{
    747758    ASSERT(k);
     
    752763        return;
    753764
    754     protectedValues().remove(k->asCell());
    755 }
    756 
    757 void Collector::collectOnMainThreadOnly(JSValue* value)
     765    protectedValues.remove(k->asCell());
     766}
     767
     768void Heap::collectOnMainThreadOnly(JSValue* value)
    758769{
    759770    ASSERT(value);
     
    769780}
    770781
    771 void Collector::markProtectedObjects()
    772 {
    773     ProtectCountSet& protectedValues = KJS::protectedValues();
     782Heap* Heap::heap(const JSValue* v)
     783{
     784    if (JSImmediate::isImmediate(v))
     785        return 0;
     786    return Heap::cellBlock(v->asCell())->heap;
     787}
     788
     789void Heap::markProtectedObjects()
     790{
    774791    ProtectCountSet::iterator end = protectedValues.end();
    775792    for (ProtectCountSet::iterator it = protectedValues.begin(); it != end; ++it) {
     
    780797}
    781798
    782 void Collector::markMainThreadOnlyObjects()
     799void Heap::markMainThreadOnlyObjects()
    783800{
    784801#if USE(MULTIPLE_THREADS)
     
    822839}
    823840
    824 template <Collector::HeapType heapType> size_t Collector::sweep(bool currentThreadIsMainThread)
     841template <Heap::HeapType heapType> size_t Heap::sweep(bool currentThreadIsMainThread)
    825842{
    826843    typedef typename HeapConstants<heapType>::Block Block;
     
    829846    UNUSED_PARAM(currentThreadIsMainThread); // currentThreadIsMainThread is only used in ASSERTs
    830847    // SWEEP: delete everything with a zero refcount (garbage) and unmark everything else
    831     CollectorHeap& heap = heapType == Collector::PrimaryHeap ? primaryHeap : numberHeap;
     848    CollectorHeap& heap = heapType == Heap::PrimaryHeap ? primaryHeap : numberHeap;
    832849   
    833850    size_t emptyBlocks = 0;
     
    846863                    Cell* cell = curBlock->cells + i;
    847864                   
    848                     if (heapType != Collector::NumberHeap) {
     865                    if (heapType != Heap::NumberHeap) {
    849866                        JSCell* imp = reinterpret_cast<JSCell*>(cell);
    850867                        // special case for allocated but uninitialized object
     
    857874                        if (curBlock->collectOnMainThreadOnly.get(i)) {
    858875                            curBlock->collectOnMainThreadOnly.clear(i);
    859                             --Collector::mainThreadOnlyObjectCount;
     876                            --mainThreadOnlyObjectCount;
    860877                        }
    861878                        imp->~JSCell();
     
    879896                } else {
    880897                    if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) {
    881                         if (heapType != Collector::NumberHeap) {
     898                        if (heapType != Heap::NumberHeap) {
    882899                            JSCell* imp = reinterpret_cast<JSCell*>(cell);
    883900                            ASSERT(currentThreadIsMainThread || !curBlock->collectOnMainThreadOnly.get(i));
    884901                            if (curBlock->collectOnMainThreadOnly.get(i)) {
    885902                                curBlock->collectOnMainThreadOnly.clear(i);
    886                                 --Collector::mainThreadOnlyObjectCount;
     903                                --mainThreadOnlyObjectCount;
    887904                            }
    888905                            imp->~JSCell();
     
    932949}
    933950   
    934 bool Collector::collect()
    935 {
    936     ASSERT(JSLock::lockCount() > 0);
    937     ASSERT(JSLock::currentThreadIsHoldingLock());
     951bool Heap::collect()
     952{
     953#ifndef NDEBUG
     954    if (JSGlobalData::sharedInstance().heap == this) {
     955        ASSERT(JSLock::lockCount() > 0);
     956        ASSERT(JSLock::currentThreadIsHoldingLock());
     957    }
     958#endif
    938959
    939960    ASSERT((primaryHeap.operationInProgress == NoOperation) | (numberHeap.operationInProgress == NoOperation));
     
    947968
    948969    // MARK: first mark all referenced objects recursively starting out from the set of root objects
    949 
    950 #ifndef NDEBUG
    951     // Forbid malloc during the mark phase. Marking a thread suspends it, so
    952     // a malloc inside mark() would risk a deadlock with a thread that had been
    953     // suspended while holding the malloc lock.
    954     fastMallocForbid();
    955 #endif
    956970
    957971    markStackObjectsConservatively();
     
    964978#endif
    965979
    966 #ifndef NDEBUG
    967     fastMallocAllow();
    968 #endif
    969 
    970980    size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
    971981    size_t numLiveObjects = sweep<PrimaryHeap>(currentThreadIsMainThread);
     
    978988}
    979989
    980 size_t Collector::size()
     990size_t Heap::size()
    981991{
    982992    return primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
    983993}
    984994
    985 size_t Collector::globalObjectCount()
     995size_t Heap::globalObjectCount()
    986996{
    987997    size_t count = 0;
     
    9961006}
    9971007
    998 size_t Collector::protectedGlobalObjectCount()
     1008size_t Heap::protectedGlobalObjectCount()
    9991009{
    10001010    size_t count = 0;
     
    10021012        JSGlobalObject* o = JSGlobalObject::head();
    10031013        do {
    1004             if (protectedValues().contains(o))
     1014            if (protectedValues.contains(o))
    10051015                ++count;
    10061016            o = o->next();
     
    10101020}
    10111021
    1012 size_t Collector::protectedObjectCount()
    1013 {
    1014     return protectedValues().size();
     1022size_t Heap::protectedObjectCount()
     1023{
     1024    return protectedValues.size();
    10151025}
    10161026
     
    10481058}
    10491059
    1050 HashCountedSet<const char*>* Collector::protectedObjectTypeCounts()
     1060HashCountedSet<const char*>* Heap::protectedObjectTypeCounts()
    10511061{
    10521062    HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
    10531063
    1054     ProtectCountSet& protectedValues = KJS::protectedValues();
    10551064    ProtectCountSet::iterator end = protectedValues.end();
    10561065    for (ProtectCountSet::iterator it = protectedValues.begin(); it != end; ++it)
     
    10601069}
    10611070
    1062 bool Collector::isBusy()
     1071bool Heap::isBusy()
    10631072{
    10641073    return (primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation);
Note: See TracChangeset for help on using the changeset viewer.