Tidy up card walking logic
https://bugs.webkit.org/show_bug.cgi?id=69883

Reviewed by Gavin Barraclough.

Special case common cell sizes when walking a block's
cards.

* heap/CardSet.h:
(JSC::::testAndClear):
* heap/Heap.cpp:
(JSC::GCTimer::GCCounter::GCCounter):
(JSC::GCTimer::GCCounter::count):
(JSC::GCTimer::GCCounter::~GCCounter):
(JSC::Heap::markRoots):
* heap/MarkStack.cpp:
(JSC::MarkStack::reset):
* heap/MarkStack.h:
(JSC::MarkStack::visitCount):
(JSC::MarkStack::MarkStack):
(JSC::MarkStack::append):
* heap/MarkedBlock.h:
(JSC::MarkedBlock::gatherDirtyCellsWithSize):
(JSC::MarkedBlock::gatherDirtyCells):
* runtime/Structure.h:
(JSC::MarkStack::internalAppend):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@97203 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index 94ddbb1..ea63b6e 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -43,9 +43,20 @@
 
 static const size_t largeHeapSize = 16 * 1024 * 1024;
 static const size_t smallHeapSize = 512 * 1024;
-
+#define ENABLE_GC_LOGGING 1
 #if ENABLE(GC_LOGGING)
-    
+#if COMPILER(CLANG)
+#define DEFINE_GC_LOGGING_GLOBAL(type, name, arguments) \
+_Pragma("clang diagnostic push") \
+_Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \
+_Pragma("clang diagnostic ignored \"-Wexit-time-destructors\"") \
+static type name arguments; \
+_Pragma("clang diagnostic pop")
+#else
+#define DEFINE_GC_LOGGING_GLOBAL(type, name, arguments) \
+static type name arguments;
+#endif // COMPILER(CLANG)
+
 struct GCTimer {
     GCTimer(const char* name)
         : m_time(0)
@@ -86,14 +97,45 @@
     double m_start;
 };
 
-#define GCPHASE(name) static GCTimer name##Timer(#name); GCTimerScope name##TimerScope(&name##Timer)
-#define COND_GCPHASE(cond, name1, name2) static GCTimer name1##Timer(#name1); static GCTimer name2##Timer(#name2); GCTimerScope name1##CondTimerScope(cond ? &name1##Timer : &name2##Timer)
+struct GCCounter {
+    GCCounter(const char* name)
+        : m_name(name)
+        , m_count(0)
+        , m_total(0)
+        , m_min(10000000)
+        , m_max(0)
+    {
+    }
+    
+    void count(size_t amount)
+    {
+        m_count++;
+        m_total += amount;
+        if (amount < m_min)
+            m_min = amount;
+        if (amount > m_max)
+            m_max = amount;
+    }
+    ~GCCounter()
+    {
+        printf("%s: %zu values (avg. %zu, min. %zu, max. %zu)\n", m_name, m_total, m_total / m_count, m_min, m_max);
+    }
+    const char* m_name;
+    size_t m_count;
+    size_t m_total;
+    size_t m_min;
+    size_t m_max;
+};
 
+#define GCPHASE(name) DEFINE_GC_LOGGING_GLOBAL(GCTimer, name##Timer, (#name)); GCTimerScope name##TimerScope(&name##Timer)
+#define COND_GCPHASE(cond, name1, name2) DEFINE_GC_LOGGING_GLOBAL(GCTimer, name1##Timer, (#name1)); DEFINE_GC_LOGGING_GLOBAL(GCTimer, name2##Timer, (#name2)); GCTimerScope name1##CondTimerScope(cond ? &name1##Timer : &name2##Timer)
+#define GCCOUNTER(name, value) do { DEFINE_GC_LOGGING_GLOBAL(GCCounter, name##Counter, (#name)); name##Counter.count(value); } while (false)
+    
 #else
 
 #define GCPHASE(name) do { } while (false)
 #define COND_GCPHASE(cond, name1, name2) do { } while (false)
-
+#define GCCOUNTER(name, value) do { } while (false)
 #endif
 
 static size_t heapSizeForHint(HeapSize heapSize)
@@ -548,8 +590,10 @@
     HeapRootVisitor heapRootVisitor(visitor);
 
 #if ENABLE(GGC)
-    if (size_t dirtyCellCount = dirtyCells.size()) {
+    {
+        size_t dirtyCellCount = dirtyCells.size();
         GCPHASE(VisitDirtyCells);
+        GCCOUNTER(DirtyCellCount, dirtyCellCount);
         for (size_t i = 0; i < dirtyCellCount; i++) {
             heapRootVisitor.visitChildren(dirtyCells[i]);
             visitor.drain();
@@ -621,6 +665,7 @@
             // If the set of opaque roots has grown, more weak handles may have become reachable.
         } while (lastOpaqueRootCount != visitor.opaqueRootCount());
     }
+    GCCOUNTER(VisitedValueCount, visitor.visitCount());
     visitor.reset();
 
     m_operationInProgress = NoOperation;