Refactored PathTracer in heap.cc.
This is so that it can be reused by LOL code later. Patch by Mark Lam from Hewlett-Packard Development Company, LP Review URL: http://codereview.chromium.org/6541044 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6886 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
2ab5691ac1
commit
b0fa94777e
185
src/heap.cc
185
src/heap.cc
@ -5181,32 +5181,77 @@ void HeapIterator::reset() {
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
|
||||
|
||||
static bool search_for_any_global;
|
||||
static Object* search_target;
|
||||
static bool found_target;
|
||||
static List<Object*> object_stack(20);
|
||||
Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL);
|
||||
|
||||
|
||||
// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject.
|
||||
static const int kMarkTag = 2;
|
||||
|
||||
static void MarkObjectRecursively(Object** p);
|
||||
class MarkObjectVisitor : public ObjectVisitor {
|
||||
class PathTracer::MarkVisitor: public ObjectVisitor {
|
||||
public:
|
||||
explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
|
||||
void VisitPointers(Object** start, Object** end) {
|
||||
// Copy all HeapObject pointers in [start, end)
|
||||
for (Object** p = start; p < end; p++) {
|
||||
// Scan all HeapObject pointers in [start, end)
|
||||
for (Object** p = start; !tracer_->found() && (p < end); p++) {
|
||||
if ((*p)->IsHeapObject())
|
||||
MarkObjectRecursively(p);
|
||||
tracer_->MarkRecursively(p, this);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PathTracer* tracer_;
|
||||
};
|
||||
|
||||
static MarkObjectVisitor mark_visitor;
|
||||
|
||||
static void MarkObjectRecursively(Object** p) {
|
||||
class PathTracer::UnmarkVisitor: public ObjectVisitor {
|
||||
public:
|
||||
explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
|
||||
void VisitPointers(Object** start, Object** end) {
|
||||
// Scan all HeapObject pointers in [start, end)
|
||||
for (Object** p = start; p < end; p++) {
|
||||
if ((*p)->IsHeapObject())
|
||||
tracer_->UnmarkRecursively(p, this);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PathTracer* tracer_;
|
||||
};
|
||||
|
||||
|
||||
void PathTracer::VisitPointers(Object** start, Object** end) {
|
||||
bool done = ((what_to_find_ == FIND_FIRST) && found_target_);
|
||||
// Visit all HeapObject pointers in [start, end)
|
||||
for (Object** p = start; !done && (p < end); p++) {
|
||||
if ((*p)->IsHeapObject()) {
|
||||
TracePathFrom(p);
|
||||
done = ((what_to_find_ == FIND_FIRST) && found_target_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PathTracer::Reset() {
|
||||
found_target_ = false;
|
||||
object_stack_.Clear();
|
||||
}
|
||||
|
||||
|
||||
void PathTracer::TracePathFrom(Object** root) {
|
||||
ASSERT((search_target_ == kAnyGlobalObject) ||
|
||||
search_target_->IsHeapObject());
|
||||
found_target_in_trace_ = false;
|
||||
object_stack_.Clear();
|
||||
|
||||
MarkVisitor mark_visitor(this);
|
||||
MarkRecursively(root, &mark_visitor);
|
||||
|
||||
UnmarkVisitor unmark_visitor(this);
|
||||
UnmarkRecursively(root, &unmark_visitor);
|
||||
|
||||
ProcessResults();
|
||||
}
|
||||
|
||||
|
||||
void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) {
|
||||
if (!(*p)->IsHeapObject()) return;
|
||||
|
||||
HeapObject* obj = HeapObject::cast(*p);
|
||||
@ -5215,14 +5260,17 @@ static void MarkObjectRecursively(Object** p) {
|
||||
|
||||
if (!map->IsHeapObject()) return; // visited before
|
||||
|
||||
if (found_target) return; // stop if target found
|
||||
object_stack.Add(obj);
|
||||
if ((search_for_any_global && obj->IsJSGlobalObject()) ||
|
||||
(!search_for_any_global && (obj == search_target))) {
|
||||
found_target = true;
|
||||
if (found_target_in_trace_) return; // stop if target found
|
||||
object_stack_.Add(obj);
|
||||
if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) ||
|
||||
(obj == search_target_)) {
|
||||
found_target_in_trace_ = true;
|
||||
found_target_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_global_context = obj->IsGlobalContext();
|
||||
|
||||
// not visited yet
|
||||
Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
|
||||
|
||||
@ -5230,31 +5278,30 @@ static void MarkObjectRecursively(Object** p) {
|
||||
|
||||
obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag));
|
||||
|
||||
MarkObjectRecursively(&map);
|
||||
// Scan the object body.
|
||||
if (is_global_context && (visit_mode_ == VISIT_ONLY_STRONG)) {
|
||||
// This is specialized to scan Context's properly.
|
||||
Object** start = reinterpret_cast<Object**>(obj->address() +
|
||||
Context::kHeaderSize);
|
||||
Object** end = reinterpret_cast<Object**>(obj->address() +
|
||||
Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize);
|
||||
mark_visitor->VisitPointers(start, end);
|
||||
} else {
|
||||
obj->IterateBody(map_p->instance_type(),
|
||||
obj->SizeFromMap(map_p),
|
||||
mark_visitor);
|
||||
}
|
||||
|
||||
obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p),
|
||||
&mark_visitor);
|
||||
// Scan the map after the body because the body is a lot more interesting
|
||||
// when doing leak detection.
|
||||
MarkRecursively(&map, mark_visitor);
|
||||
|
||||
if (!found_target) // don't pop if found the target
|
||||
object_stack.RemoveLast();
|
||||
if (!found_target_in_trace_) // don't pop if found the target
|
||||
object_stack_.RemoveLast();
|
||||
}
|
||||
|
||||
|
||||
static void UnmarkObjectRecursively(Object** p);
|
||||
class UnmarkObjectVisitor : public ObjectVisitor {
|
||||
public:
|
||||
void VisitPointers(Object** start, Object** end) {
|
||||
// Copy all HeapObject pointers in [start, end)
|
||||
for (Object** p = start; p < end; p++) {
|
||||
if ((*p)->IsHeapObject())
|
||||
UnmarkObjectRecursively(p);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static UnmarkObjectVisitor unmark_visitor;
|
||||
|
||||
static void UnmarkObjectRecursively(Object** p) {
|
||||
void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) {
|
||||
if (!(*p)->IsHeapObject()) return;
|
||||
|
||||
HeapObject* obj = HeapObject::cast(*p);
|
||||
@ -5273,63 +5320,38 @@ static void UnmarkObjectRecursively(Object** p) {
|
||||
|
||||
obj->set_map(reinterpret_cast<Map*>(map_p));
|
||||
|
||||
UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p));
|
||||
UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor);
|
||||
|
||||
obj->IterateBody(Map::cast(map_p)->instance_type(),
|
||||
obj->SizeFromMap(Map::cast(map_p)),
|
||||
&unmark_visitor);
|
||||
unmark_visitor);
|
||||
}
|
||||
|
||||
|
||||
static void MarkRootObjectRecursively(Object** root) {
|
||||
if (search_for_any_global) {
|
||||
ASSERT(search_target == NULL);
|
||||
} else {
|
||||
ASSERT(search_target->IsHeapObject());
|
||||
}
|
||||
found_target = false;
|
||||
object_stack.Clear();
|
||||
|
||||
MarkObjectRecursively(root);
|
||||
UnmarkObjectRecursively(root);
|
||||
|
||||
if (found_target) {
|
||||
void PathTracer::ProcessResults() {
|
||||
if (found_target_) {
|
||||
PrintF("=====================================\n");
|
||||
PrintF("==== Path to object ====\n");
|
||||
PrintF("=====================================\n\n");
|
||||
|
||||
ASSERT(!object_stack.is_empty());
|
||||
for (int i = 0; i < object_stack.length(); i++) {
|
||||
ASSERT(!object_stack_.is_empty());
|
||||
for (int i = 0; i < object_stack_.length(); i++) {
|
||||
if (i > 0) PrintF("\n |\n |\n V\n\n");
|
||||
Object* obj = object_stack[i];
|
||||
Object* obj = object_stack_[i];
|
||||
obj->Print();
|
||||
}
|
||||
PrintF("=====================================\n");
|
||||
}
|
||||
}
|
||||
#endif // DEBUG || LIVE_OBJECT_LIST
|
||||
|
||||
|
||||
// Helper class for visiting HeapObjects recursively.
|
||||
class MarkRootVisitor: public ObjectVisitor {
|
||||
public:
|
||||
void VisitPointers(Object** start, Object** end) {
|
||||
// Visit all HeapObject pointers in [start, end)
|
||||
for (Object** p = start; p < end; p++) {
|
||||
if ((*p)->IsHeapObject())
|
||||
MarkRootObjectRecursively(p);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
// Triggers a depth-first traversal of reachable objects from roots
|
||||
// and finds a path to a specific heap object and prints it.
|
||||
void Heap::TracePathToObject(Object* target) {
|
||||
search_target = target;
|
||||
search_for_any_global = false;
|
||||
|
||||
MarkRootVisitor root_visitor;
|
||||
IterateRoots(&root_visitor, VISIT_ONLY_STRONG);
|
||||
PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
|
||||
IterateRoots(&tracer, VISIT_ONLY_STRONG);
|
||||
}
|
||||
|
||||
|
||||
@ -5337,11 +5359,10 @@ void Heap::TracePathToObject(Object* target) {
|
||||
// and finds a path to any global object and prints it. Useful for
|
||||
// determining the source for leaks of global objects.
|
||||
void Heap::TracePathToGlobal() {
|
||||
search_target = NULL;
|
||||
search_for_any_global = true;
|
||||
|
||||
MarkRootVisitor root_visitor;
|
||||
IterateRoots(&root_visitor, VISIT_ONLY_STRONG);
|
||||
PathTracer tracer(PathTracer::kAnyGlobalObject,
|
||||
PathTracer::FIND_ALL,
|
||||
VISIT_ALL);
|
||||
IterateRoots(&tracer, VISIT_ONLY_STRONG);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
61
src/heap.h
61
src/heap.h
@ -30,6 +30,8 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "list.h"
|
||||
#include "spaces.h"
|
||||
#include "splay-tree-inl.h"
|
||||
#include "v8-counters.h"
|
||||
@ -2152,6 +2154,65 @@ class WeakObjectRetainer {
|
||||
};
|
||||
|
||||
|
||||
#if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
|
||||
// Helper class for tracing paths to a search target Object from all roots.
|
||||
// The TracePathFrom() method can be used to trace paths from a specific
|
||||
// object to the search target object.
|
||||
class PathTracer : public ObjectVisitor {
|
||||
public:
|
||||
enum WhatToFind {
|
||||
FIND_ALL, // Will find all matches.
|
||||
FIND_FIRST // Will stop the search after first match.
|
||||
};
|
||||
|
||||
// For the WhatToFind arg, if FIND_FIRST is specified, tracing will stop
|
||||
// after the first match. If FIND_ALL is specified, then tracing will be
|
||||
// done for all matches.
|
||||
PathTracer(Object* search_target,
|
||||
WhatToFind what_to_find,
|
||||
VisitMode visit_mode)
|
||||
: search_target_(search_target),
|
||||
found_target_(false),
|
||||
found_target_in_trace_(false),
|
||||
what_to_find_(what_to_find),
|
||||
visit_mode_(visit_mode),
|
||||
object_stack_(20),
|
||||
no_alloc() {}
|
||||
|
||||
virtual void VisitPointers(Object** start, Object** end);
|
||||
|
||||
void Reset();
|
||||
void TracePathFrom(Object** root);
|
||||
|
||||
bool found() const { return found_target_; }
|
||||
|
||||
static Object* const kAnyGlobalObject;
|
||||
|
||||
protected:
|
||||
class MarkVisitor;
|
||||
class UnmarkVisitor;
|
||||
|
||||
void MarkRecursively(Object** p, MarkVisitor* mark_visitor);
|
||||
void UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor);
|
||||
virtual void ProcessResults();
|
||||
|
||||
// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject.
|
||||
static const int kMarkTag = 2;
|
||||
|
||||
Object* search_target_;
|
||||
bool found_target_;
|
||||
bool found_target_in_trace_;
|
||||
WhatToFind what_to_find_;
|
||||
VisitMode visit_mode_;
|
||||
List<Object*> object_stack_;
|
||||
|
||||
AssertNoAllocation no_alloc; // i.e. no gc allowed.
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PathTracer);
|
||||
};
|
||||
#endif // DEBUG || LIVE_OBJECT_LIST
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_HEAP_H_
|
||||
|
Loading…
Reference in New Issue
Block a user