| Index: src/heap.cc
|
| ===================================================================
|
| --- src/heap.cc (revision 6872)
|
| +++ src/heap.cc (working copy)
|
| @@ -5181,32 +5181,60 @@
|
| }
|
|
|
|
|
| -#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);
|
| +class PathTracer::MarkVisitor: public ObjectVisitor {
|
| + public:
|
| + explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
|
| + void VisitPointers(Object** start, Object** end) {
|
| + // Scan all HeapObject pointers in [start, end)
|
| + for (Object** p = start; !tracer_->found() && (p < end); p++) {
|
| + if ((*p)->IsHeapObject())
|
| + tracer_->MarkRecursively(p, this);
|
| + }
|
| + }
|
|
|
| + private:
|
| + PathTracer* tracer_;
|
| +};
|
|
|
| -// 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::UnmarkVisitor: public ObjectVisitor {
|
| public:
|
| + explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
|
| void VisitPointers(Object** start, Object** end) {
|
| - // Copy all HeapObject pointers in [start, end)
|
| + // Scan all HeapObject pointers in [start, end)
|
| for (Object** p = start; p < end; p++) {
|
| if ((*p)->IsHeapObject())
|
| - MarkObjectRecursively(p);
|
| + tracer_->UnmarkRecursively(p, this);
|
| }
|
| }
|
| +
|
| + private:
|
| + PathTracer* tracer_;
|
| };
|
|
|
| -static MarkObjectVisitor mark_visitor;
|
|
|
| -static void MarkObjectRecursively(Object** p) {
|
| +void PathTracer::TracePathFrom(Object** root) {
|
| + if (search_for_any_global_) {
|
| + ASSERT(search_target_ == NULL);
|
| + } else {
|
| + ASSERT(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 +5243,17 @@
|
|
|
| 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_for_any_global_ && obj->IsJSGlobalObject()) ||
|
| + (!search_for_any_global_ && (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 +5261,30 @@
|
|
|
| obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag));
|
|
|
| - MarkObjectRecursively(&map);
|
| + // Scan the object body.
|
| + if (is_global_context && skip_weak_refs_) {
|
| + // 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 +5303,38 @@
|
|
|
| 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, false, PathTracer::FIND_ALL, false);
|
| + IterateRoots(&tracer, VISIT_ONLY_STRONG);
|
| }
|
|
|
|
|
| @@ -5337,11 +5342,8 @@
|
| // 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(NULL, true, PathTracer::FIND_ALL, false);
|
| + IterateRoots(&tracer, VISIT_ONLY_STRONG);
|
| }
|
| #endif
|
|
|
|
|