| Index: Source/platform/heap/Heap.cpp
|
| diff --git a/Source/platform/heap/Heap.cpp b/Source/platform/heap/Heap.cpp
|
| index 3f1948e6cdd9fa8424962f288b751c04f063cfbe..53defd6939fa888f8b413843d0a442528ab23bee 100644
|
| --- a/Source/platform/heap/Heap.cpp
|
| +++ b/Source/platform/heap/Heap.cpp
|
| @@ -39,7 +39,7 @@
|
| #include "wtf/Assertions.h"
|
| #include "wtf/LeakAnnotations.h"
|
| #include "wtf/PassOwnPtr.h"
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| #include "wtf/HashMap.h"
|
| #include "wtf/HashSet.h"
|
| #include "wtf/text/StringBuilder.h"
|
| @@ -47,6 +47,9 @@
|
| #include <stdio.h>
|
| #include <utility>
|
| #endif
|
| +#if GC_PROFILE_HEAP
|
| +#include "platform/TracedValue.h"
|
| +#endif
|
|
|
| #if OS(POSIX)
|
| #include <sys/mman.h>
|
| @@ -57,7 +60,7 @@
|
|
|
| namespace WebCore {
|
|
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| static String classOf(const void* object)
|
| {
|
| const GCInfo* gcInfo = Heap::findGCInfo(reinterpret_cast<Address>(const_cast<void*>(object)));
|
| @@ -505,7 +508,7 @@ void LargeHeapObject<Header>::checkAndMarkPointer(Visitor* visitor, Address addr
|
| ASSERT(contains(address));
|
| if (!objectContains(address))
|
| return;
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| visitor->setHostInfo(&address, "stack");
|
| #endif
|
| mark(visitor);
|
| @@ -641,7 +644,7 @@ BaseHeapPage* ThreadHeap<Header>::heapPageFromAddress(Address address)
|
| return 0;
|
| }
|
|
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| template<typename Header>
|
| const GCInfo* ThreadHeap<Header>::findGCInfoOfLargeHeapObject(Address address)
|
| {
|
| @@ -653,6 +656,43 @@ const GCInfo* ThreadHeap<Header>::findGCInfoOfLargeHeapObject(Address address)
|
| }
|
| #endif
|
|
|
| +#if GC_PROFILE_HEAP
|
| +template<typename Header>
|
| +void ThreadHeap<Header>::snapshot(TracedDictionaryBase* json, ThreadState::SnapshotInfo* info)
|
| +{
|
| + size_t previousPageCount = info->pageCount;
|
| +
|
| + TracedArrayBase& pages = json->beginArray("pages");
|
| + for (HeapPage<Header>* page = m_firstPage; page; page = page->next(), ++info->pageCount) {
|
| + // FIXME: To limit the size of the snapshot we only output "threshold" many page snapshots.
|
| + TracedArrayBase* jsonPage = 0;
|
| + if (info->pageCount < GC_PROFILE_HEAP_PAGE_DUMP_THRESHOLD) {
|
| + jsonPage = &pages.beginArray();
|
| + jsonPage->pushInteger(reinterpret_cast<intptr_t>(page));
|
| + }
|
| + page->snapshot(jsonPage, info);
|
| + if (jsonPage)
|
| + jsonPage->endArray();
|
| + }
|
| + pages.endArray();
|
| +
|
| + TracedArrayBase& largeObjects = json->beginArray("largeObjects");
|
| + for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; current = current->next()) {
|
| + TracedDictionaryBase& jsonCurrent = largeObjects.beginDictionary();
|
| + current->snapshot(&jsonCurrent, info);
|
| + jsonCurrent.endDictionary();
|
| + }
|
| + largeObjects.endArray();
|
| +
|
| + size_t pagePoolSize = 0;
|
| + for (PagePoolEntry* page = m_pagePool; page; page = page->next())
|
| + ++pagePoolSize;
|
| +
|
| + json->setInteger("pagePoolSize", pagePoolSize)
|
| + .setInteger("pageCount", info->pageCount - previousPageCount);
|
| +}
|
| +#endif
|
| +
|
| template<typename Header>
|
| void ThreadHeap<Header>::addToFreeList(Address address, size_t size)
|
| {
|
| @@ -1201,7 +1241,7 @@ void HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address)
|
| if (!header)
|
| return;
|
|
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| visitor->setHostInfo(&address, "stack");
|
| #endif
|
| if (hasVTable(header) && !vTableInitialized(header->payload()))
|
| @@ -1210,7 +1250,7 @@ void HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address)
|
| visitor->mark(header, traceCallback(header));
|
| }
|
|
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| template<typename Header>
|
| const GCInfo* HeapPage<Header>::findGCInfo(Address address)
|
| {
|
| @@ -1228,6 +1268,42 @@ const GCInfo* HeapPage<Header>::findGCInfo(Address address)
|
| }
|
| #endif
|
|
|
| +#if GC_PROFILE_HEAP
|
| +template<typename Header>
|
| +void HeapPage<Header>::snapshot(TracedArrayBase* json, ThreadState::SnapshotInfo* info)
|
| +{
|
| + Header* header = 0;
|
| + for (Address addr = payload(); addr < end(); addr += header->size()) {
|
| + header = reinterpret_cast<Header*>(addr);
|
| + if (json)
|
| + json->pushInteger(header->encodedSize());
|
| + if (header->isFree()) {
|
| + info->freeSize += header->size();
|
| + continue;
|
| + }
|
| +
|
| + size_t tag = info->getClassTag(header->gcInfo());
|
| + size_t age = header->age();
|
| + if (json)
|
| + json->pushInteger(tag);
|
| + if (header->isMarked()) {
|
| + info->liveCount[tag] += 1;
|
| + info->liveSize += header->size();
|
| + // Count objects that are live when promoted to the final generation.
|
| + if (age == maxHeapObjectAge - 1)
|
| + info->generations[tag][maxHeapObjectAge] += 1;
|
| + header->incAge();
|
| + } else {
|
| + info->deadCount[tag] += 1;
|
| + info->deadSize += header->size();
|
| + // Count objects that are dead before the final generation.
|
| + if (age < maxHeapObjectAge)
|
| + info->generations[tag][age] += 1;
|
| + }
|
| + }
|
| +}
|
| +#endif
|
| +
|
| #if defined(ADDRESS_SANITIZER)
|
| template<typename Header>
|
| void HeapPage<Header>::poisonUnmarkedObjects()
|
| @@ -1289,6 +1365,37 @@ void LargeHeapObject<Header>::getStats(HeapStats& stats)
|
| stats.increaseObjectSpace(payloadSize());
|
| }
|
|
|
| +#if GC_PROFILE_HEAP
|
| +template<typename Header>
|
| +void LargeHeapObject<Header>::snapshot(TracedDictionaryBase* json, ThreadState::SnapshotInfo* info)
|
| +{
|
| + Header* header = heapObjectHeader();
|
| + size_t tag = info->getClassTag(header->gcInfo());
|
| + size_t age = header->age();
|
| + if (isMarked()) {
|
| + info->liveCount[tag] += 1;
|
| + info->liveSize += header->size();
|
| + // Count objects that are live when promoted to the final generation.
|
| + if (age == maxHeapObjectAge - 1)
|
| + info->generations[tag][maxHeapObjectAge] += 1;
|
| + header->incAge();
|
| + } else {
|
| + info->deadCount[tag] += 1;
|
| + info->deadSize += header->size();
|
| + // Count objects that are live when promoted to the final generation.
|
| + if (age == maxHeapObjectAge - 1)
|
| + info->generations[tag][maxHeapObjectAge] += 1;
|
| + header->incAge();
|
| + }
|
| +
|
| + if (json) {
|
| + json->setInteger("class", tag)
|
| + .setInteger("size", header->size())
|
| + .setInteger("isMarked", isMarked());
|
| + }
|
| +}
|
| +#endif
|
| +
|
| template<typename Entry>
|
| void HeapExtentCache<Entry>::flush()
|
| {
|
| @@ -1403,7 +1510,7 @@ bool CallbackStack::popAndInvokeCallback(CallbackStack** first, Visitor* visitor
|
| Item* item = --m_current;
|
|
|
| VisitorCallback callback = item->callback();
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| if (ThreadState::isAnyThreadInGC()) // weak-processing will also use popAndInvokeCallback
|
| visitor->setHostInfo(item->object(), classOf(item->object()));
|
| #endif
|
| @@ -1461,7 +1568,7 @@ bool CallbackStack::hasCallbackForObject(const void* object)
|
|
|
| class MarkingVisitor : public Visitor {
|
| public:
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| typedef HashSet<uintptr_t> LiveObjectSet;
|
| typedef HashMap<String, LiveObjectSet> LiveObjectMap;
|
| typedef HashMap<uintptr_t, std::pair<uintptr_t, String> > ObjectGraph;
|
| @@ -1474,7 +1581,7 @@ public:
|
| if (header->isMarked())
|
| return;
|
| header->mark();
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| MutexLocker locker(objectGraphMutex());
|
| String className(classOf(objectPointer));
|
| {
|
| @@ -1580,7 +1687,7 @@ public:
|
| FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS)
|
| #undef DEFINE_VISITOR_METHODS
|
|
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| void reportStats()
|
| {
|
| fprintf(stderr, "\n---------- AFTER MARKING -------------------\n");
|
| @@ -1758,12 +1865,14 @@ Address Heap::checkAndMarkPointer(Visitor* visitor, Address address)
|
| return 0;
|
| }
|
|
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| const GCInfo* Heap::findGCInfo(Address address)
|
| {
|
| return ThreadState::findGCInfoFromAllThreads(address);
|
| }
|
| +#endif
|
|
|
| +#if GC_PROFILE_MARKING
|
| void Heap::dumpPathToObjectOnNextGC(void* p)
|
| {
|
| static_cast<MarkingVisitor*>(s_markingVisitor)->dumpPathToObjectOnNextGC(p);
|
| @@ -1880,10 +1989,10 @@ void Heap::collectGarbage(ThreadState::StackState stackState)
|
| ScriptForbiddenScope forbiddenScope;
|
| s_lastGCWasConservative = false;
|
|
|
| - TRACE_EVENT0("blink", "Heap::collectGarbage");
|
| - TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "BlinkGC");
|
| + TRACE_EVENT0(GC_PROFILE_GROUP, "Heap::collectGarbage");
|
| + TRACE_EVENT_SCOPED_SAMPLING_STATE(GC_PROFILE_GROUP, "BlinkGC");
|
| double timeStamp = WTF::currentTimeMS();
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| static_cast<MarkingVisitor*>(s_markingVisitor)->objectGraph().clear();
|
| #endif
|
|
|
| @@ -1920,7 +2029,7 @@ void Heap::collectGarbage(ThreadState::StackState stackState)
|
| // callback phase, so the marking stack should still be empty here.
|
| ASSERT(s_markingStack->isEmpty());
|
|
|
| -#if ENABLE(GC_TRACING)
|
| +#if GC_PROFILE_MARKING
|
| static_cast<MarkingVisitor*>(s_markingVisitor)->reportStats();
|
| #endif
|
|
|
|
|