2011-09-30  Oliver Hunt  <oliver@apple.com>

        Need a sensible GGC policy

        Reviewed by Geoff Garen.

        This replaces the existing random collection policy
        with a deterministic policy based on nursery size.

        * heap/AllocationSpace.cpp:
        (JSC::AllocationSpace::allocateSlowCase):
        * heap/Heap.cpp:
        (JSC::Heap::Heap):
        (JSC::Heap::markRoots):
        (JSC::Heap::collect):
        * heap/Heap.h:
        * heap/MarkedSpace.cpp:
        (JSC::MarkedSpace::MarkedSpace):
        (JSC::MarkedSpace::resetAllocator):
        * heap/MarkedSpace.h:
        (JSC::MarkedSpace::nurseryWaterMark):
        (JSC::MarkedSpace::allocate):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@96432 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 50ea45c..1c4ea63 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,26 @@
+2011-09-30  Oliver Hunt  <oliver@apple.com>
+
+        Need a sensible GGC policy
+
+        Reviewed by Geoff Garen.
+
+        This replaces the existing random collection policy
+        with a deterministic policy based on nursery size.
+
+        * heap/AllocationSpace.cpp:
+        (JSC::AllocationSpace::allocateSlowCase):
+        * heap/Heap.cpp:
+        (JSC::Heap::Heap):
+        (JSC::Heap::markRoots):
+        (JSC::Heap::collect):
+        * heap/Heap.h:
+        * heap/MarkedSpace.cpp:
+        (JSC::MarkedSpace::MarkedSpace):
+        (JSC::MarkedSpace::resetAllocator):
+        * heap/MarkedSpace.h:
+        (JSC::MarkedSpace::nurseryWaterMark):
+        (JSC::MarkedSpace::allocate):
+
 2011-09-30  Filip Pizlo  <fpizlo@apple.com>
 
         DFG 32-bit support for op_call and op_construct causes
diff --git a/Source/JavaScriptCore/heap/AllocationSpace.cpp b/Source/JavaScriptCore/heap/AllocationSpace.cpp
index 5a1509c..1725de5 100644
--- a/Source/JavaScriptCore/heap/AllocationSpace.cpp
+++ b/Source/JavaScriptCore/heap/AllocationSpace.cpp
@@ -55,7 +55,13 @@
     
     AllocationEffort allocationEffort;
     
-    if (m_markedSpace.waterMark() < m_markedSpace.highWaterMark() || !m_heap->m_isSafeToCollect)
+    if ((
+#if ENABLE(GGC)
+         m_markedSpace.nurseryWaterMark() < m_heap->m_minBytesPerCycle
+#else
+         m_markedSpace.waterMark() < m_markedSpace.highWaterMark()
+#endif
+         ) || !m_heap->m_isSafeToCollect)
         allocationEffort = AllocationMustSucceed;
     else
         allocationEffort = AllocationCanFail;
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index 37cf164..88f2585 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -214,6 +214,7 @@
 Heap::Heap(JSGlobalData* globalData, HeapSize heapSize)
     : m_heapSize(heapSize)
     , m_minBytesPerCycle(heapSizeForHint(heapSize))
+    , m_lastFullGCSize(0)
     , m_operationInProgress(NoOperation)
     , m_objectSpace(this)
     , m_extraCost(0)
@@ -453,8 +454,9 @@
     m_operationInProgress = NoOperation;
 }
 
-void Heap::markRoots()
+void Heap::markRoots(bool fullGC)
 {
+    UNUSED_PARAM(fullGC);
     ASSERT(isValidThreadState(m_globalData));
     if (m_operationInProgress != NoOperation)
         CRASH();
@@ -473,9 +475,7 @@
     m_jettisonedCodeBlocks.deleteUnmarkedCodeBlocks();
 #if ENABLE(GGC)
     MarkedBlock::DirtyCellVector dirtyCells;
-    // Until we have a sensible policy we just random choose to perform
-    // young generation collections 90% of the time.
-    if (WTF::randomNumber() > 0.1)
+    if (!fullGC)
         m_objectSpace.gatherDirtyCells(dirtyCells);
     else
 #endif
@@ -486,7 +486,8 @@
     HeapRootVisitor heapRootVisitor(visitor);
 
 #if ENABLE(GGC)
-    for (size_t i = 0; i < dirtyObjectCount; i++) {
+    size_t dirtyCellCount = dirtyCells.size();
+    for (size_t i = 0; i < dirtyCellCount; i++) {
         heapRootVisitor.visitChildren(dirtyCells[i]);
         visitor.drain();
     }
@@ -599,9 +600,12 @@
     ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
     ASSERT(m_isSafeToCollect);
     JAVASCRIPTCORE_GC_BEGIN();
-    
+    bool fullGC = sweepToggle == DoSweep;
+    if (!fullGC)
+        fullGC = (capacity() > 4 * m_lastFullGCSize);  
     canonicalizeCellLivenessData();
-    markRoots();
+
+    markRoots(fullGC);
 
     harvestWeakReferences();
     m_handleHeap.finalizeWeakHandles();
@@ -621,6 +625,9 @@
     // proportion is a bit arbitrary. A 2X multiplier gives a 1:1 (heap size :
     // new bytes allocated) proportion, and seems to work well in benchmarks.
     size_t proportionalBytes = 2 * size();
+    if (fullGC)
+        m_lastFullGCSize = proportionalBytes / 2;
+    
     m_objectSpace.setHighWaterMark(max(proportionalBytes, m_minBytesPerCycle));
     JAVASCRIPTCORE_GC_END();
 
diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h
index 2d93bcd..b5c6106 100644
--- a/Source/JavaScriptCore/heap/Heap.h
+++ b/Source/JavaScriptCore/heap/Heap.h
@@ -144,7 +144,7 @@
         void freeBlocks(MarkedBlock*);
 
         void clearMarks();
-        void markRoots();
+        void markRoots(bool fullGC);
         void markProtectedObjects(HeapRootVisitor&);
         void markTempSortVectors(HeapRootVisitor&);
         void harvestWeakReferences();
@@ -164,6 +164,7 @@
 
         const HeapSize m_heapSize;
         const size_t m_minBytesPerCycle;
+        size_t m_lastFullGCSize;
         
         OperationInProgress m_operationInProgress;
         AllocationSpace m_objectSpace;
diff --git a/Source/JavaScriptCore/heap/MarkedSpace.cpp b/Source/JavaScriptCore/heap/MarkedSpace.cpp
index 04cb937..acbd8ac 100644
--- a/Source/JavaScriptCore/heap/MarkedSpace.cpp
+++ b/Source/JavaScriptCore/heap/MarkedSpace.cpp
@@ -32,6 +32,7 @@
 
 MarkedSpace::MarkedSpace(Heap* heap)
     : m_waterMark(0)
+    , m_nurseryWaterMark(0)
     , m_highWaterMark(0)
     , m_heap(heap)
 {
@@ -63,6 +64,7 @@
 void MarkedSpace::resetAllocator()
 {
     m_waterMark = 0;
+    m_nurseryWaterMark = 0;
 
     for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep)
         sizeClassFor(cellSize).resetAllocator();
diff --git a/Source/JavaScriptCore/heap/MarkedSpace.h b/Source/JavaScriptCore/heap/MarkedSpace.h
index 1a4d919..751fe2f 100644
--- a/Source/JavaScriptCore/heap/MarkedSpace.h
+++ b/Source/JavaScriptCore/heap/MarkedSpace.h
@@ -72,6 +72,7 @@
 
     size_t waterMark();
     size_t highWaterMark();
+    size_t nurseryWaterMark();
     void setHighWaterMark(size_t);
 
     template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&); // Safe to remove the current item while iterating.
@@ -91,6 +92,7 @@
     FixedArray<SizeClass, preciseCount> m_preciseSizeClasses;
     FixedArray<SizeClass, impreciseCount> m_impreciseSizeClasses;
     size_t m_waterMark;
+    size_t m_nurseryWaterMark;
     size_t m_highWaterMark;
     Heap* m_heap;
 };
@@ -105,6 +107,11 @@
     return m_highWaterMark;
 }
 
+inline size_t MarkedSpace::nurseryWaterMark()
+{
+    return m_nurseryWaterMark;
+}
+
 inline void MarkedSpace::setHighWaterMark(size_t highWaterMark)
 {
     m_highWaterMark = highWaterMark;
@@ -126,7 +133,7 @@
             firstFreeCell = block->sweep(MarkedBlock::SweepToFreeList);
             if (firstFreeCell)
                 break;
-
+            m_nurseryWaterMark += block->capacity() - block->size();
             m_waterMark += block->capacity();
             block->didConsumeFreeList();
         }