Index: src/heap.cc |
=================================================================== |
--- src/heap.cc (revision 6875) |
+++ src/heap.cc (working copy) |
@@ -5181,32 +5181,77 @@ |
} |
-#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); |
+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); |
+ } |
+ } |
-// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject. |
-static const int kMarkTag = 2; |
+ private: |
+ PathTracer* tracer_; |
+}; |
-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::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 @@ |
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 @@ |
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 @@ |
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 @@ |
// 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 |