Commit 8a23d6ad authored by ggaren@apple.com's avatar ggaren@apple.com

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
parent 55834f46
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.
2011-06-08 Mikołaj Małecki <m.malecki@samsung.com>
Reviewed by Pavel Feldman.
......
......@@ -221,6 +221,7 @@ __ZN3JSC25evaluateInGlobalCallFrameERKNS_7UStringERNS_7JSValueEPNS_14JSGlobalObj
__ZN3JSC35createInterruptedExecutionExceptionEPNS_12JSGlobalDataE
__ZN3JSC3NaNE
__ZN3JSC41constructFunctionSkippingEvalEnabledCheckEPNS_9ExecStateEPNS_14JSGlobalObjectERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi
__ZN3JSC4Heap11objectCountEv
__ZN3JSC4Heap16activityCallbackEv
__ZN3JSC4Heap16objectTypeCountsEv
__ZN3JSC4Heap17collectAllGarbageEv
......@@ -231,9 +232,11 @@ __ZN3JSC4Heap20protectedObjectCountEv
__ZN3JSC4Heap25protectedObjectTypeCountsEv
__ZN3JSC4Heap26protectedGlobalObjectCountEv
__ZN3JSC4Heap29reportExtraMemoryCostSlowCaseEm
__ZN3JSC4Heap4sizeEv
__ZN3JSC4Heap7destroyEv
__ZN3JSC4Heap7protectENS_7JSValueE
__ZN3JSC4Heap8allocateERNS_8NewSpace9SizeClassE
__ZN3JSC4Heap8capacityEv
__ZN3JSC4Heap9unprotectENS_7JSValueE
__ZN3JSC4Yarr11YarrPatternC1ERKNS_7UStringEbbPPKc
__ZN3JSC4Yarr11byteCompileERNS0_11YarrPatternEPN3WTF20BumpPointerAllocatorE
......@@ -535,9 +538,6 @@ __ZNK3JSC18PropertyDescriptor6getterEv
__ZNK3JSC18PropertyDescriptor6setterEv
__ZNK3JSC18PropertyDescriptor8writableEv
__ZNK3JSC19SourceProviderCache8byteSizeEv
__ZNK3JSC4Heap11objectCountEv
__ZNK3JSC4Heap4sizeEv
__ZNK3JSC4Heap8capacityEv
__ZNK3JSC6JSCell11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
__ZNK3JSC6JSCell12toThisObjectEPNS_9ExecStateE
__ZNK3JSC6JSCell14isGetterSetterEv
......
......@@ -76,7 +76,7 @@ EXPORTS
?callOnMainThread@WTF@@YAXP6AXPAX@Z0@Z
?callOnMainThreadAndWait@WTF@@YAXP6AXPAX@Z0@Z
?cancelCallOnMainThread@WTF@@YAXP6AXPAX@Z0@Z
?capacity@Heap@JSC@@QBEIXZ
?capacity@Heap@JSC@@QAEIXZ
?changePrototypeTransition@Structure@JSC@@SAPAV12@AAVJSGlobalData@2@PAV12@VJSValue@2@@Z
?checkCurrentIdentifierTable@Identifier@JSC@@CAXPAVExecState@2@@Z
?checkCurrentIdentifierTable@Identifier@JSC@@CAXPAVJSGlobalData@2@@Z
......@@ -253,7 +253,7 @@ EXPORTS
?number@UString@JSC@@SA?AV12@I@Z
?number@UString@JSC@@SA?AV12@N@Z
?numberToString@WTF@@YAINQA_W@Z
?objectCount@Heap@JSC@@QBEIXZ
?objectCount@Heap@JSC@@QAEIXZ
?objectProtoFuncToString@JSC@@YI_JPAVExecState@1@@Z
?parseDateFromNullTerminatedCharacters@WTF@@YANPBD@Z
?preventExtensions@JSObject@JSC@@UAEXAAVJSGlobalData@2@@Z
......@@ -312,7 +312,7 @@ EXPORTS
?setter@PropertyDescriptor@JSC@@QBE?AVJSValue@2@XZ
?shrinkToFit@StringBuilder@WTF@@QAEXXZ
?signal@ThreadCondition@WTF@@QAEXXZ
?size@Heap@JSC@@QBEIXZ
?size@Heap@JSC@@QAEIXZ
?slowAppend@MarkedArgumentBuffer@JSC@@AAEXVJSValue@2@@Z
?slowValidateCell@JSC@@YAXPAVJSCell@1@@Z
?slowValidateCell@JSC@@YAXPAVJSGlobalObject@1@@Z
......
......@@ -33,7 +33,7 @@ namespace {
using namespace JSC;
class Recompiler {
class Recompiler : public MarkedBlock::VoidFunctor {
public:
Recompiler(Debugger*);
~Recompiler();
......@@ -118,7 +118,7 @@ void Debugger::recompileAllJSFunctions(JSGlobalData* globalData)
return;
Recompiler recompiler(this);
globalData->heap.forEach(recompiler);
globalData->heap.forEachCell(recompiler);
}
JSValue evaluateInGlobalCallFrame(const UString& script, JSValue& exception, JSGlobalObject* globalObject)
......
......@@ -28,6 +28,7 @@
#include "BlockStack.h"
#include "Handle.h"
#include "HashCountedSet.h"
#include "SentinelLinkedList.h"
#include "SinglyLinkedList.h"
......@@ -38,7 +39,6 @@ class HeapRootVisitor;
class JSGlobalData;
class JSValue;
class MarkStack;
class TypeCounter;
typedef MarkStack SlotVisitor;
class WeakHandleOwner {
......@@ -74,7 +74,8 @@ public:
#endif
unsigned protectedGlobalObjectCount();
void protectedObjectTypeCounts(TypeCounter&);
template<typename Functor> void forEachStrongHandle(Functor&, const HashCountedSet<JSCell*>& skipSet);
private:
class Node {
......@@ -278,6 +279,19 @@ inline WeakHandleOwner* HandleHeap::Node::emptyWeakOwner()
return reinterpret_cast<WeakHandleOwner*>(-1);
}
template<typename Functor> void HandleHeap::forEachStrongHandle(Functor& functor, const HashCountedSet<JSCell*>& skipSet)
{
Node* end = m_strongList.end();
for (Node* node = m_strongList.begin(); node != end; node = node->next()) {
JSValue value = *node->slot();
if (!value || !value.isCell())
continue;
if (skipSet.contains(value.asCell()))
continue;
functor(value.asCell());
}
}
}
#endif
......@@ -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 @@ static inline bool isValidThreadState(JSGlobalData* globalData)
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::markRoots()
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();
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::protectedObjectCount()
{
return m_protectedValues.size();
return forEachProtectedCell<CountIfGlobalObject>();
}
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)
size_t Heap::globalObjectCount()
{
if (!m_cells.add(cell).second)
return;
m_typeCountSet->add(typeName(cell));
return forEachCell<CountIfGlobalObject>();
}
inline PassOwnPtr<TypeCountSet> TypeCounter::take()
size_t Heap::protectedObjectCount()
{
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::collect(SweepToggle sweepToggle)
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 @@ MarkedBlock* Heap::allocateBlock(size_t cellSize)
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::freeBlocks(DoublyLinkedList<MarkedBlock>& blocks)
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
......@@ -91,9 +91,9 @@ namespace JSC {
bool contains(const void*);
size_t size() const;
size_t capacity() const;
size_t objectCount() const;
size_t size();
size_t capacity();
size_t objectCount();
size_t globalObjectCount();
size_t protectedObjectCount();
size_t protectedGlobalObjectCount();
......@@ -105,7 +105,12 @@ namespace JSC {
HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; }
template <typename Functor> void forEach(Functor&);
template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&);
template<typename Functor> typename Functor::ReturnType forEachProtectedCell();
template<typename Functor> typename Functor::ReturnType forEachCell(Functor&);
template<typename Functor> typename Functor::ReturnType forEachCell();
template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&);
template<typename Functor> typename Functor::ReturnType forEachBlock();
HandleSlot allocateGlobalHandle() { return m_handleHeap.allocate(); }
HandleSlot allocateLocalHandle() { return m_handleStack.push(); }
......@@ -124,7 +129,7 @@ namespace JSC {
void resetAllocator();
MarkedBlock* allocateBlock(size_t cellSize);
void freeBlocks(DoublyLinkedList<MarkedBlock>&);
void freeBlocks(MarkedBlock*);
void clearMarks();
void markRoots();
......@@ -221,11 +226,48 @@ namespace JSC {
reportExtraMemoryCostSlowCase(cost);
}
template <typename Functor> inline void Heap::forEach(Functor& functor)
template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
{
ProtectCountSet::iterator end = m_protectedValues.end();
for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)