[heap] Remove Heap::TracePath* functions.
The functions do not work correctly with concurrent sweeper and they do not take weak references into account. The latter is a fundamental problem for this tracing approach. BUG= Review-Url: https://codereview.chromium.org/2707433002 Cr-Commit-Position: refs/heads/master@{#43284}
This commit is contained in:
parent
a84b23399e
commit
9e187ea91b
188
src/heap/heap.cc
188
src/heap/heap.cc
@ -6189,194 +6189,6 @@ HeapObject* HeapIterator::NextObject() {
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
Object* const PathTracer::kAnyGlobalObject = NULL;
|
||||
|
||||
class PathTracer::MarkVisitor : public ObjectVisitor {
|
||||
public:
|
||||
explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
|
||||
|
||||
void VisitPointers(Object** start, Object** end) override {
|
||||
// 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_;
|
||||
};
|
||||
|
||||
|
||||
class PathTracer::UnmarkVisitor : public ObjectVisitor {
|
||||
public:
|
||||
explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
|
||||
|
||||
void VisitPointers(Object** start, Object** end) override {
|
||||
// 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) {
|
||||
DCHECK((search_target_ == kAnyGlobalObject) ||
|
||||
search_target_->IsHeapObject());
|
||||
found_target_in_trace_ = false;
|
||||
Reset();
|
||||
|
||||
MarkVisitor mark_visitor(this);
|
||||
MarkRecursively(root, &mark_visitor);
|
||||
|
||||
UnmarkVisitor unmark_visitor(this);
|
||||
UnmarkRecursively(root, &unmark_visitor);
|
||||
|
||||
ProcessResults();
|
||||
}
|
||||
|
||||
|
||||
static bool SafeIsNativeContext(HeapObject* obj) {
|
||||
return obj->map() == obj->GetHeap()->root(Heap::kNativeContextMapRootIndex);
|
||||
}
|
||||
|
||||
|
||||
void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) {
|
||||
if (!(*p)->IsHeapObject()) return;
|
||||
|
||||
HeapObject* obj = HeapObject::cast(*p);
|
||||
|
||||
MapWord map_word = obj->map_word();
|
||||
if (!map_word.ToMap()->IsHeapObject()) return; // visited before
|
||||
|
||||
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_native_context = SafeIsNativeContext(obj);
|
||||
|
||||
// not visited yet
|
||||
Map* map = Map::cast(map_word.ToMap());
|
||||
|
||||
MapWord marked_map_word =
|
||||
MapWord::FromRawValue(obj->map_word().ToRawValue() + kMarkTag);
|
||||
obj->set_map_word(marked_map_word);
|
||||
|
||||
// Scan the object body.
|
||||
if (is_native_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->instance_type(), obj->SizeFromMap(map), mark_visitor);
|
||||
}
|
||||
|
||||
// Scan the map after the body because the body is a lot more interesting
|
||||
// when doing leak detection.
|
||||
MarkRecursively(reinterpret_cast<Object**>(&map), mark_visitor);
|
||||
|
||||
if (!found_target_in_trace_) { // don't pop if found the target
|
||||
object_stack_.RemoveLast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) {
|
||||
if (!(*p)->IsHeapObject()) return;
|
||||
|
||||
HeapObject* obj = HeapObject::cast(*p);
|
||||
|
||||
MapWord map_word = obj->map_word();
|
||||
if (map_word.ToMap()->IsHeapObject()) return; // unmarked already
|
||||
|
||||
MapWord unmarked_map_word =
|
||||
MapWord::FromRawValue(map_word.ToRawValue() - kMarkTag);
|
||||
obj->set_map_word(unmarked_map_word);
|
||||
|
||||
Map* map = Map::cast(unmarked_map_word.ToMap());
|
||||
|
||||
UnmarkRecursively(reinterpret_cast<Object**>(&map), unmark_visitor);
|
||||
|
||||
obj->IterateBody(map->instance_type(), obj->SizeFromMap(map), unmark_visitor);
|
||||
}
|
||||
|
||||
|
||||
void PathTracer::ProcessResults() {
|
||||
if (found_target_) {
|
||||
OFStream os(stdout);
|
||||
os << "=====================================\n"
|
||||
<< "==== Path to object ====\n"
|
||||
<< "=====================================\n\n";
|
||||
|
||||
DCHECK(!object_stack_.is_empty());
|
||||
for (int i = 0; i < object_stack_.length(); i++) {
|
||||
if (i > 0) os << "\n |\n |\n V\n\n";
|
||||
object_stack_[i]->Print(os);
|
||||
}
|
||||
os << "=====================================\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Triggers a depth-first traversal of reachable objects from one
|
||||
// given root object and finds a path to a specific heap object and
|
||||
// prints it.
|
||||
void Heap::TracePathToObjectFrom(Object* target, Object* root) {
|
||||
PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
|
||||
tracer.VisitPointer(&root);
|
||||
}
|
||||
|
||||
|
||||
// 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) {
|
||||
PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
|
||||
IterateRoots(&tracer, VISIT_ONLY_STRONG);
|
||||
}
|
||||
|
||||
|
||||
// Triggers a depth-first traversal of reachable objects from roots
|
||||
// and finds a path to any global object and prints it. Useful for
|
||||
// determining the source for leaks of global objects.
|
||||
void Heap::TracePathToGlobal() {
|
||||
PathTracer tracer(PathTracer::kAnyGlobalObject, PathTracer::FIND_ALL,
|
||||
VISIT_ALL);
|
||||
IterateRoots(&tracer, VISIT_ONLY_STRONG);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Heap::UpdateTotalGCTime(double duration) {
|
||||
if (FLAG_trace_gc_verbose) {
|
||||
total_gc_time_ms_ += duration;
|
||||
|
@ -1489,10 +1489,6 @@ class Heap {
|
||||
#ifdef DEBUG
|
||||
void set_allocation_timeout(int timeout) { allocation_timeout_ = timeout; }
|
||||
|
||||
void TracePathToObjectFrom(Object* target, Object* root);
|
||||
void TracePathToObject(Object* target);
|
||||
void TracePathToGlobal();
|
||||
|
||||
void Print();
|
||||
void PrintHandles();
|
||||
|
||||
|
@ -5497,18 +5497,6 @@ TEST(RegressArrayListGC) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
TEST(PathTracer) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
v8::Local<v8::Value> result = CompileRun("'abc'");
|
||||
Handle<Object> o = v8::Utils::OpenHandle(*result);
|
||||
CcTest::i_isolate()->heap()->TracePathToObject(*o);
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
TEST(WritableVsImmortalRoots) {
|
||||
for (int i = 0; i < Heap::kStrongRootListLength; ++i) {
|
||||
Heap::RootListIndex root_index = static_cast<Heap::RootListIndex>(i);
|
||||
|
@ -13701,9 +13701,6 @@ static void CheckSurvivingGlobalObjectsCount(int expected) {
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
CcTest::CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
|
||||
int count = GetGlobalObjectsCount();
|
||||
#ifdef DEBUG
|
||||
if (count != expected) CcTest::heap()->TracePathToGlobal();
|
||||
#endif
|
||||
CHECK_EQ(expected, count);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user