Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (134079 => 134080)
--- trunk/Source/_javascript_Core/ChangeLog 2012-11-09 17:51:38 UTC (rev 134079)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-11-09 17:58:19 UTC (rev 134080)
@@ -1,3 +1,51 @@
+2012-11-08 Mark Hahnenberg <mhahnenb...@apple.com>
+
+ MarkStackArray should use the BlockAllocator instead of the MarkStackSegmentAllocator
+ https://bugs.webkit.org/show_bug.cgi?id=101642
+
+ Reviewed by Filip Pizlo.
+
+ MarkStackSegmentAllocator is like a miniature version of the BlockAllocator. Now that the BlockAllocator has support
+ for a variety of block sizes, we should get rid of the MarkStackSegmentAllocator in favor of the BlockAllocator.
+
+ * heap/BlockAllocator.h: Add new specializations of regionSetFor for the new MarkStackSegments.
+ (JSC):
+ (JSC::MarkStackSegment):
+ * heap/GCThreadSharedData.cpp:
+ (JSC::GCThreadSharedData::GCThreadSharedData):
+ (JSC::GCThreadSharedData::reset):
+ * heap/GCThreadSharedData.h:
+ (GCThreadSharedData):
+ * heap/MarkStack.cpp:
+ (JSC::MarkStackArray::MarkStackArray): We now have a doubly linked list of MarkStackSegments, so we need to refactor
+ all the places that used the old custom tail/previous logic.
+ (JSC::MarkStackArray::~MarkStackArray):
+ (JSC::MarkStackArray::expand):
+ (JSC::MarkStackArray::refill):
+ (JSC::MarkStackArray::donateSomeCellsTo): Refactor to use the new linked list.
+ (JSC::MarkStackArray::stealSomeCellsFrom): Ditto.
+ * heap/MarkStack.h:
+ (JSC):
+ (MarkStackSegment):
+ (JSC::MarkStackSegment::MarkStackSegment):
+ (JSC::MarkStackSegment::sizeFromCapacity):
+ (MarkStackArray):
+ * heap/MarkStackInlines.h:
+ (JSC::MarkStackSegment::create):
+ (JSC):
+ (JSC::MarkStackArray::postIncTop):
+ (JSC::MarkStackArray::preDecTop):
+ (JSC::MarkStackArray::setTopForFullSegment):
+ (JSC::MarkStackArray::setTopForEmptySegment):
+ (JSC::MarkStackArray::top):
+ (JSC::MarkStackArray::validatePrevious):
+ (JSC::MarkStackArray::append):
+ (JSC::MarkStackArray::removeLast):
+ (JSC::MarkStackArray::isEmpty):
+ (JSC::MarkStackArray::size):
+ * heap/SlotVisitor.cpp:
+ (JSC::SlotVisitor::SlotVisitor):
+
2012-11-09 Gabor Ballabas <gab...@inf.u-szeged.hu>
[Qt] r133953 broke the ARM_TRADITIONAL build
Modified: trunk/Source/_javascript_Core/heap/BlockAllocator.cpp (134079 => 134080)
--- trunk/Source/_javascript_Core/heap/BlockAllocator.cpp 2012-11-09 17:51:38 UTC (rev 134079)
+++ trunk/Source/_javascript_Core/heap/BlockAllocator.cpp 2012-11-09 17:58:19 UTC (rev 134080)
@@ -36,7 +36,7 @@
BlockAllocator::BlockAllocator()
: m_copiedRegionSet(CopiedBlock::blockSize)
, m_markedRegionSet(MarkedBlock::blockSize)
- , m_weakRegionSet(WeakBlock::blockSize)
+ , m_weakAndMarkStackRegionSet(WeakBlock::blockSize)
, m_numberOfEmptyRegions(0)
, m_isCurrentlyAllocating(false)
, m_blockFreeingThreadShouldQuit(false)
Modified: trunk/Source/_javascript_Core/heap/BlockAllocator.h (134079 => 134080)
--- trunk/Source/_javascript_Core/heap/BlockAllocator.h 2012-11-09 17:51:38 UTC (rev 134079)
+++ trunk/Source/_javascript_Core/heap/BlockAllocator.h 2012-11-09 17:58:19 UTC (rev 134080)
@@ -37,6 +37,7 @@
class BlockAllocator;
class CopiedBlock;
+class MarkStackSegment;
class MarkedBlock;
class Region;
class WeakBlock;
@@ -185,7 +186,8 @@
RegionSet m_copiedRegionSet;
RegionSet m_markedRegionSet;
- RegionSet m_weakRegionSet;
+ // WeakBlocks and MarkStackSegments use the same RegionSet since they're the same size.
+ RegionSet m_weakAndMarkStackRegionSet;
DoublyLinkedList<Region> m_emptyRegions;
size_t m_numberOfEmptyRegions;
@@ -315,10 +317,16 @@
template <>
inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<WeakBlock>()
{
- return m_weakRegionSet;
+ return m_weakAndMarkStackRegionSet;
}
template <>
+inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<MarkStackSegment>()
+{
+ return m_weakAndMarkStackRegionSet;
+}
+
+template <>
inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<CopiedBlock> >()
{
return m_copiedRegionSet;
@@ -333,9 +341,15 @@
template <>
inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<WeakBlock> >()
{
- return m_weakRegionSet;
+ return m_weakAndMarkStackRegionSet;
}
+template <>
+inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<MarkStackSegment> >()
+{
+ return m_weakAndMarkStackRegionSet;
+}
+
template <typename T>
inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor()
{
Modified: trunk/Source/_javascript_Core/heap/GCThreadSharedData.cpp (134079 => 134080)
--- trunk/Source/_javascript_Core/heap/GCThreadSharedData.cpp 2012-11-09 17:51:38 UTC (rev 134079)
+++ trunk/Source/_javascript_Core/heap/GCThreadSharedData.cpp 2012-11-09 17:58:19 UTC (rev 134080)
@@ -56,7 +56,7 @@
: m_globalData(globalData)
, m_copiedSpace(&globalData->heap.m_storageSpace)
, m_shouldHashConst(false)
- , m_sharedMarkStack(m_segmentAllocator)
+ , m_sharedMarkStack(globalData->heap.blockAllocator())
, m_numberOfActiveParallelMarkers(0)
, m_parallelMarkersShouldExit(false)
, m_blocksToCopy(globalData->heap.m_blockSnapshot)
@@ -110,7 +110,6 @@
ASSERT(m_sharedMarkStack.isEmpty());
#if ENABLE(PARALLEL_GC)
- m_segmentAllocator.shrinkReserve();
m_opaqueRoots.clear();
#else
ASSERT(m_opaqueRoots.isEmpty());
Modified: trunk/Source/_javascript_Core/heap/GCThreadSharedData.h (134079 => 134080)
--- trunk/Source/_javascript_Core/heap/GCThreadSharedData.h 2012-11-09 17:51:38 UTC (rev 134079)
+++ trunk/Source/_javascript_Core/heap/GCThreadSharedData.h 2012-11-09 17:58:19 UTC (rev 134080)
@@ -80,8 +80,6 @@
JSGlobalData* m_globalData;
CopiedSpace* m_copiedSpace;
- MarkStackSegmentAllocator m_segmentAllocator;
-
bool m_shouldHashConst;
Vector<GCThread*> m_gcThreads;
Modified: trunk/Source/_javascript_Core/heap/MarkStack.cpp (134079 => 134080)
--- trunk/Source/_javascript_Core/heap/MarkStack.cpp 2012-11-09 17:51:38 UTC (rev 134079)
+++ trunk/Source/_javascript_Core/heap/MarkStack.cpp 2012-11-09 17:58:19 UTC (rev 134080)
@@ -45,84 +45,35 @@
namespace JSC {
-MarkStackSegmentAllocator::MarkStackSegmentAllocator()
- : m_nextFreeSegment(0)
-{
- m_lock.Init();
-}
-
-MarkStackSegmentAllocator::~MarkStackSegmentAllocator()
-{
- shrinkReserve();
-}
-
-MarkStackSegment* MarkStackSegmentAllocator::allocate()
-{
- {
- SpinLockHolder locker(&m_lock);
- if (m_nextFreeSegment) {
- MarkStackSegment* result = m_nextFreeSegment;
- m_nextFreeSegment = result->m_previous;
- return result;
- }
- }
-
- return static_cast<MarkStackSegment*>(OSAllocator::reserveAndCommit(Options::gcMarkStackSegmentSize()));
-}
-
-void MarkStackSegmentAllocator::release(MarkStackSegment* segment)
-{
- SpinLockHolder locker(&m_lock);
- segment->m_previous = m_nextFreeSegment;
- m_nextFreeSegment = segment;
-}
-
-void MarkStackSegmentAllocator::shrinkReserve()
-{
- MarkStackSegment* segments;
- {
- SpinLockHolder locker(&m_lock);
- segments = m_nextFreeSegment;
- m_nextFreeSegment = 0;
- }
- while (segments) {
- MarkStackSegment* toFree = segments;
- segments = segments->m_previous;
- OSAllocator::decommitAndRelease(toFree, Options::gcMarkStackSegmentSize());
- }
-}
-
-MarkStackArray::MarkStackArray(MarkStackSegmentAllocator& allocator)
- : m_allocator(allocator)
+MarkStackArray::MarkStackArray(BlockAllocator& blockAllocator)
+ : m_blockAllocator(blockAllocator)
, m_segmentCapacity(MarkStackSegment::capacityFromSize(Options::gcMarkStackSegmentSize()))
, m_top(0)
- , m_numberOfPreviousSegments(0)
+ , m_numberOfSegments(0)
{
- m_topSegment = m_allocator.allocate();
-#if !ASSERT_DISABLED
- m_topSegment->m_top = 0;
-#endif
- m_topSegment->m_previous = 0;
+ ASSERT(MarkStackSegment::blockSize == WeakBlock::blockSize);
+ m_segments.push(MarkStackSegment::create(m_blockAllocator.allocate<MarkStackSegment>()));
+ m_numberOfSegments++;
}
MarkStackArray::~MarkStackArray()
{
- ASSERT(!m_topSegment->m_previous);
- m_allocator.release(m_topSegment);
+ ASSERT(m_numberOfSegments == 1 && m_segments.size() == 1);
+ m_blockAllocator.deallocate(MarkStackSegment::destroy(m_segments.removeHead()));
}
void MarkStackArray::expand()
{
- ASSERT(m_topSegment->m_top == m_segmentCapacity);
+ ASSERT(m_segments.head()->m_top == m_segmentCapacity);
- m_numberOfPreviousSegments++;
+ MarkStackSegment* nextSegment = MarkStackSegment::create(m_blockAllocator.allocate<MarkStackSegment>());
+ m_numberOfSegments++;
- MarkStackSegment* nextSegment = m_allocator.allocate();
#if !ASSERT_DISABLED
nextSegment->m_top = 0;
#endif
- nextSegment->m_previous = m_topSegment;
- m_topSegment = nextSegment;
+
+ m_segments.push(nextSegment);
setTopForEmptySegment();
validatePrevious();
}
@@ -132,14 +83,9 @@
validatePrevious();
if (top())
return true;
- MarkStackSegment* toFree = m_topSegment;
- MarkStackSegment* previous = m_topSegment->m_previous;
- if (!previous)
- return false;
- ASSERT(m_numberOfPreviousSegments);
- m_numberOfPreviousSegments--;
- m_topSegment = previous;
- m_allocator.release(toFree);
+ m_blockAllocator.deallocate(MarkStackSegment::destroy(m_segments.removeHead()));
+ ASSERT(m_numberOfSegments > 1);
+ m_numberOfSegments--;
setTopForFullSegment();
validatePrevious();
return true;
@@ -153,7 +99,7 @@
ASSERT(m_segmentCapacity == other.m_segmentCapacity);
- size_t segmentsToDonate = (m_numberOfPreviousSegments + 2 - 1) / 2; // Round up to donate 1 / 1 previous segments.
+ size_t segmentsToDonate = m_numberOfSegments / 2; // If we only have one segment (our head) we don't donate any segments.
if (!segmentsToDonate) {
size_t cellsToDonate = m_top / 2; // Round down to donate 0 / 1 cells.
@@ -167,22 +113,24 @@
validatePrevious();
other.validatePrevious();
- MarkStackSegment* previous = m_topSegment->m_previous;
- while (segmentsToDonate--) {
- ASSERT(previous);
- ASSERT(m_numberOfPreviousSegments);
+ // Remove our head and the head of the other list before we start moving segments around.
+ // We'll add them back on once we're done donating.
+ MarkStackSegment* myHead = m_segments.removeHead();
+ MarkStackSegment* otherHead = other.m_segments.removeHead();
- MarkStackSegment* current = previous;
- previous = current->m_previous;
-
- current->m_previous = other.m_topSegment->m_previous;
- other.m_topSegment->m_previous = current;
-
- m_numberOfPreviousSegments--;
- other.m_numberOfPreviousSegments++;
+ while (segmentsToDonate--) {
+ MarkStackSegment* current = m_segments.removeHead();
+ ASSERT(current);
+ ASSERT(m_numberOfSegments > 1);
+ other.m_segments.push(current);
+ m_numberOfSegments--;
+ other.m_numberOfSegments++;
}
- m_topSegment->m_previous = previous;
+ // Put the original heads back in their places.
+ m_segments.push(myHead);
+ other.m_segments.push(otherHead);
+
validatePrevious();
other.validatePrevious();
}
@@ -198,21 +146,21 @@
other.validatePrevious();
// If other has an entire segment, steal it and return.
- if (other.m_topSegment->m_previous) {
- ASSERT(other.m_topSegment->m_previous->m_top == m_segmentCapacity);
-
- // First remove a segment from other.
- MarkStackSegment* current = other.m_topSegment->m_previous;
- other.m_topSegment->m_previous = current->m_previous;
- other.m_numberOfPreviousSegments--;
-
- ASSERT(!!other.m_numberOfPreviousSegments == !!other.m_topSegment->m_previous);
-
- // Now add it to this.
- current->m_previous = m_topSegment->m_previous;
- m_topSegment->m_previous = current;
- m_numberOfPreviousSegments++;
-
+ if (other.m_numberOfSegments > 1) {
+ // Move the heads of the lists aside. We'll push them back on after.
+ MarkStackSegment* otherHead = other.m_segments.removeHead();
+ MarkStackSegment* myHead = m_segments.removeHead();
+
+ ASSERT(other.m_segments.head()->m_top == m_segmentCapacity);
+
+ m_segments.push(other.m_segments.removeHead());
+
+ m_numberOfSegments++;
+ other.m_numberOfSegments--;
+
+ m_segments.push(myHead);
+ other.m_segments.push(otherHead);
+
validatePrevious();
other.validatePrevious();
return;
Modified: trunk/Source/_javascript_Core/heap/MarkStack.h (134079 => 134080)
--- trunk/Source/_javascript_Core/heap/MarkStack.h 2012-11-09 17:51:38 UTC (rev 134079)
+++ trunk/Source/_javascript_Core/heap/MarkStack.h 2012-11-09 17:58:19 UTC (rev 134080)
@@ -50,19 +50,27 @@
#define MARK_LOG_CHILD(visitor, child) do { } while (false)
#endif
+#include "HeapBlock.h"
#include <wtf/StdLibExtras.h>
-#include <wtf/TCSpinLock.h>
namespace JSC {
+class BlockAllocator;
+class DeadBlock;
class JSCell;
-struct MarkStackSegment {
- MarkStackSegment* m_previous;
+class MarkStackSegment : public HeapBlock<MarkStackSegment> {
+public:
+ MarkStackSegment(Region* region)
+ : HeapBlock<MarkStackSegment>(region)
#if !ASSERT_DISABLED
- size_t m_top;
+ , m_top(0)
#endif
-
+ {
+ }
+
+ static MarkStackSegment* create(DeadBlock*);
+
const JSCell** data()
{
return bitwise_cast<const JSCell**>(this + 1);
@@ -77,26 +85,17 @@
{
return sizeof(MarkStackSegment) + capacity * sizeof(const JSCell*);
}
-};
-class MarkStackSegmentAllocator {
-public:
- MarkStackSegmentAllocator();
- ~MarkStackSegmentAllocator();
-
- MarkStackSegment* allocate();
- void release(MarkStackSegment*);
-
- void shrinkReserve();
-
-private:
- SpinLock m_lock;
- MarkStackSegment* m_nextFreeSegment;
+ static const size_t blockSize = 4 * KB;
+
+#if !ASSERT_DISABLED
+ size_t m_top;
+#endif
};
class MarkStackArray {
public:
- MarkStackArray(MarkStackSegmentAllocator&);
+ MarkStackArray(BlockAllocator&);
~MarkStackArray();
void append(const JSCell*);
@@ -122,12 +121,12 @@
void validatePrevious();
- MarkStackSegment* m_topSegment;
- MarkStackSegmentAllocator& m_allocator;
+ DoublyLinkedList<MarkStackSegment> m_segments;
+ BlockAllocator& m_blockAllocator;
size_t m_segmentCapacity;
size_t m_top;
- size_t m_numberOfPreviousSegments;
+ size_t m_numberOfSegments;
};
Modified: trunk/Source/_javascript_Core/heap/MarkStackInlines.h (134079 => 134080)
--- trunk/Source/_javascript_Core/heap/MarkStackInlines.h 2012-11-09 17:51:38 UTC (rev 134079)
+++ trunk/Source/_javascript_Core/heap/MarkStackInlines.h 2012-11-09 17:58:19 UTC (rev 134080)
@@ -31,35 +31,40 @@
namespace JSC {
+inline MarkStackSegment* MarkStackSegment::create(DeadBlock* block)
+{
+ return new (NotNull, block) MarkStackSegment(block->region());
+}
+
inline size_t MarkStackArray::postIncTop()
{
size_t result = m_top++;
- ASSERT(result == m_topSegment->m_top++);
+ ASSERT(result == m_segments.head()->m_top++);
return result;
}
inline size_t MarkStackArray::preDecTop()
{
size_t result = --m_top;
- ASSERT(result == --m_topSegment->m_top);
+ ASSERT(result == --m_segments.head()->m_top);
return result;
}
inline void MarkStackArray::setTopForFullSegment()
{
- ASSERT(m_topSegment->m_top == m_segmentCapacity);
+ ASSERT(m_segments.head()->m_top == m_segmentCapacity);
m_top = m_segmentCapacity;
}
inline void MarkStackArray::setTopForEmptySegment()
{
- ASSERT(!m_topSegment->m_top);
+ ASSERT(!m_segments.head()->m_top);
m_top = 0;
}
inline size_t MarkStackArray::top()
{
- ASSERT(m_top == m_topSegment->m_top);
+ ASSERT(m_top == m_segments.head()->m_top);
return m_top;
}
@@ -69,9 +74,9 @@
inline void MarkStackArray::validatePrevious()
{
unsigned count = 0;
- for (MarkStackSegment* current = m_topSegment->m_previous; current; current = current->m_previous)
+ for (MarkStackSegment* current = m_segments.head(); current; current = current->next())
count++;
- ASSERT(count == m_numberOfPreviousSegments);
+ ASSERT(m_segments.size() == m_numberOfSegments);
}
#endif
@@ -79,7 +84,7 @@
{
if (m_top == m_segmentCapacity)
expand();
- m_topSegment->data()[postIncTop()] = cell;
+ m_segments.head()->data()[postIncTop()] = cell;
}
inline bool MarkStackArray::canRemoveLast()
@@ -89,15 +94,15 @@
inline const JSCell* MarkStackArray::removeLast()
{
- return m_topSegment->data()[preDecTop()];
+ return m_segments.head()->data()[preDecTop()];
}
inline bool MarkStackArray::isEmpty()
{
if (m_top)
return false;
- if (m_topSegment->m_previous) {
- ASSERT(m_topSegment->m_previous->m_top == m_segmentCapacity);
+ if (m_segments.head()->next()) {
+ ASSERT(m_segments.head()->next()->m_top == m_segmentCapacity);
return false;
}
return true;
@@ -105,7 +110,7 @@
inline size_t MarkStackArray::size()
{
- return m_top + m_segmentCapacity * m_numberOfPreviousSegments;
+ return m_top + m_segmentCapacity * (m_numberOfSegments - 1);
}
} // namespace JSC
Modified: trunk/Source/_javascript_Core/heap/SlotVisitor.cpp (134079 => 134080)
--- trunk/Source/_javascript_Core/heap/SlotVisitor.cpp 2012-11-09 17:51:38 UTC (rev 134079)
+++ trunk/Source/_javascript_Core/heap/SlotVisitor.cpp 2012-11-09 17:58:19 UTC (rev 134080)
@@ -15,7 +15,7 @@
namespace JSC {
SlotVisitor::SlotVisitor(GCThreadSharedData& shared)
- : m_stack(shared.m_segmentAllocator)
+ : m_stack(shared.m_globalData->heap.blockAllocator())
, m_visitCount(0)
, m_isInParallelMode(false)
, m_shared(shared)