2011-06-08  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Oliver Hunt.

        Factored a bunch of Heap functionality into stand-alone functors
        https://bugs.webkit.org/show_bug.cgi?id=62337
        
        This is in preparation for making these functors operate on arbitrary
        sets of MarkedBlocks.

        * JavaScriptCore.exp: This file is a small tragedy.

        * debugger/Debugger.cpp:
        (JSC::Debugger::recompileAllJSFunctions): Updated for type change and rename.

        * heap/HandleHeap.h:
        (JSC::HandleHeap::forEachStrongHandle): New function for iterating all
        strong handles, so we can play along in the functor game.

        * heap/Heap.cpp:
        (JSC::CountFunctor::CountFunctor::CountFunctor):
        (JSC::CountFunctor::CountFunctor::count):
        (JSC::CountFunctor::CountFunctor::returnValue):
        (JSC::CountFunctor::ClearMarks::operator()):
        (JSC::CountFunctor::ResetAllocator::operator()):
        (JSC::CountFunctor::Sweep::operator()):
        (JSC::CountFunctor::MarkCount::operator()):
        (JSC::CountFunctor::Size::operator()):
        (JSC::CountFunctor::Capacity::operator()):
        (JSC::CountFunctor::Count::operator()):
        (JSC::CountFunctor::CountIfGlobalObject::operator()):
        (JSC::CountFunctor::TakeIfEmpty::TakeIfEmpty):
        (JSC::CountFunctor::TakeIfEmpty::operator()):
        (JSC::CountFunctor::TakeIfEmpty::returnValue):
        (JSC::CountFunctor::RecordType::RecordType):
        (JSC::CountFunctor::RecordType::typeName):
        (JSC::CountFunctor::RecordType::operator()):
        (JSC::CountFunctor::RecordType::returnValue): These functors factor out
        behavior that used to be in the functions below.

        (JSC::Heap::clearMarks):
        (JSC::Heap::sweep):
        (JSC::Heap::objectCount):
        (JSC::Heap::size):
        (JSC::Heap::capacity):
        (JSC::Heap::protectedGlobalObjectCount):
        (JSC::Heap::protectedObjectCount):
        (JSC::Heap::protectedObjectTypeCounts):
        (JSC::Heap::objectTypeCounts):
        (JSC::Heap::resetAllocator):
        (JSC::Heap::freeBlocks):
        (JSC::Heap::shrink): Factored out behavior into the functors above.

        * heap/Heap.h:
        (JSC::Heap::forEachProtectedCell):
        (JSC::Heap::forEachCell):
        (JSC::Heap::forEachBlock): Added forEach* iteration templates. I chose
        functor-based templates instead of plain iterators because they're simpler
        to implement in this case and they require a lot less code at the call site.

        * heap/MarkedBlock.h:
        (JSC::MarkedBlock::VoidFunctor::returnValue): Default parent class for
        trivial functors.

        (JSC::MarkedBlock::forEachCell): Renamed forEach to forEachCell because
        we have a few different kind of "for each" now.

        * runtime/JSGlobalData.cpp:
        (WTF::Recompile::operator()):
        (JSC::JSGlobalData::JSGlobalData):
        (JSC::JSGlobalData::recompileAllJSFunctions): Updated for type change and rename.

        * runtime/JSGlobalData.h: Removed globalObjectCount because it was unused.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@88473 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index f76a188..1546c75 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -36,9 +36,12 @@
 #define COLLECT_ON_EVERY_ALLOCATION 0
 
 using namespace std;
+using namespace JSC;
 
 namespace JSC {
 
+namespace { 
+
 const size_t minBytesPerCycle = 512 * 1024;
 
 static inline bool isValidSharedInstanceThreadState()
@@ -63,6 +66,179 @@
     return true;
 }
 
+class CountFunctor {
+public:
+    typedef size_t ReturnType;
+
+    CountFunctor();
+    void count(size_t);
+    ReturnType returnValue();
+
+private:
+    ReturnType m_count;
+};
+
+inline CountFunctor::CountFunctor()
+    : m_count(0)
+{
+}
+
+inline void CountFunctor::count(size_t count)
+{
+    m_count += count;
+}
+
+inline CountFunctor::ReturnType CountFunctor::returnValue()
+{
+    return m_count;
+}
+
+struct ClearMarks : MarkedBlock::VoidFunctor {
+    void operator()(MarkedBlock*);
+};
+
+inline void ClearMarks::operator()(MarkedBlock* block)
+{
+    block->clearMarks();
+}
+
+struct ResetAllocator : MarkedBlock::VoidFunctor {
+    void operator()(MarkedBlock*);
+};
+
+inline void ResetAllocator::operator()(MarkedBlock* block)
+{
+    block->resetAllocator();
+}
+
+struct Sweep : MarkedBlock::VoidFunctor {
+    void operator()(MarkedBlock*);
+};
+
+inline void Sweep::operator()(MarkedBlock* block)
+{
+    block->sweep();
+}
+
+struct MarkCount : CountFunctor {
+    void operator()(MarkedBlock*);
+};
+
+inline void MarkCount::operator()(MarkedBlock* block)
+{
+    count(block->markCount());
+}
+
+struct Size : CountFunctor {
+    void operator()(MarkedBlock*);
+};
+
+inline void Size::operator()(MarkedBlock* block)
+{
+    count(block->markCount() * block->cellSize());
+}
+
+struct Capacity : CountFunctor {
+    void operator()(MarkedBlock*);
+};
+
+inline void Capacity::operator()(MarkedBlock* block)
+{
+    count(block->capacity());
+}
+
+struct Count : public CountFunctor {
+    void operator()(JSCell*);
+};
+
+inline void Count::operator()(JSCell*)
+{
+    count(1);
+}
+
+struct CountIfGlobalObject : CountFunctor {
+    void operator()(JSCell*);
+};
+
+inline void CountIfGlobalObject::operator()(JSCell* cell)
+{
+    if (!cell->isObject())
+        return;
+    if (!asObject(cell)->isGlobalObject())
+        return;
+    count(1);
+}
+
+class TakeIfEmpty {
+public:
+    typedef MarkedBlock* ReturnType;
+
+    TakeIfEmpty(NewSpace*);
+    void operator()(MarkedBlock*);
+    ReturnType returnValue();
+
+private:
+    NewSpace* m_newSpace;
+    DoublyLinkedList<MarkedBlock> m_empties;
+};
+
+inline TakeIfEmpty::TakeIfEmpty(NewSpace* newSpace)
+    : m_newSpace(newSpace)
+{
+}
+
+inline void TakeIfEmpty::operator()(MarkedBlock* block)
+{
+    if (!block->isEmpty())
+        return;
+
+    m_newSpace->removeBlock(block);
+    m_empties.append(block);
+}
+
+inline TakeIfEmpty::ReturnType TakeIfEmpty::returnValue()
+{
+    return m_empties.head();
+}
+
+class RecordType {
+public:
+    typedef PassOwnPtr<TypeCountSet> ReturnType;
+
+    RecordType();
+    void operator()(JSCell*);
+    ReturnType returnValue();
+
+private:
+    const char* typeName(JSCell*);
+    OwnPtr<TypeCountSet> m_typeCountSet;
+};
+
+inline RecordType::RecordType()
+    : m_typeCountSet(adoptPtr(new TypeCountSet))
+{
+}
+
+inline const char* RecordType::typeName(JSCell* cell)
+{
+    const ClassInfo* info = cell->classInfo();
+    if (!info || !info->className)
+        return "[unknown]";
+    return info->className;
+}
+
+inline void RecordType::operator()(JSCell* cell)
+{
+    m_typeCountSet->add(typeName(cell));
+}
+
+inline PassOwnPtr<TypeCountSet> RecordType::returnValue()
+{
+    return m_typeCountSet.release();
+}
+
+} // anonymous namespace
+
 Heap::Heap(JSGlobalData* globalData)
     : m_operationInProgress(NoOperation)
     , m_newSpace(this)
@@ -282,141 +458,52 @@
 
 void Heap::clearMarks()
 {
-    BlockIterator end = m_blocks.end();
-    for (BlockIterator it = m_blocks.begin(); it != end; ++it)
-        (*it)->clearMarks();
+    forEachBlock<ClearMarks>();
 }
 
 void Heap::sweep()
 {
-    BlockIterator end = m_blocks.end();
-    for (BlockIterator it = m_blocks.begin(); it != end; ++it)
-        (*it)->sweep();
+    forEachBlock<Sweep>();
 }
 
-size_t Heap::objectCount() const
+size_t Heap::objectCount()
 {
-    size_t result = 0;
-    BlockIterator end = m_blocks.end();
-    for (BlockIterator it = m_blocks.begin(); it != end; ++it)
-        result += (*it)->markCount();
-    return result;
+    return forEachBlock<MarkCount>();
 }
 
-size_t Heap::size() const
+size_t Heap::size()
 {
-    size_t result = 0;
-    BlockIterator end = m_blocks.end();
-    for (BlockIterator it = m_blocks.begin(); it != end; ++it)
-        result += (*it)->size();
-    return result;
+    return forEachBlock<Size>();
 }
 
-size_t Heap::capacity() const
+size_t Heap::capacity()
 {
-    size_t result = 0;
-    BlockIterator end = m_blocks.end();
-    for (BlockIterator it = m_blocks.begin(); it != end; ++it)
-        result += (*it)->capacity();
-    return result;
-}
-
-size_t Heap::globalObjectCount()
-{
-    return m_globalData->globalObjectCount;
+    return forEachBlock<Capacity>();
 }
 
 size_t Heap::protectedGlobalObjectCount()
 {
-    size_t count = m_handleHeap.protectedGlobalObjectCount();
+    return forEachProtectedCell<CountIfGlobalObject>();
+}
 
-    ProtectCountSet::iterator end = m_protectedValues.end();
-    for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) {
-        if (it->first->isObject() && asObject(it->first)->isGlobalObject())
-            count++;
-    }
-
-    return count;
+size_t Heap::globalObjectCount()
+{
+    return forEachCell<CountIfGlobalObject>();
 }
 
 size_t Heap::protectedObjectCount()
 {
-    return m_protectedValues.size();
-}
-
-class TypeCounter {
-public:
-    TypeCounter();
-    void operator()(JSCell*);
-    PassOwnPtr<TypeCountSet> take();
-    
-private:
-    const char* typeName(JSCell*);
-    OwnPtr<TypeCountSet> m_typeCountSet;
-    HashSet<JSCell*> m_cells;
-};
-
-inline TypeCounter::TypeCounter()
-    : m_typeCountSet(adoptPtr(new TypeCountSet))
-{
-}
-
-inline const char* TypeCounter::typeName(JSCell* cell)
-{
-    if (cell->isString())
-        return "string";
-    if (cell->isGetterSetter())
-        return "Getter-Setter";
-    if (cell->isAPIValueWrapper())
-        return "API wrapper";
-    if (cell->isPropertyNameIterator())
-        return "For-in iterator";
-    if (const ClassInfo* info = cell->classInfo())
-        return info->className;
-    if (!cell->isObject())
-        return "[empty cell]";
-    return "Object";
-}
-
-inline void TypeCounter::operator()(JSCell* cell)
-{
-    if (!m_cells.add(cell).second)
-        return;
-    m_typeCountSet->add(typeName(cell));
-}
-
-inline PassOwnPtr<TypeCountSet> TypeCounter::take()
-{
-    return m_typeCountSet.release();
+    return forEachProtectedCell<Count>();
 }
 
 PassOwnPtr<TypeCountSet> Heap::protectedObjectTypeCounts()
 {
-    TypeCounter typeCounter;
-
-    ProtectCountSet::iterator end = m_protectedValues.end();
-    for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
-        typeCounter(it->first);
-    m_handleHeap.protectedObjectTypeCounts(typeCounter);
-
-    return typeCounter.take();
-}
-
-void HandleHeap::protectedObjectTypeCounts(TypeCounter& typeCounter)
-{
-    Node* end = m_strongList.end();
-    for (Node* node = m_strongList.begin(); node != end; node = node->next()) {
-        JSValue value = *node->slot();
-        if (value && value.isCell())
-            typeCounter(value.asCell());
-    }
+    return forEachProtectedCell<RecordType>();
 }
 
 PassOwnPtr<TypeCountSet> Heap::objectTypeCounts()
 {
-    TypeCounter typeCounter;
-    forEach(typeCounter);
-    return typeCounter.take();
+    return forEachCell<RecordType>();
 }
 
 void Heap::collectAllGarbage()
@@ -463,13 +550,9 @@
 
 void Heap::resetAllocator()
 {
-    m_newSpace.resetAllocator();
-
-    BlockIterator end = m_blocks.end();
-    for (BlockIterator it = m_blocks.begin(); it != end; ++it)
-        (*it)->resetAllocator();
-
     m_extraCost = 0;
+    m_newSpace.resetAllocator();
+    forEachBlock<ResetAllocator>();
 }
 
 void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback)
@@ -504,10 +587,10 @@
     return block;
 }
 
-void Heap::freeBlocks(DoublyLinkedList<MarkedBlock>& blocks)
+void Heap::freeBlocks(MarkedBlock* head)
 {
     MarkedBlock* next;
-    for (MarkedBlock* block = blocks.head(); block; block = next) {
+    for (MarkedBlock* block = head; block; block = next) {
         next = block->next();
 
         m_blocks.remove(block);
@@ -518,19 +601,8 @@
 void Heap::shrink()
 {
     // We record a temporary list of empties to avoid modifying m_blocks while iterating it.
-    DoublyLinkedList<MarkedBlock> empties;
-
-    BlockIterator end = m_blocks.end();
-    for (BlockIterator it = m_blocks.begin(); it != end; ++it) {
-        MarkedBlock* block = *it;
-        if (!block->isEmpty())
-            continue;
-
-        m_newSpace.removeBlock(block);
-        empties.append(block);
-    }
-    
-    freeBlocks(empties);
+    TakeIfEmpty takeIfEmpty(&m_newSpace);
+    freeBlocks(forEachBlock(takeIfEmpty));
 }
 
 } // namespace JSC