Title: [128141] trunk/Source/_javascript_Core
Revision
128141
Author
[email protected]
Date
2012-09-10 20:02:46 -0700 (Mon, 10 Sep 2012)

Log Message

Added large allocation support to MarkedSpace
https://bugs.webkit.org/show_bug.cgi?id=96214

Originally reviewed by Oliver Hunt, then I added a design revision by
suggested by Phil Pizlo.

I expanded the imprecise size classes to cover up to 32KB, then added
an mmap-based allocator for everything bigger. There's a lot of tuning
we could do in these size classes, but currently they're almost
completely unused, so I haven't done any tuning.

Subtle point: the large allocator is a degenerate case of our free list
logic. Its list only ever contains zero or one items.

* heap/Heap.h:
(JSC::Heap::allocateStructure): Pipe in size information.

* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::tryAllocateHelper): Handle the case where we
find a free item in the sweep list but the item isn't big enough. This
can happen in the large allocator because it mixes sizes.

(JSC::MarkedAllocator::tryAllocate):
(JSC::MarkedAllocator::allocateSlowCase): More piping.

(JSC::MarkedAllocator::allocateBlock): Handle the oversize case.

(JSC::MarkedAllocator::addBlock): I moved the call to didAddBlock here
because it made more sense.

* heap/MarkedAllocator.h:
(MarkedAllocator):
(JSC::MarkedAllocator::allocate):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::MarkedSpace):
(JSC::MarkedSpace::resetAllocators):
(JSC::MarkedSpace::canonicalizeCellLivenessData):
(JSC::MarkedSpace::isPagedOut):
(JSC::MarkedSpace::freeBlock):
* heap/MarkedSpace.h:
(MarkedSpace):
(JSC::MarkedSpace::allocatorFor):
(JSC::MarkedSpace::destructorAllocatorFor):
(JSC::MarkedSpace::allocateWithoutDestructor):
(JSC::MarkedSpace::allocateWithDestructor):
(JSC::MarkedSpace::allocateStructure):
(JSC::MarkedSpace::forEachBlock):
* runtime/Structure.h:
(JSC::Structure): More piping.

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (128140 => 128141)


--- trunk/Source/_javascript_Core/ChangeLog	2012-09-11 01:41:27 UTC (rev 128140)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-09-11 03:02:46 UTC (rev 128141)
@@ -1,5 +1,57 @@
 2012-09-10  Geoffrey Garen  <[email protected]>
 
+        Added large allocation support to MarkedSpace
+        https://bugs.webkit.org/show_bug.cgi?id=96214
+
+        Originally reviewed by Oliver Hunt, then I added a design revision by
+        suggested by Phil Pizlo.
+
+        I expanded the imprecise size classes to cover up to 32KB, then added
+        an mmap-based allocator for everything bigger. There's a lot of tuning
+        we could do in these size classes, but currently they're almost
+        completely unused, so I haven't done any tuning.
+
+        Subtle point: the large allocator is a degenerate case of our free list
+        logic. Its list only ever contains zero or one items.
+
+        * heap/Heap.h:
+        (JSC::Heap::allocateStructure): Pipe in size information.
+
+        * heap/MarkedAllocator.cpp:
+        (JSC::MarkedAllocator::tryAllocateHelper): Handle the case where we
+        find a free item in the sweep list but the item isn't big enough. This
+        can happen in the large allocator because it mixes sizes.
+
+        (JSC::MarkedAllocator::tryAllocate):
+        (JSC::MarkedAllocator::allocateSlowCase): More piping.
+
+        (JSC::MarkedAllocator::allocateBlock): Handle the oversize case.
+
+        (JSC::MarkedAllocator::addBlock): I moved the call to didAddBlock here
+        because it made more sense.
+
+        * heap/MarkedAllocator.h:
+        (MarkedAllocator):
+        (JSC::MarkedAllocator::allocate):
+        * heap/MarkedSpace.cpp:
+        (JSC::MarkedSpace::MarkedSpace):
+        (JSC::MarkedSpace::resetAllocators):
+        (JSC::MarkedSpace::canonicalizeCellLivenessData):
+        (JSC::MarkedSpace::isPagedOut):
+        (JSC::MarkedSpace::freeBlock):
+        * heap/MarkedSpace.h:
+        (MarkedSpace):
+        (JSC::MarkedSpace::allocatorFor):
+        (JSC::MarkedSpace::destructorAllocatorFor):
+        (JSC::MarkedSpace::allocateWithoutDestructor):
+        (JSC::MarkedSpace::allocateWithDestructor):
+        (JSC::MarkedSpace::allocateStructure):
+        (JSC::MarkedSpace::forEachBlock):
+        * runtime/Structure.h:
+        (JSC::Structure): More piping.
+
+2012-09-10  Geoffrey Garen  <[email protected]>
+
         Try to fix the Windows (32-bit) build.
 
         * jit/JITOpcodes.cpp:

Modified: trunk/Source/_javascript_Core/_javascript_Core.vcproj/_javascript_Core/_javascript_Core.def (128140 => 128141)


--- trunk/Source/_javascript_Core/_javascript_Core.vcproj/_javascript_Core/_javascript_Core.def	2012-09-11 01:41:27 UTC (rev 128140)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcproj/_javascript_Core/_javascript_Core.def	2012-09-11 03:02:46 UTC (rev 128141)
@@ -63,7 +63,7 @@
     ?addSlowCase@Identifier@JSC@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVExecState@2@PAVStringImpl@4@@Z
     ?addSlowCase@Identifier@JSC@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVJSGlobalData@2@PAVStringImpl@4@@Z
     ?addStaticGlobals@JSGlobalObject@JSC@@IAEXPAUGlobalPropertyInfo@12@H@Z
-    ?allocateSlowCase@MarkedAllocator@JSC@@AAEPAXXZ
+    ?allocateSlowCase@MarkedAllocator@JSC@@AAEPAXI@Z
     ?append@StringBuilder@WTF@@QAEXPBEI@Z
     ?append@StringBuilder@WTF@@QAEXPB_WI@Z
     ?appendNumber@StringBuilder@WTF@@QAEXH@Z

Modified: trunk/Source/_javascript_Core/heap/Heap.h (128140 => 128141)


--- trunk/Source/_javascript_Core/heap/Heap.h	2012-09-11 01:41:27 UTC (rev 128140)
+++ trunk/Source/_javascript_Core/heap/Heap.h	2012-09-11 03:02:46 UTC (rev 128141)
@@ -185,7 +185,7 @@
 
         void* allocateWithDestructor(size_t);
         void* allocateWithoutDestructor(size_t);
-        void* allocateStructure();
+        void* allocateStructure(size_t);
 
         static const size_t minExtraCost = 256;
         static const size_t maxExtraCost = 1024 * 1024;
@@ -372,9 +372,9 @@
         return m_objectSpace.allocateWithoutDestructor(bytes);
     }
    
-    inline void* Heap::allocateStructure()
+    inline void* Heap::allocateStructure(size_t bytes)
     {
-        return m_objectSpace.allocateStructure();
+        return m_objectSpace.allocateStructure(bytes);
     }
  
     inline CheckedBoolean Heap::tryAllocateStorage(size_t bytes, void** outPtr)

Modified: trunk/Source/_javascript_Core/heap/MarkedAllocator.cpp (128140 => 128141)


--- trunk/Source/_javascript_Core/heap/MarkedAllocator.cpp	2012-09-11 01:41:27 UTC (rev 128140)
+++ trunk/Source/_javascript_Core/heap/MarkedAllocator.cpp	2012-09-11 03:02:46 UTC (rev 128141)
@@ -27,7 +27,7 @@
     return false;
 }
 
-inline void* MarkedAllocator::tryAllocateHelper()
+inline void* MarkedAllocator::tryAllocateHelper(size_t bytes)
 {
     if (!m_freeList.head) {
         if (m_onlyContainsStructures && !m_heap->isSafeToSweepStructures()) {
@@ -42,12 +42,20 @@
         }
 
         for (MarkedBlock*& block = m_blocksToSweep; block; block = block->next()) {
-            m_freeList = block->sweep(MarkedBlock::SweepToFreeList);
-            if (m_freeList.head) {
-                m_currentBlock = block;
-                break;
+            MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList);
+            if (!freeList.head) {
+                block->didConsumeFreeList();
+                continue;
             }
-            block->didConsumeFreeList();
+
+            if (bytes > block->cellSize()) {
+                block->zapFreeList(freeList);
+                continue;
+            }
+
+            m_currentBlock = block;
+            m_freeList = freeList;
+            break;
         }
         
         if (!m_freeList.head) {
@@ -62,16 +70,16 @@
     return head;
 }
     
-inline void* MarkedAllocator::tryAllocate()
+inline void* MarkedAllocator::tryAllocate(size_t bytes)
 {
     ASSERT(!m_heap->isBusy());
     m_heap->m_operationInProgress = Allocation;
-    void* result = tryAllocateHelper();
+    void* result = tryAllocateHelper(bytes);
     m_heap->m_operationInProgress = NoOperation;
     return result;
 }
     
-void* MarkedAllocator::allocateSlowCase()
+void* MarkedAllocator::allocateSlowCase(size_t bytes)
 {
     ASSERT(m_heap->globalData()->apiLock().currentThreadIsHoldingLock());
 #if COLLECT_ON_EVERY_ALLOCATION
@@ -82,7 +90,7 @@
     ASSERT(!m_freeList.head);
     m_heap->didAllocate(m_freeList.bytes);
     
-    void* result = tryAllocate();
+    void* result = tryAllocate(bytes);
     
     if (LIKELY(result != 0))
         return result;
@@ -90,27 +98,39 @@
     if (m_heap->shouldCollect()) {
         m_heap->collect(Heap::DoNotSweep);
 
-        result = tryAllocate();
+        result = tryAllocate(bytes);
         if (result)
             return result;
     }
 
     ASSERT(!m_heap->shouldCollect());
     
-    MarkedBlock* block = allocateBlock();
+    MarkedBlock* block = allocateBlock(bytes);
     ASSERT(block);
     addBlock(block);
         
-    result = tryAllocate();
+    result = tryAllocate(bytes);
     ASSERT(result);
     return result;
 }
 
-MarkedBlock* MarkedAllocator::allocateBlock()
+MarkedBlock* MarkedAllocator::allocateBlock(size_t bytes)
 {
-    MarkedBlock* block = MarkedBlock::create(m_heap->blockAllocator().allocate(), m_heap, m_cellSize, m_cellsNeedDestruction, m_onlyContainsStructures);
-    m_markedSpace->didAddBlock(block);
-    return block;
+    size_t minBlockSize = MarkedBlock::blockSize;
+    size_t minAllocationSize = WTF::roundUpToMultipleOf(WTF::pageSize(), sizeof(MarkedBlock) + bytes);
+    size_t blockSize = std::max(minBlockSize, minAllocationSize);
+
+    size_t cellSize = m_cellSize ? m_cellSize : WTF::roundUpToMultipleOf<MarkedBlock::atomSize>(bytes);
+
+    if (blockSize == MarkedBlock::blockSize) {
+        PageAllocationAligned allocation = m_heap->blockAllocator().allocate();
+        return MarkedBlock::create(allocation, m_heap, cellSize, m_cellsNeedDestruction, m_onlyContainsStructures);
+    }
+
+    PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, MarkedBlock::blockSize, OSAllocator::JSGCHeapPages);
+    if (!static_cast<bool>(allocation))
+        CRASH();
+    return MarkedBlock::create(allocation, m_heap, cellSize, m_cellsNeedDestruction, m_onlyContainsStructures);
 }
 
 void MarkedAllocator::addBlock(MarkedBlock* block)
@@ -121,6 +141,7 @@
     m_blockList.append(block);
     m_blocksToSweep = m_currentBlock = block;
     m_freeList = block->sweep(MarkedBlock::SweepToFreeList);
+    m_markedSpace->didAddBlock(block);
 }
 
 void MarkedAllocator::removeBlock(MarkedBlock* block)

Modified: trunk/Source/_javascript_Core/heap/MarkedAllocator.h (128140 => 128141)


--- trunk/Source/_javascript_Core/heap/MarkedAllocator.h	2012-09-11 01:41:27 UTC (rev 128140)
+++ trunk/Source/_javascript_Core/heap/MarkedAllocator.h	2012-09-11 03:02:46 UTC (rev 128141)
@@ -25,7 +25,7 @@
     size_t cellSize() { return m_cellSize; }
     bool cellsNeedDestruction() { return m_cellsNeedDestruction; }
     bool onlyContainsStructures() { return m_onlyContainsStructures; }
-    void* allocate();
+    void* allocate(size_t);
     Heap* heap() { return m_heap; }
     
     template<typename Functor> void forEachBlock(Functor&);
@@ -39,10 +39,10 @@
 private:
     friend class LLIntOffsetsExtractor;
     
-    JS_EXPORT_PRIVATE void* allocateSlowCase();
-    void* tryAllocate();
-    void* tryAllocateHelper();
-    MarkedBlock* allocateBlock();
+    JS_EXPORT_PRIVATE void* allocateSlowCase(size_t);
+    void* tryAllocate(size_t);
+    void* tryAllocateHelper(size_t);
+    MarkedBlock* allocateBlock(size_t);
     
     MarkedBlock::FreeList m_freeList;
     MarkedBlock* m_currentBlock;
@@ -75,12 +75,11 @@
     m_onlyContainsStructures = onlyContainsStructures;
 }
 
-inline void* MarkedAllocator::allocate()
+inline void* MarkedAllocator::allocate(size_t bytes)
 {
     MarkedBlock::FreeCell* head = m_freeList.head;
-    // This is a light-weight fast path to cover the most common case.
     if (UNLIKELY(!head))
-        return allocateSlowCase();
+        return allocateSlowCase(bytes);
     
     m_freeList.head = head->next;
     return head;

Modified: trunk/Source/_javascript_Core/heap/MarkedSpace.cpp (128140 => 128141)


--- trunk/Source/_javascript_Core/heap/MarkedSpace.cpp	2012-09-11 01:41:27 UTC (rev 128140)
+++ trunk/Source/_javascript_Core/heap/MarkedSpace.cpp	2012-09-11 03:02:46 UTC (rev 128141)
@@ -90,6 +90,7 @@
         destructorAllocatorFor(cellSize).init(heap, this, cellSize, true, false);
     }
 
+    m_largeAllocator.init(heap, this, 0, true, false);
     m_structureAllocator.init(heap, this, WTF::roundUpToMultipleOf(32, sizeof(Structure)), true, true);
 }
 
@@ -127,6 +128,7 @@
         destructorAllocatorFor(cellSize).reset();
     }
 
+    m_largeAllocator.reset();
     m_structureAllocator.reset();
 }
 
@@ -153,6 +155,7 @@
         destructorAllocatorFor(cellSize).zapFreeList();
     }
 
+    m_largeAllocator.zapFreeList();
     m_structureAllocator.zapFreeList();
 }
 
@@ -168,6 +171,9 @@
             return true;
     }
 
+    if (m_largeAllocator.isPagedOut(deadline))
+        return true;
+
     if (m_structureAllocator.isPagedOut(deadline))
         return true;
 
@@ -178,7 +184,12 @@
 {
     allocatorFor(block).removeBlock(block);
     m_blocks.remove(block);
-    m_heap->blockAllocator().deallocate(MarkedBlock::destroy(block));
+    if (block->capacity() == MarkedBlock::blockSize) {
+        m_heap->blockAllocator().deallocate(MarkedBlock::destroy(block));
+        return;
+    }
+
+    MarkedBlock::destroy(block).deallocate();
 }
 
 void MarkedSpace::freeOrShrinkBlock(MarkedBlock* block)

Modified: trunk/Source/_javascript_Core/heap/MarkedSpace.h (128140 => 128141)


--- trunk/Source/_javascript_Core/heap/MarkedSpace.h	2012-09-11 01:41:27 UTC (rev 128140)
+++ trunk/Source/_javascript_Core/heap/MarkedSpace.h	2012-09-11 03:02:46 UTC (rev 128141)
@@ -80,7 +80,7 @@
     MarkedAllocator& destructorAllocatorFor(size_t);
     void* allocateWithDestructor(size_t);
     void* allocateWithoutDestructor(size_t);
-    void* allocateStructure();
+    void* allocateStructure(size_t);
  
     void resetAllocators();
 
@@ -115,15 +115,15 @@
 
 private:
     friend class LLIntOffsetsExtractor;
-    
-    // [ 32... 256 ]
+
+    // [ 32... 512 ]
     static const size_t preciseStep = MarkedBlock::atomSize;
-    static const size_t preciseCutoff = 256;
+    static const size_t preciseCutoff = 512;
     static const size_t preciseCount = preciseCutoff / preciseStep;
 
-    // [ 512... 2048 ]
-    static const size_t impreciseStep = preciseCutoff;
-    static const size_t impreciseCutoff = maxCellSize;
+    // [ 1024... blockSize ]
+    static const size_t impreciseStep = 2 * preciseCutoff;
+    static const size_t impreciseCutoff = MarkedBlock::blockSize / 2;
     static const size_t impreciseCount = impreciseCutoff / impreciseStep;
 
     struct Subspace {
@@ -133,6 +133,7 @@
 
     Subspace m_destructorSpace;
     Subspace m_normalSpace;
+    MarkedAllocator m_largeAllocator;
     MarkedAllocator m_structureAllocator;
 
     Heap* m_heap;
@@ -162,10 +163,12 @@
 
 inline MarkedAllocator& MarkedSpace::allocatorFor(size_t bytes)
 {
-    ASSERT(bytes && bytes <= maxCellSize);
+    ASSERT(bytes);
     if (bytes <= preciseCutoff)
         return m_normalSpace.preciseAllocators[(bytes - 1) / preciseStep];
-    return m_normalSpace.impreciseAllocators[(bytes - 1) / impreciseStep];
+    if (bytes <= impreciseCutoff)
+        return m_normalSpace.impreciseAllocators[(bytes - 1) / impreciseStep];
+    return m_largeAllocator;
 }
 
 inline MarkedAllocator& MarkedSpace::allocatorFor(MarkedBlock* block)
@@ -181,25 +184,27 @@
 
 inline MarkedAllocator& MarkedSpace::destructorAllocatorFor(size_t bytes)
 {
-    ASSERT(bytes && bytes <= maxCellSize);
+    ASSERT(bytes);
     if (bytes <= preciseCutoff)
         return m_destructorSpace.preciseAllocators[(bytes - 1) / preciseStep];
-    return m_destructorSpace.impreciseAllocators[(bytes - 1) / impreciseStep];
+    if (bytes <= impreciseCutoff)
+        return m_normalSpace.impreciseAllocators[(bytes - 1) / impreciseStep];
+    return m_largeAllocator;
 }
 
 inline void* MarkedSpace::allocateWithoutDestructor(size_t bytes)
 {
-    return allocatorFor(bytes).allocate();
+    return allocatorFor(bytes).allocate(bytes);
 }
 
 inline void* MarkedSpace::allocateWithDestructor(size_t bytes)
 {
-    return destructorAllocatorFor(bytes).allocate();
+    return destructorAllocatorFor(bytes).allocate(bytes);
 }
 
-inline void* MarkedSpace::allocateStructure()
+inline void* MarkedSpace::allocateStructure(size_t bytes)
 {
-    return m_structureAllocator.allocate();
+    return m_structureAllocator.allocate(bytes);
 }
 
 template <typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachBlock(Functor& functor)
@@ -214,6 +219,7 @@
         m_destructorSpace.impreciseAllocators[i].forEachBlock(functor);
     }
 
+    m_largeAllocator.forEachBlock(functor);
     m_structureAllocator.forEachBlock(functor);
 
     return functor.returnValue();

Modified: trunk/Source/_javascript_Core/runtime/Structure.h (128140 => 128141)


--- trunk/Source/_javascript_Core/runtime/Structure.h	2012-09-11 01:41:27 UTC (rev 128140)
+++ trunk/Source/_javascript_Core/runtime/Structure.h	2012-09-11 03:02:46 UTC (rev 128141)
@@ -460,7 +460,7 @@
         ASSERT(!heap.globalData()->isInitializingObject());
         heap.globalData()->setInitializingObjectClass(&Structure::s_info);
 #endif
-        JSCell* result = static_cast<JSCell*>(heap.allocateStructure());
+        JSCell* result = static_cast<JSCell*>(heap.allocateStructure(sizeof(Structure)));
         result->clearStructure();
         return result;
     }
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to