Commit 49f003e1 authored by tkent@chromium.org's avatar tkent@chromium.org

Oilpan: GC_TRACING: Improve object path dump

We frequently saw object path dump like:

    Path to 1d6ec5d8 of WebCore::Node
    <- 7abc4660 of Persistent

Then, we needed to investigate what this Persistent is. It took much time.

This CL introduces 'tracing name' property to Persistent if
ENABLE(GC_TRACING). The property is automatically filled with
backtrace of a Persistent constructor. We'll get dump like:

    Path to 1bd56220 of WebCore::Node
    <- 1bd55ff8 of WebCore::Node
    <- 1bd55dc8 of WebCore::Node
    <- 7d046600 of Persistent ... Backtrace:
            Persistent<HTMLSelectElement, ThreadLocalPersistents<(ThreadAffinity)1> >::Persistent(HTMLSelectElement*)
            v8::Handle<v8::Object> V8DOMWrapper::associateObjectWithWrapper<V8HTMLSelectElement, HTMLSelectElement>(HTMLSelectElement*, WrapperTypeInfo const*, v8::Handle<v8::Object>, v8::Isolate*, WrapperConfiguration::Lifetime)
            v8::Handle<v8::Object> V8DOMWrapper::associateObjectWithWrapper<V8HTMLSelectElement, HTMLSelectElement>(WTF::RawPtr<HTMLSelectElement>, WrapperTypeInfo const*, v8::Handle<v8::Object>, v8::Isolate*, WrapperConfiguration::Lifetime)
            V8HTMLSelectElement::createWrapper(WTF::RawPtr<HTMLSelectElement>, v8::Handle<v8::Object>, v8::Isolate*)

Additional improvement of the object path dump:
* Correct host info name for heap collections
* Don't try to dump unknown objects.

BUG=

Review URL: https://codereview.chromium.org/337653002

git-svn-id: svn://svn.chromium.org/blink/trunk@176185 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 613f996b
...@@ -294,28 +294,31 @@ public: ...@@ -294,28 +294,31 @@ public:
Persistent(T* raw) : m_raw(raw) Persistent(T* raw) : m_raw(raw)
{ {
ASSERT_IS_VALID_PERSISTENT_POINTER(m_raw); ASSERT_IS_VALID_PERSISTENT_POINTER(m_raw);
recordBacktrace();
} }
explicit Persistent(T& raw) : m_raw(&raw) explicit Persistent(T& raw) : m_raw(&raw)
{ {
ASSERT_IS_VALID_PERSISTENT_POINTER(m_raw); ASSERT_IS_VALID_PERSISTENT_POINTER(m_raw);
recordBacktrace();
} }
Persistent(const Persistent& other) : m_raw(other) { } Persistent(const Persistent& other) : m_raw(other) { recordBacktrace(); }
template<typename U> template<typename U>
Persistent(const Persistent<U, RootsAccessor>& other) : m_raw(other) { } Persistent(const Persistent<U, RootsAccessor>& other) : m_raw(other) { recordBacktrace(); }
template<typename U> template<typename U>
Persistent(const Member<U>& other) : m_raw(other) { } Persistent(const Member<U>& other) : m_raw(other) { recordBacktrace(); }
template<typename U> template<typename U>
Persistent(const RawPtr<U>& other) : m_raw(other.get()) { } Persistent(const RawPtr<U>& other) : m_raw(other.get()) { recordBacktrace(); }
template<typename U> template<typename U>
Persistent& operator=(U* other) Persistent& operator=(U* other)
{ {
m_raw = other; m_raw = other;
recordBacktrace();
return *this; return *this;
} }
...@@ -342,7 +345,7 @@ public: ...@@ -342,7 +345,7 @@ public:
{ {
COMPILE_ASSERT_IS_GARBAGE_COLLECTED(T, NonGarbageCollectedObjectInPersistent); COMPILE_ASSERT_IS_GARBAGE_COLLECTED(T, NonGarbageCollectedObjectInPersistent);
#if ENABLE(GC_TRACING) #if ENABLE(GC_TRACING)
visitor->setHostInfo(this, "Persistent"); visitor->setHostInfo(this, m_tracingName.isEmpty() ? "Persistent" : m_tracingName);
#endif #endif
visitor->mark(m_raw); visitor->mark(m_raw);
} }
...@@ -366,6 +369,7 @@ public: ...@@ -366,6 +369,7 @@ public:
Persistent& operator=(const Persistent& other) Persistent& operator=(const Persistent& other)
{ {
m_raw = other; m_raw = other;
recordBacktrace();
return *this; return *this;
} }
...@@ -373,6 +377,7 @@ public: ...@@ -373,6 +377,7 @@ public:
Persistent& operator=(const Persistent<U, RootsAccessor>& other) Persistent& operator=(const Persistent<U, RootsAccessor>& other)
{ {
m_raw = other; m_raw = other;
recordBacktrace();
return *this; return *this;
} }
...@@ -380,6 +385,7 @@ public: ...@@ -380,6 +385,7 @@ public:
Persistent& operator=(const Member<U>& other) Persistent& operator=(const Member<U>& other)
{ {
m_raw = other; m_raw = other;
recordBacktrace();
return *this; return *this;
} }
...@@ -387,12 +393,24 @@ public: ...@@ -387,12 +393,24 @@ public:
Persistent& operator=(const RawPtr<U>& other) Persistent& operator=(const RawPtr<U>& other)
{ {
m_raw = other; m_raw = other;
recordBacktrace();
return *this; return *this;
} }
T* get() const { return m_raw; } T* get() const { return m_raw; }
private: private:
#if ENABLE(GC_TRACING)
void recordBacktrace()
{
if (m_raw)
m_tracingName = Heap::createBacktraceString();
}
String m_tracingName;
#else
inline void recordBacktrace() const { }
#endif
T* m_raw; T* m_raw;
friend class CrossThreadPersistent<T>; friend class CrossThreadPersistent<T>;
...@@ -425,7 +443,13 @@ public: ...@@ -425,7 +443,13 @@ public:
template<typename OtherCollection> template<typename OtherCollection>
PersistentHeapCollectionBase(const OtherCollection& other) : Collection(other) { } PersistentHeapCollectionBase(const OtherCollection& other) : Collection(other) { }
void trace(Visitor* visitor) { visitor->trace(*static_cast<Collection*>(this)); } void trace(Visitor* visitor)
{
#if ENABLE(GC_TRACING)
visitor->setHostInfo(this, "PersistentHeapCollectionBase");
#endif
visitor->trace(*static_cast<Collection*>(this));
}
}; };
template< template<
......
...@@ -1472,10 +1472,12 @@ public: ...@@ -1472,10 +1472,12 @@ public:
static void dumpPathToObjectFromObjectGraph(const ObjectGraph& graph, uintptr_t target) static void dumpPathToObjectFromObjectGraph(const ObjectGraph& graph, uintptr_t target)
{ {
fprintf(stderr, "Path to %lx of %s\n", target, classOf(reinterpret_cast<const void*>(target)).ascii().data());
ObjectGraph::const_iterator it = graph.find(target); ObjectGraph::const_iterator it = graph.find(target);
if (it == graph.end())
return;
fprintf(stderr, "Path to %lx of %s\n", target, classOf(reinterpret_cast<const void*>(target)).ascii().data());
while (it != graph.end()) { while (it != graph.end()) {
fprintf(stderr, "<- %lx of %s\n", it->value.first, it->value.second.ascii().data()); fprintf(stderr, "<- %lx of %s\n", it->value.first, it->value.second.utf8().data());
it = graph.find(it->value.first); it = graph.find(it->value.first);
} }
fprintf(stderr, "\n"); fprintf(stderr, "\n");
...@@ -1607,6 +1609,41 @@ void Heap::dumpPathToObjectOnNextGC(void* p) ...@@ -1607,6 +1609,41 @@ void Heap::dumpPathToObjectOnNextGC(void* p)
{ {
static_cast<MarkingVisitor*>(s_markingVisitor)->dumpPathToObjectOnNextGC(p); static_cast<MarkingVisitor*>(s_markingVisitor)->dumpPathToObjectOnNextGC(p);
} }
String Heap::createBacktraceString()
{
int framesToShow = 3;
int stackFrameSize = 16;
ASSERT(stackFrameSize >= framesToShow);
typedef void* FramePointer;
FramePointer* stackFrame = static_cast<FramePointer*>(alloca(sizeof(FramePointer) * stackFrameSize));
WTFGetBacktrace(stackFrame, &stackFrameSize);
StringBuilder builder;
builder.append("Persistent");
bool didAppendFirstName = false;
// Skip frames before/including "WebCore::Persistent".
bool didSeePersistent = false;
for (int i = 0; i < stackFrameSize && framesToShow > 0; ++i) {
FrameToNameScope frameToName(stackFrame[i]);
if (!frameToName.nullableName())
continue;
if (strstr(frameToName.nullableName(), "WebCore::Persistent")) {
didSeePersistent = true;
continue;
}
if (!didSeePersistent)
continue;
if (!didAppendFirstName) {
didAppendFirstName = true;
builder.append(" ... Backtrace:");
}
builder.append("\n\t");
builder.append(frameToName.nullableName());
--framesToShow;
}
return builder.toString().replace("WebCore::", "");
}
#endif #endif
void Heap::pushTraceCallback(void* object, TraceCallback callback) void Heap::pushTraceCallback(void* object, TraceCallback callback)
......
...@@ -939,6 +939,8 @@ public: ...@@ -939,6 +939,8 @@ public:
// This is slow and should only be used for debug purposes. // This is slow and should only be used for debug purposes.
// It involves finding the heap page and scanning the heap page for an object header. // It involves finding the heap page and scanning the heap page for an object header.
static const GCInfo* findGCInfo(Address); static const GCInfo* findGCInfo(Address);
static String createBacktraceString();
#endif #endif
// Collect heap stats for all threads attached to the Blink // Collect heap stats for all threads attached to the Blink
......
...@@ -262,24 +262,38 @@ void WTFReportBacktrace(int framesToShow) ...@@ -262,24 +262,38 @@ void WTFReportBacktrace(int framesToShow)
WTFPrintBacktrace(samples + framesToSkip, frames - framesToSkip); WTFPrintBacktrace(samples + framesToSkip, frames - framesToSkip);
} }
void WTFPrintBacktrace(void** stack, int size) FrameToNameScope::FrameToNameScope(void* addr)
: m_name(0)
, m_cxaDemangled(0)
{ {
for (int i = 0; i < size; ++i) {
const char* mangledName = 0;
char* cxaDemangled = 0;
#if OS(MACOSX) || (OS(LINUX) && !defined(__UCLIBC__)) #if OS(MACOSX) || (OS(LINUX) && !defined(__UCLIBC__))
Dl_info info; Dl_info info;
if (dladdr(stack[i], &info) && info.dli_sname) if (!dladdr(addr, &info) || !info.dli_sname)
mangledName = info.dli_sname; return;
if (mangledName) const char* mangledName = info.dli_sname;
cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0); if ((m_cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0)))
m_name = m_cxaDemangled;
else
m_name = mangledName;
#else
(void)addr;
#endif #endif
}
FrameToNameScope::~FrameToNameScope()
{
free(m_cxaDemangled);
}
void WTFPrintBacktrace(void** stack, int size)
{
for (int i = 0; i < size; ++i) {
FrameToNameScope frameToName(stack[i]);
const int frameNumber = i + 1; const int frameNumber = i + 1;
if (mangledName || cxaDemangled) if (frameToName.nullableName())
printf_stderr_common("%-3d %p %s\n", frameNumber, stack[i], cxaDemangled ? cxaDemangled : mangledName); printf_stderr_common("%-3d %p %s\n", frameNumber, stack[i], frameToName.nullableName());
else else
printf_stderr_common("%-3d %p\n", frameNumber, stack[i]); printf_stderr_common("%-3d %p\n", frameNumber, stack[i]);
free(cxaDemangled);
} }
} }
......
...@@ -120,6 +120,23 @@ WTF_EXPORT void WTFInstallReportBacktraceOnCrashHook(); ...@@ -120,6 +120,23 @@ WTF_EXPORT void WTFInstallReportBacktraceOnCrashHook();
#ifdef __cplusplus #ifdef __cplusplus
} }
namespace WTF {
class WTF_EXPORT FrameToNameScope {
public:
explicit FrameToNameScope(void*);
~FrameToNameScope();
const char* nullableName() { return m_name; }
private:
const char* m_name;
char* m_cxaDemangled;
};
} // namespace WTF
using WTF::FrameToNameScope;
#endif #endif
/* IMMEDIATE_CRASH() - Like CRASH() below but crashes in the fastest, simplest possible way with no attempt at logging. */ /* IMMEDIATE_CRASH() - Like CRASH() below but crashes in the fastest, simplest possible way with no attempt at logging. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment