MarkedBlocks that are "full enough" shouldn't be swept after EdenCollections
https://bugs.webkit.org/show_bug.cgi?id=129920

Reviewed by Geoffrey Garen.

This patch introduces the notion of "retiring" MarkedBlocks. We retire a MarkedBlock
when the amount of free space in a MarkedBlock drops below a certain threshold.
Retired blocks are not considered for sweeping.

This is profitable because it reduces churn during sweeping. To build a free list, 
we have to scan through each cell in a block. After a collection, all objects that 
are live in the block will remain live until the next FullCollection, at which time
we un-retire all previously retired blocks. Thus, a small number of objects in a block
that die during each EdenCollection could cause us to do a disproportiante amount of 
sweeping for how much free memory we get back.

This patch looks like a consistent ~2% progression on boyer and is neutral everywhere else.

* heap/Heap.h:
(JSC::Heap::didRetireBlockWithFreeListSize):
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::tryAllocateHelper):
(JSC::MarkedAllocator::removeBlock):
(JSC::MarkedAllocator::reset):
* heap/MarkedAllocator.h:
(JSC::MarkedAllocator::MarkedAllocator):
(JSC::MarkedAllocator::forEachBlock):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::sweepHelper):
(JSC::MarkedBlock::clearMarksWithCollectionType):
(JSC::MarkedBlock::didRetireBlock):
* heap/MarkedBlock.h:
(JSC::MarkedBlock::willRemoveBlock):
(JSC::MarkedBlock::isLive):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::clearNewlyAllocated):
(JSC::MarkedSpace::clearMarks):
* runtime/Options.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@165458 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/heap/MarkedAllocator.cpp b/Source/JavaScriptCore/heap/MarkedAllocator.cpp
index 1ed6add..c4f216b 100644
--- a/Source/JavaScriptCore/heap/MarkedAllocator.cpp
+++ b/Source/JavaScriptCore/heap/MarkedAllocator.cpp
@@ -79,12 +79,12 @@
 
             MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList);
             
-            if (!freeList.head) {
-                block->didConsumeEmptyFreeList();
+            double utilization = ((double)MarkedBlock::blockSize - (double)freeList.bytes) / (double)MarkedBlock::blockSize;
+            if (utilization >= Options::minMarkedBlockUtilization()) {
+                ASSERT(freeList.bytes || !freeList.head);
                 m_blockList.remove(block);
-                m_blockList.push(block);
-                if (!m_lastFullBlock)
-                    m_lastFullBlock = block;
+                m_retiredBlocks.push(block);
+                block->didRetireBlock(freeList);
                 continue;
             }
 
@@ -211,9 +211,7 @@
     if (m_nextBlockToSweep == block)
         m_nextBlockToSweep = m_nextBlockToSweep->next();
 
-    if (block == m_lastFullBlock)
-        m_lastFullBlock = m_lastFullBlock->prev();
-    
+    block->willRemoveBlock();
     m_blockList.remove(block);
 }
 
@@ -223,12 +221,9 @@
     m_currentBlock = 0;
     m_freeList = MarkedBlock::FreeList();
     if (m_heap->operationInProgress() == FullCollection)
-        m_lastFullBlock = 0;
+        m_blockList.append(m_retiredBlocks);
 
-    if (m_lastFullBlock)
-        m_nextBlockToSweep = m_lastFullBlock->next() ? m_lastFullBlock->next() : m_lastFullBlock;
-    else
-        m_nextBlockToSweep = m_blockList.head();
+    m_nextBlockToSweep = m_blockList.head();
 }
 
 } // namespace JSC