Commit a57e6716 authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com
Browse files

Combine MarkStack and SlotVisitor into single class

https://bugs.webkit.org/show_bug.cgi?id=96043

Reviewed by Geoff Garen.

Move all of MarkStack into SlotVisitor. The remaining stuff in MarkStack.cpp actually has to do 
with MarkStack management/allocation. Cleaned up a few of the header files while I was at it.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CodeBlock.cpp:
* dfg/DFGCommon.h:
* heap/GCThreadSharedData.cpp:
* heap/GCThreadSharedData.h:
(GCThreadSharedData):
* heap/HeapRootVisitor.h:
* heap/MarkStack.cpp:
(JSC):
* heap/MarkStack.h:
(JSC):
(MarkStackSegment):
(JSC::MarkStackSegment::data):
(JSC::MarkStackSegment::capacityFromSize):
(JSC::MarkStackSegment::sizeFromCapacity):
(MarkStackSegmentAllocator):
(MarkStackArray):
* heap/MarkStackInlineMethods.h:
(JSC::MarkStackArray::postIncTop):
(JSC):
(JSC::MarkStackArray::preDecTop):
(JSC::MarkStackArray::setTopForFullSegment):
(JSC::MarkStackArray::setTopForEmptySegment):
(JSC::MarkStackArray::top):
(JSC::MarkStackArray::validatePrevious):
(JSC::MarkStackArray::append):
(JSC::MarkStackArray::canRemoveLast):
(JSC::MarkStackArray::removeLast):
(JSC::MarkStackArray::isEmpty):
(JSC::MarkStackArray::size):
* heap/SlotVisitor.cpp: Added.
(JSC):
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::~SlotVisitor):
(JSC::SlotVisitor::setup):
(JSC::SlotVisitor::reset):
(JSC::SlotVisitor::append):
(JSC::visitChildren):
(JSC::SlotVisitor::donateKnownParallel):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::mergeOpaqueRoots):
(JSC::SlotVisitor::startCopying):
(JSC::SlotVisitor::allocateNewSpaceSlow):
(JSC::SlotVisitor::allocateNewSpaceOrPin):
(JSC::JSString::tryHashConstLock):
(JSC::JSString::releaseHashConstLock):
(JSC::JSString::shouldTryHashConst):
(JSC::SlotVisitor::internalAppend):
(JSC::SlotVisitor::copyAndAppend):
(JSC::SlotVisitor::doneCopying):
(JSC::SlotVisitor::harvestWeakReferences):
(JSC::SlotVisitor::finalizeUnconditionalFinalizers):
(JSC::SlotVisitor::validate):
* heap/SlotVisitor.h:
(JSC):
(SlotVisitor):
(JSC::SlotVisitor::sharedData):
(JSC::SlotVisitor::isEmpty):
(JSC::SlotVisitor::visitCount):
(JSC::SlotVisitor::resetChildCount):
(JSC::SlotVisitor::childCount):
(JSC::SlotVisitor::incrementChildCount):
(ParallelModeEnabler):
(JSC::ParallelModeEnabler::ParallelModeEnabler):
(JSC::ParallelModeEnabler::~ParallelModeEnabler):
* heap/SlotVisitorInlineMethods.h:
(JSC::SlotVisitor::append):
(JSC):
(JSC::SlotVisitor::appendUnbarrieredPointer):
(JSC::SlotVisitor::appendUnbarrieredValue):
(JSC::SlotVisitor::internalAppend):
(JSC::SlotVisitor::addWeakReferenceHarvester):
(JSC::SlotVisitor::addUnconditionalFinalizer):
(JSC::SlotVisitor::addOpaqueRoot):
(JSC::SlotVisitor::containsOpaqueRoot):
(JSC::SlotVisitor::opaqueRootCount):
(JSC::SlotVisitor::mergeOpaqueRootsIfNecessary):
(JSC::SlotVisitor::mergeOpaqueRootsIfProfitable):
(JSC::SlotVisitor::donate):
(JSC::SlotVisitor::donateAndDrain):
* jit/JITWriteBarrier.h:
(JSC::SlotVisitor::append):
* jit/JumpReplacementWatchpoint.cpp:
* runtime/JSCell.h:
* runtime/Structure.h:
(JSC::SlotVisitor::internalAppend):
* runtime/WriteBarrier.h:
(JSC):
(JSC::SlotVisitor::append):
(JSC::SlotVisitor::appendValues):
* yarr/YarrJIT.cpp:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@128084 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent b9f9658c
......@@ -119,6 +119,7 @@ SET(JavaScriptCore_SOURCES
heap/MarkedBlock.cpp
heap/MarkedSpace.cpp
heap/MarkStack.cpp
heap/SlotVisitor.cpp
heap/WeakSet.cpp
heap/WeakHandleOwner.cpp
heap/WeakBlock.cpp
......
2012-09-06 Mark Hahnenberg <mhahnenberg@apple.com>
Combine MarkStack and SlotVisitor into single class
https://bugs.webkit.org/show_bug.cgi?id=96043
Reviewed by Geoff Garen.
Move all of MarkStack into SlotVisitor. The remaining stuff in MarkStack.cpp actually has to do
with MarkStack management/allocation. Cleaned up a few of the header files while I was at it.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CodeBlock.cpp:
* dfg/DFGCommon.h:
* heap/GCThreadSharedData.cpp:
* heap/GCThreadSharedData.h:
(GCThreadSharedData):
* heap/HeapRootVisitor.h:
* heap/MarkStack.cpp:
(JSC):
* heap/MarkStack.h:
(JSC):
(MarkStackSegment):
(JSC::MarkStackSegment::data):
(JSC::MarkStackSegment::capacityFromSize):
(JSC::MarkStackSegment::sizeFromCapacity):
(MarkStackSegmentAllocator):
(MarkStackArray):
* heap/MarkStackInlineMethods.h:
(JSC::MarkStackArray::postIncTop):
(JSC):
(JSC::MarkStackArray::preDecTop):
(JSC::MarkStackArray::setTopForFullSegment):
(JSC::MarkStackArray::setTopForEmptySegment):
(JSC::MarkStackArray::top):
(JSC::MarkStackArray::validatePrevious):
(JSC::MarkStackArray::append):
(JSC::MarkStackArray::canRemoveLast):
(JSC::MarkStackArray::removeLast):
(JSC::MarkStackArray::isEmpty):
(JSC::MarkStackArray::size):
* heap/SlotVisitor.cpp: Added.
(JSC):
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::~SlotVisitor):
(JSC::SlotVisitor::setup):
(JSC::SlotVisitor::reset):
(JSC::SlotVisitor::append):
(JSC::visitChildren):
(JSC::SlotVisitor::donateKnownParallel):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::mergeOpaqueRoots):
(JSC::SlotVisitor::startCopying):
(JSC::SlotVisitor::allocateNewSpaceSlow):
(JSC::SlotVisitor::allocateNewSpaceOrPin):
(JSC::JSString::tryHashConstLock):
(JSC::JSString::releaseHashConstLock):
(JSC::JSString::shouldTryHashConst):
(JSC::SlotVisitor::internalAppend):
(JSC::SlotVisitor::copyAndAppend):
(JSC::SlotVisitor::doneCopying):
(JSC::SlotVisitor::harvestWeakReferences):
(JSC::SlotVisitor::finalizeUnconditionalFinalizers):
(JSC::SlotVisitor::validate):
* heap/SlotVisitor.h:
(JSC):
(SlotVisitor):
(JSC::SlotVisitor::sharedData):
(JSC::SlotVisitor::isEmpty):
(JSC::SlotVisitor::visitCount):
(JSC::SlotVisitor::resetChildCount):
(JSC::SlotVisitor::childCount):
(JSC::SlotVisitor::incrementChildCount):
(ParallelModeEnabler):
(JSC::ParallelModeEnabler::ParallelModeEnabler):
(JSC::ParallelModeEnabler::~ParallelModeEnabler):
* heap/SlotVisitorInlineMethods.h:
(JSC::SlotVisitor::append):
(JSC):
(JSC::SlotVisitor::appendUnbarrieredPointer):
(JSC::SlotVisitor::appendUnbarrieredValue):
(JSC::SlotVisitor::internalAppend):
(JSC::SlotVisitor::addWeakReferenceHarvester):
(JSC::SlotVisitor::addUnconditionalFinalizer):
(JSC::SlotVisitor::addOpaqueRoot):
(JSC::SlotVisitor::containsOpaqueRoot):
(JSC::SlotVisitor::opaqueRootCount):
(JSC::SlotVisitor::mergeOpaqueRootsIfNecessary):
(JSC::SlotVisitor::mergeOpaqueRootsIfProfitable):
(JSC::SlotVisitor::donate):
(JSC::SlotVisitor::donateAndDrain):
* jit/JITWriteBarrier.h:
(JSC::SlotVisitor::append):
* jit/JumpReplacementWatchpoint.cpp:
* runtime/JSCell.h:
* runtime/Structure.h:
(JSC::SlotVisitor::internalAppend):
* runtime/WriteBarrier.h:
(JSC):
(JSC::SlotVisitor::append):
(JSC::SlotVisitor::appendValues):
* yarr/YarrJIT.cpp:
2012-09-10 Hojong Han <hojong.han@samsung.com>
 
[EFL] JIT memory usage is not retrieved
......
......@@ -266,6 +266,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/HeapTimer.cpp \
Source/JavaScriptCore/heap/IncrementalSweeper.h \
Source/JavaScriptCore/heap/IncrementalSweeper.cpp \
Source/JavaScriptCore/heap/SlotVisitor.cpp \
Source/JavaScriptCore/heap/SlotVisitor.h \
Source/JavaScriptCore/heap/SlotVisitorInlineMethods.h \
Source/JavaScriptCore/heap/HandleStack.cpp \
......
......@@ -365,7 +365,7 @@ EXPORTS
?unlock@Mutex@WTF@@QAEXXZ
?unlockAtomicallyInitializedStaticMutex@WTF@@YAXXZ
?unprotect@Heap@JSC@@QAE_NVJSValue@2@@Z
?validate@MarkStack@JSC@@KAXPAVJSCell@2@@Z
?validate@SlotVisitor@JSC@@CAXPAVJSCell@2@@Z
?visitChildren@JSGlobalObject@JSC@@SAXPAVJSCell@2@AAVSlotVisitor@2@@Z
?visitChildren@JSGlobalThis@JSC@@KAXPAVJSCell@2@AAVSlotVisitor@2@@Z
?visitChildren@JSObject@JSC@@SAXPAVJSCell@2@AAVSlotVisitor@2@@Z
......
......@@ -2385,6 +2385,10 @@
RelativePath="..\..\heap\MarkStackInlineMethods.h"
>
</File>
<File
RelativePath="..\..\heap\SlotVisitor.cpp"
>
</File>
<File
RelativePath="..\..\heap\Strong.h"
>
......
......@@ -693,6 +693,8 @@
C21122E115DD9AB300790E3A /* GCThreadSharedData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */; };
C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */; settings = {ATTRIBUTES = (Private, ); }; };
C21122E315DD9AB300790E3A /* MarkStackInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2160FE715F7E95E00942DFC /* SlotVisitorInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCB408515C0A3C30048932B /* SlotVisitorInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
C225494315F7DBAA0065E898 /* SlotVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C225494215F7DBAA0065E898 /* SlotVisitor.cpp */; };
C22B31B9140577D700DB475A /* SamplingCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F77008E1402FDD60078EB39 /* SamplingCounter.h */; settings = {ATTRIBUTES = (Private, ); }; };
C240305514B404E60079EB64 /* CopiedSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C240305314B404C90079EB64 /* CopiedSpace.cpp */; };
C25F8BCD157544A900245B71 /* IncrementalSweeper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */; };
......@@ -1455,6 +1457,7 @@
C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCThreadSharedData.cpp; sourceTree = "<group>"; };
C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCThreadSharedData.h; sourceTree = "<group>"; };
C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStackInlineMethods.h; sourceTree = "<group>"; };
C225494215F7DBAA0065E898 /* SlotVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SlotVisitor.cpp; sourceTree = "<group>"; };
C240305314B404C90079EB64 /* CopiedSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopiedSpace.cpp; sourceTree = "<group>"; };
C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IncrementalSweeper.cpp; sourceTree = "<group>"; };
C25F8BCC157544A900245B71 /* IncrementalSweeper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IncrementalSweeper.h; sourceTree = "<group>"; };
......@@ -1784,6 +1787,7 @@
142E312A134FF0A600AFADB5 /* heap */ = {
isa = PBXGroup;
children = (
C225494215F7DBAA0065E898 /* SlotVisitor.cpp */,
C21122DE15DD9AB300790E3A /* GCThreadSharedData.cpp */,
C21122DF15DD9AB300790E3A /* GCThreadSharedData.h */,
C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */,
......@@ -2527,6 +2531,7 @@
C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */,
FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */,
C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */,
C2160FE715F7E95E00942DFC /* SlotVisitorInlineMethods.h in Headers */,
C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */,
C21122E315DD9AB300790E3A /* MarkStackInlineMethods.h in Headers */,
C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */,
......@@ -3503,6 +3508,7 @@
14874AE515EBDE4A002E3587 /* JSScope.cpp in Sources */,
1442566115EDE98D0066A49B /* JSWithScope.cpp in Sources */,
FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */,
C225494315F7DBAA0065E898 /* SlotVisitor.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -89,6 +89,7 @@ SOURCES += \
heap/MarkedAllocator.cpp \
heap/MarkedBlock.cpp \
heap/MarkedSpace.cpp \
heap/SlotVisitor.cpp \
heap/VTableSpectrum.cpp \
heap/WriteBarrierSupport.cpp \
debugger/DebuggerActivation.cpp \
......
......@@ -45,6 +45,7 @@
#include "LowLevelInterpreter.h"
#include "MethodCallLinkStatus.h"
#include "RepatchBuffer.h"
#include "SlotVisitorInlineMethods.h"
#include <stdio.h>
#include <wtf/StringExtras.h>
#include <wtf/UnusedParam.h>
......
......@@ -31,6 +31,7 @@
#if ENABLE(DFG_JIT)
#include "CodeOrigin.h"
#include "Options.h"
#include "VirtualRegister.h"
/* DFG_ENABLE() - turn on a specific features in the DFG JIT */
......
......@@ -29,6 +29,7 @@
#include "JSGlobalData.h"
#include "MarkStack.h"
#include "SlotVisitor.h"
#include "SlotVisitorInlineMethods.h"
#include <wtf/MainThread.h>
namespace JSC {
......
......@@ -26,7 +26,12 @@
#ifndef GCThreadSharedData_h
#define GCThreadSharedData_h
#include "ListableHandler.h"
#include "MarkStack.h"
#include "UnconditionalFinalizer.h"
#include "WeakReferenceHarvester.h"
#include <wtf/HashSet.h>
#include <wtf/Threading.h>
#include <wtf/Vector.h>
namespace JSC {
......@@ -48,7 +53,6 @@ public:
#endif
private:
friend class MarkStack;
friend class SlotVisitor;
#if ENABLE(PARALLEL_GC)
......@@ -64,7 +68,7 @@ private:
bool m_shouldHashConst;
Vector<ThreadIdentifier> m_markingThreads;
Vector<MarkStack*> m_markingThreadsMarkStack;
Vector<SlotVisitor*> m_markingThreadsMarkStack;
Mutex m_markingLock;
ThreadCondition m_markingCondition;
......
......@@ -27,6 +27,7 @@
#define HeapRootVisitor_h
#include "SlotVisitor.h"
#include "SlotVisitorInlineMethods.h"
namespace JSC {
......
......@@ -223,402 +223,4 @@ void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other, size_t idleThread
append(other.removeLast());
}
MarkStack::MarkStack(GCThreadSharedData& shared)
: m_stack(shared.m_segmentAllocator)
#if !ASSERT_DISABLED
, m_isCheckingForDefaultMarkViolation(false)
, m_isDraining(false)
#endif
, m_visitCount(0)
, m_isInParallelMode(false)
, m_shared(shared)
, m_shouldHashConst(false)
{
}
MarkStack::~MarkStack()
{
ASSERT(m_stack.isEmpty());
}
void MarkStack::setup()
{
m_shared.m_shouldHashConst = m_shared.m_globalData->haveEnoughNewStringsToHashConst();
m_shouldHashConst = m_shared.m_shouldHashConst;
#if ENABLE(PARALLEL_GC)
for (unsigned i = 0; i < m_shared.m_markingThreadsMarkStack.size(); ++i)
m_shared.m_markingThreadsMarkStack[i]->m_shouldHashConst = m_shared.m_shouldHashConst;
#endif
}
void MarkStack::reset()
{
m_visitCount = 0;
ASSERT(m_stack.isEmpty());
#if ENABLE(PARALLEL_GC)
ASSERT(m_opaqueRoots.isEmpty()); // Should have merged by now.
#else
m_opaqueRoots.clear();
#endif
if (m_shouldHashConst) {
m_uniqueStrings.clear();
m_shouldHashConst = false;
}
}
void MarkStack::append(ConservativeRoots& conservativeRoots)
{
JSCell** roots = conservativeRoots.roots();
size_t size = conservativeRoots.size();
for (size_t i = 0; i < size; ++i)
internalAppend(roots[i]);
}
ALWAYS_INLINE static void visitChildren(SlotVisitor& visitor, const JSCell* cell)
{
#if ENABLE(SIMPLE_HEAP_PROFILING)
m_visitedTypeCounts.count(cell);
#endif
ASSERT(Heap::isMarked(cell));
if (isJSString(cell)) {
JSString::visitChildren(const_cast<JSCell*>(cell), visitor);
return;
}
if (isJSFinalObject(cell)) {
JSFinalObject::visitChildren(const_cast<JSCell*>(cell), visitor);
return;
}
if (isJSArray(cell)) {
JSArray::visitChildren(const_cast<JSCell*>(cell), visitor);
return;
}
cell->methodTable()->visitChildren(const_cast<JSCell*>(cell), visitor);
}
void SlotVisitor::donateKnownParallel()
{
// NOTE: Because we re-try often, we can afford to be conservative, and
// assume that donating is not profitable.
// Avoid locking when a thread reaches a dead end in the object graph.
if (m_stack.size() < 2)
return;
// If there's already some shared work queued up, be conservative and assume
// that donating more is not profitable.
if (m_shared.m_sharedMarkStack.size())
return;
// If we're contending on the lock, be conservative and assume that another
// thread is already donating.
MutexTryLocker locker(m_shared.m_markingLock);
if (!locker.locked())
return;
// Otherwise, assume that a thread will go idle soon, and donate.
m_stack.donateSomeCellsTo(m_shared.m_sharedMarkStack);
if (m_shared.m_numberOfActiveParallelMarkers < Options::numberOfGCMarkers())
m_shared.m_markingCondition.broadcast();
}
void SlotVisitor::drain()
{
ASSERT(m_isInParallelMode);
#if ENABLE(PARALLEL_GC)
if (Options::numberOfGCMarkers() > 1) {
while (!m_stack.isEmpty()) {
m_stack.refill();
for (unsigned countdown = Options::minimumNumberOfScansBetweenRebalance(); m_stack.canRemoveLast() && countdown--;)
visitChildren(*this, m_stack.removeLast());
donateKnownParallel();
}
mergeOpaqueRootsIfNecessary();
return;
}
#endif
while (!m_stack.isEmpty()) {
m_stack.refill();
while (m_stack.canRemoveLast())
visitChildren(*this, m_stack.removeLast());
}
}
void SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode)
{
ASSERT(m_isInParallelMode);
ASSERT(Options::numberOfGCMarkers());
bool shouldBeParallel;
#if ENABLE(PARALLEL_GC)
shouldBeParallel = Options::numberOfGCMarkers() > 1;
#else
ASSERT(Options::numberOfGCMarkers() == 1);
shouldBeParallel = false;
#endif
if (!shouldBeParallel) {
// This call should be a no-op.
ASSERT_UNUSED(sharedDrainMode, sharedDrainMode == MasterDrain);
ASSERT(m_stack.isEmpty());
ASSERT(m_shared.m_sharedMarkStack.isEmpty());
return;
}
#if ENABLE(PARALLEL_GC)
{
MutexLocker locker(m_shared.m_markingLock);
m_shared.m_numberOfActiveParallelMarkers++;
}
while (true) {
{
MutexLocker locker(m_shared.m_markingLock);
m_shared.m_numberOfActiveParallelMarkers--;
// How we wait differs depending on drain mode.
if (sharedDrainMode == MasterDrain) {
// Wait until either termination is reached, or until there is some work
// for us to do.
while (true) {
// Did we reach termination?
if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty()) {
// Let any sleeping slaves know it's time for them to give their private CopiedBlocks back
m_shared.m_markingCondition.broadcast();
return;
}
// Is there work to be done?
if (!m_shared.m_sharedMarkStack.isEmpty())
break;
// Otherwise wait.
m_shared.m_markingCondition.wait(m_shared.m_markingLock);
}
} else {
ASSERT(sharedDrainMode == SlaveDrain);
// Did we detect termination? If so, let the master know.
if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty())
m_shared.m_markingCondition.broadcast();
while (m_shared.m_sharedMarkStack.isEmpty() && !m_shared.m_parallelMarkersShouldExit) {
if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty())
doneCopying();
m_shared.m_markingCondition.wait(m_shared.m_markingLock);
}
// Is the VM exiting? If so, exit this thread.
if (m_shared.m_parallelMarkersShouldExit) {
doneCopying();
return;
}
}
size_t idleThreadCount = Options::numberOfGCMarkers() - m_shared.m_numberOfActiveParallelMarkers;
m_stack.stealSomeCellsFrom(m_shared.m_sharedMarkStack, idleThreadCount);
m_shared.m_numberOfActiveParallelMarkers++;
}
drain();
}
#endif
}
void MarkStack::mergeOpaqueRoots()
{
ASSERT(!m_opaqueRoots.isEmpty()); // Should only be called when opaque roots are non-empty.
{
MutexLocker locker(m_shared.m_opaqueRootsLock);
HashSet<void*>::iterator begin = m_opaqueRoots.begin();
HashSet<void*>::iterator end = m_opaqueRoots.end();
for (HashSet<void*>::iterator iter = begin; iter != end; ++iter)
m_shared.m_opaqueRoots.add(*iter);
}
m_opaqueRoots.clear();
}
void SlotVisitor::startCopying()
{
ASSERT(!m_copiedAllocator.isValid());
}
void* SlotVisitor::allocateNewSpaceSlow(size_t bytes)
{
m_shared.m_copiedSpace->doneFillingBlock(m_copiedAllocator.resetCurrentBlock());
m_copiedAllocator.setCurrentBlock(m_shared.m_copiedSpace->allocateBlockForCopyingPhase());
void* result = 0;
CheckedBoolean didSucceed = m_copiedAllocator.tryAllocate(bytes, &result);
ASSERT(didSucceed);
return result;
}
void* SlotVisitor::allocateNewSpaceOrPin(void* ptr, size_t bytes)
{
if (!checkIfShouldCopyAndPinOtherwise(ptr, bytes))
return 0;
return allocateNewSpace(bytes);
}
ALWAYS_INLINE bool JSString::tryHashConstLock()
{
#if ENABLE(PARALLEL_GC)
unsigned currentFlags = m_flags;
if (currentFlags & HashConstLock)
return false;
unsigned newFlags = currentFlags | HashConstLock;
if (!WTF::weakCompareAndSwap(&m_flags, currentFlags, newFlags))
return false;
WTF::memoryBarrierAfterLock();
return true;
#else
if (isHashConstSingleton())
return false;
m_flags |= HashConstLock;
return true;
#endif
}
ALWAYS_INLINE void JSString::releaseHashConstLock()
{
#if ENABLE(PARALLEL_GC)
WTF::memoryBarrierBeforeUnlock();
#endif
m_flags &= ~HashConstLock;
}
ALWAYS_INLINE bool JSString::shouldTryHashConst()
{
return ((length() > 1) && !isRope() && !isHashConstSingleton());
}
ALWAYS_INLINE void MarkStack::internalAppend(JSValue* slot)
{
// This internalAppend is only intended for visits to object and array backing stores.
// as it can change the JSValue pointed to be the argument when the original JSValue
// is a string that contains the same contents as another string.
ASSERT(slot);
JSValue value = *slot;
ASSERT(value);
if (!value.isCell())
return;
JSCell* cell = value.asCell();
if (!cell)
return;
if (m_shouldHashConst && cell->isString()) {
JSString* string = jsCast<JSString*>(cell);
if (string->shouldTryHashConst() && string->tryHashConstLock()) {
UniqueStringMap::AddResult addResult = m_uniqueStrings.add(string->string().impl(), value);
if (addResult.isNewEntry)
string->setHashConstSingleton();
else {
JSValue existingJSValue = addResult.iterator->second;
if (value != existingJSValue)
jsCast<JSString*>(existingJSValue.asCell())->clearHashConstSingleton();
*slot = existingJSValue;
string->releaseHashConstLock();
return;
}
string->releaseHashConstLock();
}
}
internalAppend(cell);
}
void SlotVisitor::copyAndAppend(void** ptr, size_t bytes, JSValue* values, unsigned length)
{
void* oldPtr = *ptr;
void* newPtr = allocateNewSpaceOrPin(oldPtr, bytes);
if (newPtr) {