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