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:
Persistent(T* raw) : m_raw(raw)
{
ASSERT_IS_VALID_PERSISTENT_POINTER(m_raw);
recordBacktrace();
}
explicit Persistent(T& raw) : m_raw(&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>
Persistent(const Persistent<U, RootsAccessor>& other) : m_raw(other) { }
Persistent(const Persistent<U, RootsAccessor>& other) : m_raw(other) { recordBacktrace(); }
template<typename U>
Persistent(const Member<U>& other) : m_raw(other) { }
Persistent(const Member<U>& other) : m_raw(other) { recordBacktrace(); }
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>
Persistent& operator=(U* other)
{
m_raw = other;
recordBacktrace();
return *this;
}
......@@ -342,7 +345,7 @@ public:
{
COMPILE_ASSERT_IS_GARBAGE_COLLECTED(T, NonGarbageCollectedObjectInPersistent);
#if ENABLE(GC_TRACING)
visitor->setHostInfo(this, "Persistent");
visitor->setHostInfo(this, m_tracingName.isEmpty() ? "Persistent" : m_tracingName);
#endif
visitor->mark(m_raw);
}
......@@ -366,6 +369,7 @@ public:
Persistent& operator=(const Persistent& other)
{
m_raw = other;
recordBacktrace();
return *this;
}
......@@ -373,6 +377,7 @@ public:
Persistent& operator=(const Persistent<U, RootsAccessor>& other)
{
m_raw = other;
recordBacktrace();
return *this;
}
......@@ -380,6 +385,7 @@ public:
Persistent& operator=(const Member<U>& other)
{
m_raw = other;
recordBacktrace();
return *this;
}
......@@ -387,12 +393,24 @@ public:
Persistent& operator=(const RawPtr<U>& other)
{
m_raw = other;
recordBacktrace();
return *this;
}
T* get() const { return m_raw; }
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;
friend class CrossThreadPersistent<T>;
......@@ -425,7 +443,13 @@ public:
template<typename OtherCollection>
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<
......
......@@ -1472,10 +1472,12 @@ public:
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);
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()) {
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);
}
fprintf(stderr, "\n");
......@@ -1607,6 +1609,41 @@ void Heap::dumpPathToObjectOnNextGC(void* 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
void Heap::pushTraceCallback(void* object, TraceCallback callback)
......
......@@ -939,6 +939,8 @@ public:
// 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.
static const GCInfo* findGCInfo(Address);
static String createBacktraceString();
#endif
// Collect heap stats for all threads attached to the Blink
......
......@@ -262,24 +262,38 @@ void WTFReportBacktrace(int framesToShow)
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__))
Dl_info info;
if (dladdr(stack[i], &info) && info.dli_sname)
mangledName = info.dli_sname;
if (mangledName)
cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0);
Dl_info info;
if (!dladdr(addr, &info) || !info.dli_sname)
return;
const char* mangledName = info.dli_sname;
if ((m_cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0)))
m_name = m_cxaDemangled;
else
m_name = mangledName;
#else
(void)addr;
#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;
if (mangledName || cxaDemangled)
printf_stderr_common("%-3d %p %s\n", frameNumber, stack[i], cxaDemangled ? cxaDemangled : mangledName);
if (frameToName.nullableName())
printf_stderr_common("%-3d %p %s\n", frameNumber, stack[i], frameToName.nullableName());
else
printf_stderr_common("%-3d %p\n", frameNumber, stack[i]);
free(cxaDemangled);
}
}
......
......@@ -120,6 +120,23 @@ WTF_EXPORT void WTFInstallReportBacktraceOnCrashHook();
#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
/* 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