From b0fa94777ec70d92cbba236368220e0742fe76db Mon Sep 17 00:00:00 2001 From: "sgjesse@chromium.org" Date: Tue, 22 Feb 2011 10:05:30 +0000 Subject: [PATCH] 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 --- src/heap.cc | 179 +++++++++++++++++++++++++++++++++--------------------------- src/heap.h | 61 +++++++++++++++++++++ 2 files changed, 161 insertions(+), 79 deletions(-) diff --git a/src/heap.cc b/src/heap.cc index 90e83d8..b9104a8 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -5181,32 +5181,77 @@ void HeapIterator::reset() { } -#ifdef DEBUG +#if defined(DEBUG) || defined(LIVE_OBJECT_LIST) + +Object* const PathTracer::kAnyGlobalObject = reinterpret_cast(NULL); -static bool search_for_any_global; -static Object* search_target; -static bool found_target; -static List 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::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(HeapObject::cast(map)); @@ -5230,31 +5278,30 @@ static void MarkObjectRecursively(Object** p) { obj->set_map(reinterpret_cast(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(obj->address() + + Context::kHeaderSize); + Object** end = reinterpret_cast(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_p)); - UnmarkObjectRecursively(reinterpret_cast(&map_p)); + UnmarkRecursively(reinterpret_cast(&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 diff --git a/src/heap.h b/src/heap.h index a92770e..163eb04 100644 --- a/src/heap.h +++ b/src/heap.h @@ -30,6 +30,8 @@ #include +#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_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_ -- 2.7.4