Ignore:
Timestamp:
Dec 14, 2009, 12:13:24 AM (15 years ago)
Author:
[email protected]
Message:

JavaScriptCore: Changed GC from mark-sweep to mark-allocate.

Reviewed by Sam Weinig.

Added WeakGCMap to keep WebCore blissfully ignorant about objects that
have become garbage but haven't run their destructors yet.

1% SunSpider speedup.
7.6% v8 speedup (37% splay speedup).
17% speedup on bench-alloc-nonretained.js.
18% speedup on bench-alloc-retained.js.

  • API/JSBase.cpp:

(JSGarbageCollect):

files.

  • debugger/Debugger.cpp:

(JSC::Debugger::recompileAllJSFunctions): Updated to use the Collector
iterator abstraction.

  • jsc.cpp:

(functionGC): Updated for rename.

  • runtime/Collector.cpp: Slightly reduced the number of allocations per

collection, so that small workloads only allocate on collector block,
rather than two.

(JSC::Heap::Heap): Updated to use the new allocateBlock function.

(JSC::Heap::destroy): Updated to use the new freeBlocks function.

(JSC::Heap::allocateBlock): New function to initialize a block when
allocating it.

(JSC::Heap::freeBlock): Consolidated the responsibility for running
destructors into this function.

(JSC::Heap::freeBlocks): Updated to use freeBlock.

(JSC::Heap::recordExtraCost): Sweep the heap in this reporting function,
so that allocation, which is more common, doesn't have to check extraCost.

(JSC::Heap::heapAllocate): Run destructors right before recycling a
garbage cell. This has better cache utilization than a separate sweep phase.

(JSC::Heap::resizeBlocks):
(JSC::Heap::growBlocks):
(JSC::Heap::shrinkBlocks): New set of functions for managing the size of
the heap, now that the heap doesn't maintain any information about its
size.

(JSC::isPointerAligned):
(JSC::isHalfCellAligned):
(JSC::isPossibleCell):
(JSC::isCellAligned):
(JSC::Heap::markConservatively): Cleaned up this code a bit.

(JSC::Heap::clearMarkBits):
(JSC::Heap::markedCells): Some helper functions for examining the the mark
bitmap.

(JSC::Heap::sweep): Simplified this function by using a DeadObjectIterator.

(JSC::Heap::markRoots): Reordered some operations for clarity.

(JSC::Heap::objectCount):
(JSC::Heap::addToStatistics):
(JSC::Heap::statistics): Rewrote these functions to calculate an object
count on demand, since the heap doesn't maintain this information by
itself.

(JSC::Heap::reset): New function for resetting the heap once we've
exhausted heap space.

(JSC::Heap::collectAllGarbage): This function matches the old collect()
behavior, but it's now an uncommon function used only by API.

  • runtime/Collector.h:

(JSC::CollectorBitmap::count):
(JSC::CollectorBitmap::isEmpty): Added some helper functions for managing
the collector mark bitmap.

(JSC::Heap::reportExtraMemoryCost): Changed reporting from cell equivalents
to bytes, so it's easier to understand.

  • runtime/CollectorHeapIterator.h:

(JSC::CollectorHeapIterator::CollectorHeapIterator):
(JSC::CollectorHeapIterator::operator!=):
(JSC::CollectorHeapIterator::operator*):
(JSC::CollectorHeapIterator::advance):
(JSC::::LiveObjectIterator):
(JSC::::operator):
(JSC::::DeadObjectIterator):
(JSC::::ObjectIterator): New iterators for encapsulating details about
heap layout, and what's live and dead on the heap.

  • runtime/JSArray.cpp:

(JSC::JSArray::putSlowCase):
(JSC::JSArray::increaseVectorLength): Delay reporting extra cost until
we're fully constructed, so the heap mark phase won't visit us in an
invalid state.

  • runtime/JSCell.h:

(JSC::JSCell::):
(JSC::JSCell::createDummyStructure):
(JSC::JSCell::JSCell):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):

  • runtime/JSGlobalData.h: Added a dummy cell to simplify allocation logic.
  • runtime/JSString.h:

(JSC::jsSubstring): Don't report extra cost for substrings, since they
share a buffer that's already reported extra cost.

  • runtime/Tracing.d:
  • runtime/Tracing.h: Changed these dtrace hooks not to report object

counts, since they're no longer cheap to compute.

  • runtime/UString.h: Updated for renames.
  • runtime/WeakGCMap.h: Added.

(JSC::WeakGCMap::isEmpty):
(JSC::WeakGCMap::uncheckedGet):
(JSC::WeakGCMap::uncheckedBegin):
(JSC::WeakGCMap::uncheckedEnd):
(JSC::::get):
(JSC::::take):
(JSC::::set):
(JSC::::uncheckedRemove): Mentioned above.

  • wtf/StdLibExtras.h:

(WTF::bitCount): Added a bit population count function, so the heap can
count live objects to fulfill statistics questions.

JavaScriptGlue: Changed GC from mark-sweep to mark-allocate.

Reviewed by Sam Weinig.

  • JavaScriptGlue.cpp:

(JSCollect): Updated for rename. Fixed a bug where JSGlue would not check
to avoid nested GC calls.

WebCore: Changed GC from mark-sweep to mark-allocate.

Reviewed by Sam Weinig.

  • ForwardingHeaders/runtime/WeakGCMap.h: Added.
  • bindings/js/GCController.cpp:

(WebCore::collect):
(WebCore::GCController::gcTimerFired):
(WebCore::GCController::garbageCollectNow): Updated for rename.

  • bindings/js/JSDOMBinding.cpp:

(WebCore::removeWrappers):
(WebCore::hasCachedDOMObjectWrapperUnchecked):
(WebCore::hasCachedDOMObjectWrapper):
(WebCore::hasCachedDOMNodeWrapperUnchecked):
(WebCore::forgetDOMObject):
(WebCore::forgetDOMNode):
(WebCore::isObservableThroughDOM):
(WebCore::markDOMNodesForDocument):
(WebCore::markDOMObjectWrapper):
(WebCore::markDOMNodeWrapper):

  • bindings/js/JSDOMBinding.h: Changed DOM wrapper maps to be WeakGCMaps.

Don't ASSERT that an item must be in the WeakGCMap when its destructor
runs, since it might have been overwritten in the map first.

  • bindings/js/JSDocumentCustom.cpp:

(WebCore::toJS): Changed Document from a DOM object wrapper to a DOM node
wrapper, to simplify some code.

  • bindings/js/JSInspectedObjectWrapper.cpp:

(WebCore::JSInspectedObjectWrapper::JSInspectedObjectWrapper):
(WebCore::JSInspectedObjectWrapper::~JSInspectedObjectWrapper):

  • bindings/js/JSInspectorCallbackWrapper.cpp: Use a WeakGCMap for these

wrappers.

  • bindings/js/JSNodeCustom.cpp:

(WebCore::JSNode::markChildren): Updated for WeakGCMap and Document using
a DOM node wrapper instead of a DOM object wrapper.

  • bindings/js/JSSVGPODTypeWrapper.h:

(WebCore::JSSVGDynamicPODTypeWrapperCache::wrapperMap):
(WebCore::JSSVGDynamicPODTypeWrapperCache::lookupOrCreateWrapper):
(WebCore::JSSVGDynamicPODTypeWrapperCache::forgetWrapper):
(WebCore::::~JSSVGDynamicPODTypeWrapper): Shined a small beam of sanity light
on this code. Use hashtable-based lookup in JSSVGPODTypeWrapper.h instead
of linear lookup through iteration, since that's what hashtables were
invented for. Make JSSVGPODTypeWrapper.h responsible for reomving itself
from the table, instead of its JS wrapper, to decouple these objects from
GC, and because these objects are refCounted, not solely owned by their
JS wrappers.

  • bindings/scripts/CodeGeneratorJS.pm:
  • dom/Document.h: Adopted changes above.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/Collector.h

    r52047 r52082  
    2929#include <wtf/Noncopyable.h>
    3030#include <wtf/OwnPtr.h>
     31#include <wtf/StdLibExtras.h>
    3132#include <wtf/Threading.h>
    3233
    33 // This is supremely lame that we require pthreads to build on windows.
    3434#if ENABLE(JSC_MULTIPLE_THREADS)
    3535#include <pthread.h>
     
    5050    enum HeapType { PrimaryHeap, NumberHeap };
    5151
    52     template <HeapType> class CollectorHeapIterator;
     52    template <HeapType> class LiveObjectIterator;
    5353
    5454    struct CollectorHeap {
     55        size_t nextBlock;
     56        size_t nextCell;
     57
    5558        CollectorBlock** blocks;
    5659        size_t numBlocks;
    5760        size_t usedBlocks;
    58         size_t firstBlockWithPossibleSpace;
    59 
    60         size_t numLiveObjects;
    61         size_t numLiveObjectsAtLastCollect;
     61
    6262        size_t extraCost;
    63 #if ENABLE(JSC_ZOMBIES)
    64         size_t numZombies;
    65 #endif
     63       
     64        bool didShrink;
    6665
    6766        OperationInProgress operationInProgress;
     
    7170    public:
    7271        class Thread;
    73         typedef CollectorHeapIterator<PrimaryHeap> iterator;
    7472
    7573        void destroy();
     
    7876        void* allocate(size_t);
    7977
    80         bool collect();
    8178        bool isBusy(); // true if an allocation or collection is in progress
    82 
    83         static const size_t minExtraCostSize = 256;
     79        void collectAllGarbage();
     80
     81        static const size_t minExtraCost = 256;
     82        static const size_t maxExtraCost = 1024 * 1024;
    8483
    8584        void reportExtraMemoryCost(size_t cost);
    8685
    87         size_t objectCount();
     86        size_t objectCount() const;
    8887        struct Statistics {
    8988            size_t size;
     
    115114        static bool isNumber(JSCell*);
    116115       
    117         // Iterators for the object heap.
    118         iterator primaryHeapBegin();
    119         iterator primaryHeapEnd();
     116        LiveObjectIterator<PrimaryHeap> primaryHeapBegin();
     117        LiveObjectIterator<PrimaryHeap> primaryHeapEnd();
    120118
    121119    private:
    122120        template <HeapType heapType> void* heapAllocate(size_t);
    123         template <HeapType heapType> size_t sweep();
     121        void reset();
     122        void collectRemainingGarbage();
     123        template <HeapType heapType> void sweep();
    124124        static CollectorBlock* cellBlock(const JSCell*);
    125125        static size_t cellOffset(const JSCell*);
     
    132132        template <HeapType heapType> NEVER_INLINE void freeBlock(size_t);
    133133        NEVER_INLINE void freeBlock(CollectorBlock*);
    134         void freeBlocks(CollectorHeap*);
     134        template <HeapType heapType> void freeBlocks();
     135        template <HeapType heapType> void resizeBlocks();
     136        template <HeapType heapType> void growBlocks(size_t neededBlocks);
     137        template <HeapType heapType> void shrinkBlocks(size_t neededBlocks);
     138        template <HeapType heapType> void clearMarkBits();
     139        template <HeapType heapType> void clearMarkBits(CollectorBlock*);
     140        template <HeapType heapType> size_t markedCells(size_t startBlock = 0, size_t startCell = 0) const;
    135141
    136142        void recordExtraCost(size_t);
     143
     144        template <HeapType heapType> void addToStatistics(Statistics&) const;
     145        template <HeapType heapType> size_t objectCount() const;
     146
     147        void markRoots();
    137148        void markProtectedObjects(MarkStack&);
    138149        void markCurrentThreadConservatively(MarkStack&);
     
    190201    const size_t CELL_MASK = CELL_SIZE - 1;
    191202    const size_t CELL_ALIGN_MASK = ~CELL_MASK;
    192     const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2);
     203    const size_t CELLS_PER_BLOCK = (BLOCK_SIZE - sizeof(Heap*) - sizeof(HeapType)) * 8 * CELL_SIZE / (8 * CELL_SIZE + 1) / CELL_SIZE; // one bitmap byte can represent 8 cells.
     204   
    193205    const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK;
    194206    const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8;
    195207    const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t);
    196  
     208
    197209    struct CollectorBitmap {
    198210        uint32_t bits[BITMAP_WORDS];
     
    201213        void clear(size_t n) { bits[n >> 5] &= ~(1 << (n & 0x1F)); }
    202214        void clearAll() { memset(bits, 0, sizeof(bits)); }
     215        size_t count(size_t startCell = 0)
     216        {
     217            size_t result = 0;
     218            for ( ; (startCell & 0x1F) != 0; ++startCell) {
     219                if (get(startCell))
     220                    ++result;
     221            }
     222            for (size_t i = startCell >> 5; i < BITMAP_WORDS; ++i)
     223                result += WTF::bitCount(bits[i]);
     224            return result;
     225        }
     226        size_t isEmpty() // Much more efficient than testing count() == 0.
     227        {
     228            for (size_t i = 0; i < BITMAP_WORDS; ++i)
     229                if (bits[i] != 0)
     230                    return false;
     231            return true;
     232        }
    203233    };
    204234 
    205235    struct CollectorCell {
    206         union {
    207             double memory[CELL_ARRAY_LENGTH];
    208             struct {
    209                 void* zeroIfFree;
    210                 ptrdiff_t next;
    211             } freeCell;
    212         } u;
     236        double memory[CELL_ARRAY_LENGTH];
    213237    };
    214238
    215239    struct SmallCollectorCell {
    216         union {
    217             double memory[CELL_ARRAY_LENGTH / 2];
    218             struct {
    219                 void* zeroIfFree;
    220                 ptrdiff_t next;
    221             } freeCell;
    222         } u;
     240        double memory[CELL_ARRAY_LENGTH / 2];
    223241    };
    224242
     
    226244    public:
    227245        CollectorCell cells[CELLS_PER_BLOCK];
    228         uint32_t usedCells;
    229         CollectorCell* freeList;
    230246        CollectorBitmap marked;
    231247        Heap* heap;
     
    236252    public:
    237253        SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK];
    238         uint32_t usedCells;
    239         SmallCollectorCell* freeList;
    240254        CollectorBitmap marked;
    241255        Heap* heap;
     
    288302    inline void Heap::reportExtraMemoryCost(size_t cost)
    289303    {
    290         if (cost > minExtraCostSize)
    291             recordExtraCost(cost / (CELL_SIZE * 2));
     304        if (cost > minExtraCost)
     305            recordExtraCost(cost);
    292306    }
    293307
Note: See TracChangeset for help on using the changeset viewer.