Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (119632 => 119633)
--- trunk/Source/_javascript_Core/ChangeLog 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-06-06 23:11:09 UTC (rev 119633)
@@ -1,3 +1,49 @@
+2012-06-06 Michael Saboff <[email protected]>
+
+ ENH: Add Logging to GC Marking Phase
+ https://bugs.webkit.org/show_bug.cgi?id=88364
+
+ Reviewed by Filip Pizlo.
+
+ Log GC marking to stderr or a file. The logging in controlled
+ with the define ENABLE_OBJECT_MARK_LOGGING in wtf/Platform.h.
+ If DATA_LOG_TO_FILE in wtf/DataLog.cpp is set to 1, output is
+ logged to a file otherwise it is logged to stderr.
+
+ When logging is enabled, the GC is built single threaded since the
+ log output from the various threads isn't buffered and output in a
+ thread safe manner.
+
+ * heap/Heap.cpp:
+ (JSC::Heap::markRoots):
+ * heap/MarkStack.cpp:
+ (JSC::MarkStackThreadSharedData::resetChildren):
+ (JSC::MarkStackThreadSharedData::childVisitCount):
+ (JSC::MarkStackThreadSharedData::markingThreadMain):
+ (JSC::MarkStackThreadSharedData::markingThreadStartFunc):
+ (JSC::MarkStackThreadSharedData::MarkStackThreadSharedData):
+ (JSC::MarkStackThreadSharedData::reset):
+ * heap/MarkStack.h:
+ (MarkStackThreadSharedData):
+ (MarkStack):
+ (JSC::MarkStack::sharedData):
+ (JSC::MarkStack::resetChildCount):
+ (JSC::MarkStack::childCount):
+ (JSC::MarkStack::incrementChildCount):
+ * runtime/JSArray.cpp:
+ (JSC::JSArray::visitChildren):
+ * runtime/JSCell.cpp:
+ (JSC::JSCell::className):
+ * runtime/JSCell.h:
+ (JSCell):
+ (JSC::JSCell::visitChildren):
+ * runtime/JSString.cpp:
+ (JSC::JSString::visitChildren):
+ * runtime/JSString.h:
+ (JSString):
+ * runtime/Structure.h:
+ (JSC::MarkStack::internalAppend):
+
2012-06-06 Gavin Barraclough <[email protected]>
Assigning to a static property should not change iteration order
Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (119632 => 119633)
--- trunk/Source/_javascript_Core/heap/Heap.cpp 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp 2012-06-06 23:11:09 UTC (rev 119633)
@@ -421,6 +421,10 @@
UNUSED_PARAM(fullGC);
ASSERT(isValidThreadState(m_globalData));
+#if ENABLE(OBJECT_MARK_LOGGING)
+ double gcStartTime = WTF::currentTime();
+#endif
+
void* dummy;
// We gather conservative roots before clearing mark bits because conservative
@@ -484,28 +488,33 @@
{
GCPHASE(VisitMachineRoots);
+ MARK_LOG_ROOT(visitor, "C++ Stack");
visitor.append(machineThreadRoots);
visitor.donateAndDrain();
}
{
GCPHASE(VisitRegisterFileRoots);
+ MARK_LOG_ROOT(visitor, "Register File");
visitor.append(registerFileRoots);
visitor.donateAndDrain();
}
#if ENABLE(DFG_JIT)
{
GCPHASE(VisitScratchBufferRoots);
+ MARK_LOG_ROOT(visitor, "Scratch Buffers");
visitor.append(scratchBufferRoots);
visitor.donateAndDrain();
}
#endif
{
GCPHASE(VisitProtectedObjects);
+ MARK_LOG_ROOT(visitor, "Protected Objects");
markProtectedObjects(heapRootVisitor);
visitor.donateAndDrain();
}
{
GCPHASE(VisitTempSortVectors);
+ MARK_LOG_ROOT(visitor, "Temp Sort Vectors");
markTempSortVectors(heapRootVisitor);
visitor.donateAndDrain();
}
@@ -513,30 +522,35 @@
{
GCPHASE(MarkingArgumentBuffers);
if (m_markListSet && m_markListSet->size()) {
+ MARK_LOG_ROOT(visitor, "Argument Buffers");
MarkedArgumentBuffer::markLists(heapRootVisitor, *m_markListSet);
visitor.donateAndDrain();
}
}
if (m_globalData->exception) {
GCPHASE(MarkingException);
+ MARK_LOG_ROOT(visitor, "Exceptions");
heapRootVisitor.visit(&m_globalData->exception);
visitor.donateAndDrain();
}
{
GCPHASE(VisitStrongHandles);
+ MARK_LOG_ROOT(visitor, "Strong Handles");
m_handleSet.visitStrongHandles(heapRootVisitor);
visitor.donateAndDrain();
}
{
GCPHASE(HandleStack);
+ MARK_LOG_ROOT(visitor, "Handle Stack");
m_handleStack.visit(heapRootVisitor);
visitor.donateAndDrain();
}
{
GCPHASE(TraceCodeBlocks);
+ MARK_LOG_ROOT(visitor, "Trace Code Blocks");
m_dfgCodeBlocks.traceMarkedCodeBlocks(visitor);
visitor.donateAndDrain();
}
@@ -553,6 +567,7 @@
// the liveness of the rest of the object graph.
{
GCPHASE(VisitingLiveWeakHandles);
+ MARK_LOG_ROOT(visitor, "Live Weak Handles");
while (true) {
m_objectSpace.visitWeakSets(heapRootVisitor);
harvestWeakReferences();
@@ -571,8 +586,19 @@
GCCOUNTER(VisitedValueCount, visitor.visitCount());
visitor.doneCopying();
+#if ENABLE(OBJECT_MARK_LOGGING)
+ size_t visitCount = visitor.visitCount();
+#if ENABLE(PARALLEL_GC)
+ visitCount += m_sharedData.childVisitCount();
+#endif
+ MARK_LOG_MESSAGE2("\nNumber of live Objects after full GC %lu, took %.6f secs\n", visitCount, WTF::currentTime() - gcStartTime);
+#endif
+
visitor.reset();
m_sharedData.reset();
+#if ENABLE(PARALLEL_GC)
+ m_sharedData.resetChildren();
+#endif
m_storageSpace.doneCopying();
}
Modified: trunk/Source/_javascript_Core/heap/MarkStack.cpp (119632 => 119633)
--- trunk/Source/_javascript_Core/heap/MarkStack.cpp 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/_javascript_Core/heap/MarkStack.cpp 2012-06-06 23:11:09 UTC (rev 119633)
@@ -36,6 +36,7 @@
#include "JSObject.h"
#include "ScopeChain.h"
#include "Structure.h"
+#include "UString.h"
#include "WriteBarrier.h"
#include <wtf/DataLog.h>
#include <wtf/MainThread.h>
@@ -219,19 +220,35 @@
}
#if ENABLE(PARALLEL_GC)
-void MarkStackThreadSharedData::markingThreadMain()
+void MarkStackThreadSharedData::resetChildren()
{
+ for (unsigned i = 0; i < m_markingThreadsMarkStack.size(); ++i)
+ m_markingThreadsMarkStack[i]->reset();
+}
+
+size_t MarkStackThreadSharedData::childVisitCount()
+{
+ unsigned long result = 0;
+ for (unsigned i = 0; i < m_markingThreadsMarkStack.size(); ++i)
+ result += m_markingThreadsMarkStack[i]->visitCount();
+ return result;
+}
+
+void MarkStackThreadSharedData::markingThreadMain(SlotVisitor* slotVisitor)
+{
WTF::registerGCThread();
{
- SlotVisitor slotVisitor(*this);
- ParallelModeEnabler enabler(slotVisitor);
- slotVisitor.drainFromShared(SlotVisitor::SlaveDrain);
+ ParallelModeEnabler enabler(*slotVisitor);
+ slotVisitor->drainFromShared(SlotVisitor::SlaveDrain);
}
+ delete slotVisitor;
}
-void MarkStackThreadSharedData::markingThreadStartFunc(void* shared)
-{
- static_cast<MarkStackThreadSharedData*>(shared)->markingThreadMain();
+void MarkStackThreadSharedData::markingThreadStartFunc(void* myVisitor)
+{
+ SlotVisitor* slotVisitor = static_cast<SlotVisitor*>(myVisitor);
+
+ slotVisitor->sharedData().markingThreadMain(slotVisitor);
}
#endif
@@ -244,7 +261,9 @@
{
#if ENABLE(PARALLEL_GC)
for (unsigned i = 1; i < Options::numberOfGCMarkers; ++i) {
- m_markingThreads.append(createThread(markingThreadStartFunc, this, "_javascript_Core::Marking"));
+ SlotVisitor* slotVisitor = new SlotVisitor(*this);
+ m_markingThreadsMarkStack.append(slotVisitor);
+ m_markingThreads.append(createThread(markingThreadStartFunc, slotVisitor, "_javascript_Core::Marking"));
ASSERT(m_markingThreads.last());
}
#endif
@@ -276,7 +295,6 @@
#else
ASSERT(m_opaqueRoots.isEmpty());
#endif
-
m_weakReferenceHarvesters.removeAll();
}
Modified: trunk/Source/_javascript_Core/heap/MarkStack.h (119632 => 119633)
--- trunk/Source/_javascript_Core/heap/MarkStack.h 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/_javascript_Core/heap/MarkStack.h 2012-06-06 23:11:09 UTC (rev 119633)
@@ -34,13 +34,40 @@
#include "UnconditionalFinalizer.h"
#include "VTableSpectrum.h"
#include "WeakReferenceHarvester.h"
+#include <wtf/DataLog.h>
+#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/Vector.h>
#include <wtf/Noncopyable.h>
#include <wtf/OSAllocator.h>
#include <wtf/PageBlock.h>
+#include <wtf/text/StringHash.h>
+#if ENABLE(OBJECT_MARK_LOGGING)
+#define MARK_LOG_MESSAGE0(message) dataLog(message)
+#define MARK_LOG_MESSAGE1(message, arg1) dataLog(message, arg1)
+#define MARK_LOG_MESSAGE2(message, arg1, arg2) dataLog(message, arg1, arg2)
+#define MARK_LOG_ROOT(visitor, rootName) \
+ dataLog("\n%s: ", rootName); \
+ (visitor).resetChildCount()
+#define MARK_LOG_PARENT(visitor, parent) \
+ dataLog("\n%p (%s): ", parent, parent->className() ? parent->className() : "unknown"); \
+ (visitor).resetChildCount()
+#define MARK_LOG_CHILD(visitor, child) \
+ if ((visitor).childCount()) \
+ dataLogString(", "); \
+ dataLog("%p", child); \
+ (visitor).incrementChildCount()
+#else
+#define MARK_LOG_MESSAGE0(message) do { } while (false)
+#define MARK_LOG_MESSAGE1(message, arg1) do { } while (false)
+#define MARK_LOG_MESSAGE2(message, arg1, arg2) do { } while (false)
+#define MARK_LOG_ROOT(visitor, rootName) do { } while (false)
+#define MARK_LOG_PARENT(visitor, parent) do { } while (false)
+#define MARK_LOG_CHILD(visitor, child) do { } while (false)
+#endif
+
namespace JSC {
class ConservativeRoots;
@@ -171,13 +198,19 @@
~MarkStackThreadSharedData();
void reset();
+
+#if ENABLE(PARALLEL_GC)
+ void resetChildren();
+ size_t childVisitCount();
+ size_t childDupStrings();
+#endif
private:
friend class MarkStack;
friend class SlotVisitor;
#if ENABLE(PARALLEL_GC)
- void markingThreadMain();
+ void markingThreadMain(SlotVisitor*);
static void markingThreadStartFunc(void* heap);
#endif
@@ -187,6 +220,7 @@
MarkStackSegmentAllocator m_segmentAllocator;
Vector<ThreadIdentifier> m_markingThreads;
+ Vector<MarkStack*> m_markingThreadsMarkStack;
Mutex m_markingLock;
ThreadCondition m_markingCondition;
@@ -221,7 +255,8 @@
void addOpaqueRoot(void*);
bool containsOpaqueRoot(void*);
int opaqueRootCount();
-
+
+ MarkStackThreadSharedData& sharedData() { return m_shared; }
bool isEmpty() { return m_stack.isEmpty(); }
void reset();
@@ -242,6 +277,12 @@
m_shared.m_unconditionalFinalizers.addThreadSafe(unconditionalFinalizer);
}
+#if ENABLE(OBJECT_MARK_LOGGING)
+ inline void resetChildCount() { m_logChildCount = 0; }
+ inline unsigned childCount() { return m_logChildCount; }
+ inline void incrementChildCount() { m_logChildCount++; }
+#endif
+
protected:
JS_EXPORT_PRIVATE static void validate(JSCell*);
@@ -283,6 +324,10 @@
bool m_isInParallelMode;
MarkStackThreadSharedData& m_shared;
+
+#if ENABLE(OBJECT_MARK_LOGGING)
+ unsigned m_logChildCount;
+#endif
};
inline MarkStack::MarkStack(MarkStackThreadSharedData& shared)
Modified: trunk/Source/_javascript_Core/runtime/JSArray.cpp (119632 => 119633)
--- trunk/Source/_javascript_Core/runtime/JSArray.cpp 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/_javascript_Core/runtime/JSArray.cpp 2012-06-06 23:11:09 UTC (rev 119633)
@@ -1371,6 +1371,8 @@
JSNonFinalObject::visitChildren(thisObject, visitor);
if (thisObject->m_storage) {
+ MARK_LOG_MESSAGE1("[%u]: ", thisObject->length());
+
ArrayStorage* storage = thisObject->m_storage;
void* baseStorage = storage->m_allocBase;
Modified: trunk/Source/_javascript_Core/runtime/JSCell.cpp (119632 => 119633)
--- trunk/Source/_javascript_Core/runtime/JSCell.cpp 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/_javascript_Core/runtime/JSCell.cpp 2012-06-06 23:11:09 UTC (rev 119633)
@@ -184,6 +184,11 @@
return UString();
}
+const char* JSCell::className()
+{
+ return classInfo()->className;
+}
+
void JSCell::getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
{
ASSERT_NOT_REACHED();
Modified: trunk/Source/_javascript_Core/runtime/JSCell.h (119632 => 119633)
--- trunk/Source/_javascript_Core/runtime/JSCell.h 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/_javascript_Core/runtime/JSCell.h 2012-06-06 23:11:09 UTC (rev 119633)
@@ -84,6 +84,8 @@
void setStructure(JSGlobalData&, Structure*);
void clearStructure() { m_structure.clear(); }
+ const char* className();
+
// Extracting the value.
JS_EXPORT_PRIVATE bool getString(ExecState* exec, UString&) const;
JS_EXPORT_PRIVATE UString getString(ExecState* exec) const; // null string if not a string
@@ -197,6 +199,8 @@
inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
+ MARK_LOG_PARENT(visitor, cell);
+
visitor.append(&cell->m_structure);
}
Modified: trunk/Source/_javascript_Core/runtime/JSString.cpp (119632 => 119633)
--- trunk/Source/_javascript_Core/runtime/JSString.cpp 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/_javascript_Core/runtime/JSString.cpp 2012-06-06 23:11:09 UTC (rev 119633)
@@ -56,6 +56,19 @@
JSString* thisObject = jsCast<JSString*>(cell);
Base::visitChildren(thisObject, visitor);
+ MARK_LOG_MESSAGE1("[%u]: ", thisObject->length());
+
+#if ENABLE(OBJECT_MARK_LOGGING)
+ if (!thisObject->isRope()) {
+ WTF::StringImpl* ourImpl = thisObject->m_value.impl();
+ if (ourImpl->is8Bit())
+ MARK_LOG_MESSAGE1("[8 %p]", ourImpl->characters8());
+ else
+ MARK_LOG_MESSAGE1("[16 %p]", ourImpl->characters16());
+ } else
+ MARK_LOG_MESSAGE0("[rope]: ");
+#endif
+
if (thisObject->isRope())
static_cast<JSRopeString*>(thisObject)->visitFibers(visitor);
}
Modified: trunk/Source/_javascript_Core/runtime/JSString.h (119632 => 119633)
--- trunk/Source/_javascript_Core/runtime/JSString.h 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/_javascript_Core/runtime/JSString.h 2012-06-06 23:11:09 UTC (rev 119633)
@@ -67,6 +67,7 @@
friend class JSGlobalData;
friend class SpecializedThunkJIT;
friend class JSRopeString;
+ friend class SlotVisitor;
friend struct ThunkHelpers;
typedef JSCell Base;
Modified: trunk/Source/_javascript_Core/runtime/Structure.h (119632 => 119633)
--- trunk/Source/_javascript_Core/runtime/Structure.h 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/_javascript_Core/runtime/Structure.h 2012-06-06 23:11:09 UTC (rev 119633)
@@ -382,10 +382,13 @@
#if ENABLE(GC_VALIDATION)
validate(cell);
#endif
- m_visitCount++;
if (Heap::testAndSetMarked(cell) || !cell->structure())
return;
+
+ m_visitCount++;
+ MARK_LOG_CHILD(*this, cell);
+
// Should never attempt to mark something that is zapped.
ASSERT(!cell->isZapped());
Modified: trunk/Source/WTF/ChangeLog (119632 => 119633)
--- trunk/Source/WTF/ChangeLog 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/WTF/ChangeLog 2012-06-06 23:11:09 UTC (rev 119633)
@@ -1,3 +1,15 @@
+2012-06-06 Michael Saboff <[email protected]>
+
+ ENH: Add Logging to GC Marking Phase
+ https://bugs.webkit.org/show_bug.cgi?id=88364
+
+ Reviewed by Filip Pizlo.
+
+ * wtf/DataLog.cpp:
+ (WTF::dataLogString): Additional method to support GC Mark logging.
+ * wtf/DataLog.h:
+ * wtf/Platform.h: New ENABLE_OBJECT_MARK_LOGGING flag macro.
+
2012-06-06 Andy Wingo <[email protected]>
[GTK] Enable the LLInt
Modified: trunk/Source/WTF/wtf/DataLog.cpp (119632 => 119633)
--- trunk/Source/WTF/wtf/DataLog.cpp 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/WTF/wtf/DataLog.cpp 2012-06-06 23:11:09 UTC (rev 119633)
@@ -95,5 +95,10 @@
va_end(argList);
}
+void dataLogString(const char* str)
+{
+ fputs(str, dataFile());
+}
+
} // namespace WTF
Modified: trunk/Source/WTF/wtf/DataLog.h (119632 => 119633)
--- trunk/Source/WTF/wtf/DataLog.h 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/WTF/wtf/DataLog.h 2012-06-06 23:11:09 UTC (rev 119633)
@@ -37,10 +37,12 @@
WTF_EXPORT_PRIVATE void dataLogV(const char* format, va_list) WTF_ATTRIBUTE_PRINTF(1, 0);
WTF_EXPORT_PRIVATE void dataLog(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
+WTF_EXPORT_PRIVATE void dataLogString(const char*);
} // namespace WTF
using WTF::dataLog;
+using WTF::dataLogString;
#endif // DataLog_h
Modified: trunk/Source/WTF/wtf/Platform.h (119632 => 119633)
--- trunk/Source/WTF/wtf/Platform.h 2012-06-06 23:04:10 UTC (rev 119632)
+++ trunk/Source/WTF/wtf/Platform.h 2012-06-06 23:11:09 UTC (rev 119633)
@@ -1072,7 +1072,9 @@
#define ENABLE_COMPARE_AND_SWAP 1
#endif
-#if !defined(ENABLE_PARALLEL_GC) && (PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(QT) || PLATFORM(BLACKBERRY)) && ENABLE(COMPARE_AND_SWAP)
+#define ENABLE_OBJECT_MARK_LOGGING 0
+
+#if !defined(ENABLE_PARALLEL_GC) && !ENABLE(OBJECT_MARK_LOGGING) && (PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(QT) || PLATFORM(BLACKBERRY)) && ENABLE(COMPARE_AND_SWAP)
#define ENABLE_PARALLEL_GC 1
#endif