Refactor Heap allocation logic into separate AllocationSpace class
https://bugs.webkit.org/show_bug.cgi?id=68409
Reviewed by Gavin Barraclough.
../../../../Volumes/Data/git/WebKit/OpenSource/Source/JavaScriptCore:
This patch hoists direct manipulation of the MarkedSpace and related
data out of Heap and into a separate class. This will allow us to
have multiple allocation spaces in future, so easing the way towards
having GC'd backing stores for objects.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.exp:
* JavaScriptCore.gypi:
* JavaScriptCore.pro:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* debugger/Debugger.cpp:
(JSC::Debugger::recompileAllJSFunctions):
* heap/AllocationSpace.cpp: Added.
(JSC::AllocationSpace::tryAllocate):
(JSC::AllocationSpace::allocateSlowCase):
(JSC::AllocationSpace::allocateBlock):
(JSC::AllocationSpace::freeBlocks):
(JSC::TakeIfEmpty::TakeIfEmpty):
(JSC::TakeIfEmpty::operator()):
(JSC::TakeIfEmpty::returnValue):
(JSC::AllocationSpace::shrink):
* heap/AllocationSpace.h: Added.
(JSC::AllocationSpace::AllocationSpace):
(JSC::AllocationSpace::blocks):
(JSC::AllocationSpace::sizeClassFor):
(JSC::AllocationSpace::setHighWaterMark):
(JSC::AllocationSpace::highWaterMark):
(JSC::AllocationSpace::canonicalizeBlocks):
(JSC::AllocationSpace::resetAllocator):
(JSC::AllocationSpace::forEachCell):
(JSC::AllocationSpace::forEachBlock):
(JSC::AllocationSpace::allocate):
* heap/Heap.cpp:
(JSC::Heap::Heap):
(JSC::Heap::reportExtraMemoryCostSlowCase):
(JSC::Heap::getConservativeRegisterRoots):
(JSC::Heap::markRoots):
(JSC::Heap::clearMarks):
(JSC::Heap::sweep):
(JSC::Heap::objectCount):
(JSC::Heap::size):
(JSC::Heap::capacity):
(JSC::Heap::globalObjectCount):
(JSC::Heap::objectTypeCounts):
(JSC::Heap::collect):
(JSC::Heap::canonicalizeBlocks):
(JSC::Heap::resetAllocator):
(JSC::Heap::freeBlocks):
(JSC::Heap::shrink):
* heap/Heap.h:
(JSC::Heap::objectSpace):
(JSC::Heap::sizeClassForObject):
(JSC::Heap::allocate):
* jit/JITInlineMethods.h:
(JSC::JIT::emitAllocateBasicJSObject):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::recompileAllJSFunctions):
(JSC::JSGlobalData::releaseExecutableMemory):
../../../../Volumes/Data/git/WebKit/OpenSource/Source/WebCore:
Adding a forwarding header.
* ForwardingHeaders/heap/AllocationSpace.h: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@95559 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index 26e4ef4..9b4ed6a 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -33,7 +33,6 @@
#include "Tracing.h"
#include <algorithm>
-#define COLLECT_ON_EVERY_ALLOCATION 0
using namespace std;
using namespace JSC;
@@ -175,38 +174,6 @@
count(1);
}
-class TakeIfEmpty {
-public:
- typedef MarkedBlock* ReturnType;
-
- TakeIfEmpty(MarkedSpace*);
- void operator()(MarkedBlock*);
- ReturnType returnValue();
-
-private:
- MarkedSpace* m_markedSpace;
- DoublyLinkedList<MarkedBlock> m_empties;
-};
-
-inline TakeIfEmpty::TakeIfEmpty(MarkedSpace* newSpace)
- : m_markedSpace(newSpace)
-{
-}
-
-inline void TakeIfEmpty::operator()(MarkedBlock* block)
-{
- if (!block->isEmpty())
- return;
-
- m_markedSpace->removeBlock(block);
- m_empties.append(block);
-}
-
-inline TakeIfEmpty::ReturnType TakeIfEmpty::returnValue()
-{
- return m_empties.head();
-}
-
class RecordType {
public:
typedef PassOwnPtr<TypeCountSet> ReturnType;
@@ -249,7 +216,7 @@
: m_heapSize(heapSize)
, m_minBytesPerCycle(heapSizeForHint(heapSize))
, m_operationInProgress(NoOperation)
- , m_markedSpace(this)
+ , m_objectSpace(this)
, m_extraCost(0)
, m_markListSet(0)
, m_activityCallback(DefaultGCActivityCallback::create(this))
@@ -259,7 +226,7 @@
, m_isSafeToCollect(false)
, m_globalData(globalData)
{
- m_markedSpace.setHighWaterMark(m_minBytesPerCycle);
+ m_objectSpace.setHighWaterMark(m_minBytesPerCycle);
(*m_activityCallback)();
m_numberOfFreeBlocks = 0;
m_blockFreeingThread = createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree");
@@ -393,62 +360,11 @@
// if a large value survives one garbage collection, there is not much point to
// collecting more frequently as long as it stays alive.
- if (m_extraCost > maxExtraCost && m_extraCost > m_markedSpace.highWaterMark() / 2)
+ if (m_extraCost > maxExtraCost && m_extraCost > m_objectSpace.highWaterMark() / 2)
collectAllGarbage();
m_extraCost += cost;
}
-inline void* Heap::tryAllocate(MarkedSpace::SizeClass& sizeClass)
-{
- m_operationInProgress = Allocation;
- void* result = m_markedSpace.allocate(sizeClass);
- m_operationInProgress = NoOperation;
- return result;
-}
-
-void* Heap::allocateSlowCase(MarkedSpace::SizeClass& sizeClass)
-{
-#if COLLECT_ON_EVERY_ALLOCATION
- collectAllGarbage();
- ASSERT(m_operationInProgress == NoOperation);
-#endif
-
- void* result = tryAllocate(sizeClass);
-
- if (LIKELY(result != 0))
- return result;
-
- AllocationEffort allocationEffort;
-
- if (m_markedSpace.waterMark() < m_markedSpace.highWaterMark() || !m_isSafeToCollect)
- allocationEffort = AllocationMustSucceed;
- else
- allocationEffort = AllocationCanFail;
-
- MarkedBlock* block = allocateBlock(sizeClass.cellSize, allocationEffort);
- if (block) {
- m_markedSpace.addBlock(sizeClass, block);
- void* result = tryAllocate(sizeClass);
- ASSERT(result);
- return result;
- }
-
- collect(DoNotSweep);
-
- result = tryAllocate(sizeClass);
-
- if (result)
- return result;
-
- ASSERT(m_markedSpace.waterMark() < m_markedSpace.highWaterMark());
-
- m_markedSpace.addBlock(sizeClass, allocateBlock(sizeClass.cellSize, AllocationMustSucceed));
-
- result = tryAllocate(sizeClass);
- ASSERT(result);
- return result;
-}
-
void Heap::protect(JSValue k)
{
ASSERT(k);
@@ -521,7 +437,7 @@
if (m_operationInProgress != NoOperation)
CRASH();
m_operationInProgress = Collection;
- ConservativeRoots registerFileRoots(&m_blocks);
+ ConservativeRoots registerFileRoots(&m_objectSpace.blocks());
registerFile().gatherConservativeRoots(registerFileRoots);
size_t registerFileRootCount = registerFileRoots.size();
JSCell** registerRoots = registerFileRoots.roots();
@@ -543,10 +459,10 @@
// We gather conservative roots before clearing mark bits because conservative
// gathering uses the mark bits to determine whether a reference is valid.
- ConservativeRoots machineThreadRoots(&m_blocks);
+ ConservativeRoots machineThreadRoots(&m_objectSpace.blocks());
m_machineThreads.gatherConservativeRoots(machineThreadRoots, &dummy);
- ConservativeRoots registerFileRoots(&m_blocks);
+ ConservativeRoots registerFileRoots(&m_objectSpace.blocks());
registerFile().gatherConservativeRoots(registerFileRoots);
clearMarks();
@@ -599,27 +515,27 @@
void Heap::clearMarks()
{
- forEachBlock<ClearMarks>();
+ m_objectSpace.forEachBlock<ClearMarks>();
}
void Heap::sweep()
{
- forEachBlock<Sweep>();
+ m_objectSpace.forEachBlock<Sweep>();
}
size_t Heap::objectCount()
{
- return forEachBlock<MarkCount>();
+ return m_objectSpace.forEachBlock<MarkCount>();
}
size_t Heap::size()
{
- return forEachBlock<Size>();
+ return m_objectSpace.forEachBlock<Size>();
}
size_t Heap::capacity()
{
- return forEachBlock<Capacity>();
+ return m_objectSpace.forEachBlock<Capacity>();
}
size_t Heap::protectedGlobalObjectCount()
@@ -629,7 +545,7 @@
size_t Heap::globalObjectCount()
{
- return forEachCell<CountIfGlobalObject>();
+ return m_objectSpace.forEachCell<CountIfGlobalObject>();
}
size_t Heap::protectedObjectCount()
@@ -644,7 +560,7 @@
PassOwnPtr<TypeCountSet> Heap::objectTypeCounts()
{
- return forEachCell<RecordType>();
+ return m_objectSpace.forEachCell<RecordType>();
}
void Heap::collectAllGarbage()
@@ -683,7 +599,7 @@
// 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();
- m_markedSpace.setHighWaterMark(max(proportionalBytes, m_minBytesPerCycle));
+ m_objectSpace.setHighWaterMark(max(proportionalBytes, m_minBytesPerCycle));
JAVASCRIPTCORE_GC_END();
(*m_activityCallback)();
@@ -691,13 +607,13 @@
void Heap::canonicalizeBlocks()
{
- m_markedSpace.canonicalizeBlocks();
+ m_objectSpace.canonicalizeBlocks();
}
void Heap::resetAllocator()
{
m_extraCost = 0;
- m_markedSpace.resetAllocator();
+ m_objectSpace.resetAllocator();
}
void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback)
@@ -724,50 +640,14 @@
return true;
}
-MarkedBlock* Heap::allocateBlock(size_t cellSize, Heap::AllocationEffort allocationEffort)
-{
- MarkedBlock* block;
-
- {
- MutexLocker locker(m_freeBlockLock);
- if (m_numberOfFreeBlocks) {
- block = m_freeBlocks.removeHead();
- ASSERT(block);
- m_numberOfFreeBlocks--;
- } else
- block = 0;
- }
- if (block)
- block->initForCellSize(cellSize);
- else if (allocationEffort == AllocationCanFail)
- return 0;
- else
- block = MarkedBlock::create(this, cellSize);
-
- m_blocks.add(block);
-
- return block;
-}
-
void Heap::freeBlocks(MarkedBlock* head)
{
- MarkedBlock* next;
- for (MarkedBlock* block = head; block; block = next) {
- next = block->next();
-
- m_blocks.remove(block);
- block->reset();
- MutexLocker locker(m_freeBlockLock);
- m_freeBlocks.append(block);
- m_numberOfFreeBlocks++;
- }
+ m_objectSpace.freeBlocks(head);
}
void Heap::shrink()
{
- // We record a temporary list of empties to avoid modifying m_blocks while iterating it.
- TakeIfEmpty takeIfEmpty(&m_markedSpace);
- freeBlocks(forEachBlock(takeIfEmpty));
+ m_objectSpace.shrink();
}
void Heap::releaseFreeBlocks()