Chromium Code Reviews| Index: src/heap/heap.cc |
| diff --git a/src/heap/heap.cc b/src/heap/heap.cc |
| index 0742aafc83913c1c3e4a46792ca6da2e415c2ebe..02cde2d7c7fca6a1b5d9a94e343a2d7da9a61c15 100644 |
| --- a/src/heap/heap.cc |
| +++ b/src/heap/heap.cc |
| @@ -166,6 +166,10 @@ Heap::Heap() |
| RememberUnmappedPage(NULL, false); |
| ClearObjectStats(true); |
| + |
| +#ifdef TRACE_RETAINING_PATH |
| + ClearRetainingInfo(); |
| +#endif |
| } |
| @@ -614,6 +618,10 @@ void Heap::GarbageCollectionEpilogue() { |
| } |
| #endif |
| +#ifdef TRACE_RETAINING_PATH |
| + ClearRetainingInfo(); |
| +#endif |
| + |
| AllowHeapAllocation for_the_rest_of_the_epilogue; |
| #ifdef DEBUG |
| @@ -5044,41 +5052,62 @@ void Heap::IterateSmiRoots(ObjectVisitor* v) { |
| } |
| +#ifdef TRACE_RETAINING_PATH |
| +#define TRACE_ROOT(root) SetCurrentRootRetainer(std::string(root)) |
| +#else |
| +#define TRACE_ROOT(root) |
| +#endif |
| + |
| + |
| void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { |
| + TRACE_ROOT("[strong root list]"); |
| v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]); |
| v->Synchronize(VisitorSynchronization::kStrongRootList); |
| + TRACE_ROOT("[internalized string]"); |
| v->VisitPointer(bit_cast<Object**>(&hidden_string_)); |
| v->Synchronize(VisitorSynchronization::kInternalizedString); |
| + TRACE_ROOT("[bootstrapper]"); |
| isolate_->bootstrapper()->Iterate(v); |
| v->Synchronize(VisitorSynchronization::kBootstrapper); |
| + |
| + TRACE_ROOT("[isolate threads]"); |
| isolate_->Iterate(v); |
| v->Synchronize(VisitorSynchronization::kTop); |
| + |
| + TRACE_ROOT("[isolate relocatable]"); |
| Relocatable::Iterate(isolate_, v); |
| v->Synchronize(VisitorSynchronization::kRelocatable); |
| + TRACE_ROOT("[deoptimizer data]"); |
| if (isolate_->deoptimizer_data() != NULL) { |
| isolate_->deoptimizer_data()->Iterate(v); |
| } |
| v->Synchronize(VisitorSynchronization::kDebug); |
| + |
| + TRACE_ROOT("[compilation cache]"); |
| isolate_->compilation_cache()->Iterate(v); |
| v->Synchronize(VisitorSynchronization::kCompilationCache); |
| // Iterate over local handles in handle scopes. |
| + TRACE_ROOT("[internal handles]"); |
| isolate_->handle_scope_implementer()->Iterate(v); |
| + TRACE_ROOT("[internal deferred handles]"); |
| isolate_->IterateDeferredHandles(v); |
| v->Synchronize(VisitorSynchronization::kHandleScope); |
| // Iterate over the builtin code objects and code stubs in the |
| // heap. Note that it is not necessary to iterate over code objects |
| // on scavenge collections. |
| + TRACE_ROOT("[builtins]"); |
| if (mode != VISIT_ALL_IN_SCAVENGE) { |
| isolate_->builtins()->IterateBuiltins(v); |
| } |
| v->Synchronize(VisitorSynchronization::kBuiltins); |
| // Iterate over global handles. |
| + TRACE_ROOT("[global handles]"); |
| switch (mode) { |
| case VISIT_ONLY_STRONG: |
| isolate_->global_handles()->IterateStrongRoots(v); |
| @@ -5094,6 +5123,7 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { |
| v->Synchronize(VisitorSynchronization::kGlobalHandles); |
| // Iterate over eternal handles. |
| + TRACE_ROOT("[eternal handles]"); |
| if (mode == VISIT_ALL_IN_SCAVENGE) { |
| isolate_->eternal_handles()->IterateNewSpaceRoots(v); |
| } else { |
| @@ -5101,6 +5131,7 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { |
| } |
| v->Synchronize(VisitorSynchronization::kEternalHandles); |
| + TRACE_ROOT("[isolate inactive threads]"); |
| // Iterate over pointers being held by inactive threads. |
| isolate_->thread_manager()->Iterate(v); |
| v->Synchronize(VisitorSynchronization::kThreadManager); |
| @@ -5113,11 +5144,13 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { |
| // serialization this does nothing, since the partial snapshot cache is |
| // empty. However the next thing we do is create the partial snapshot, |
| // filling up the partial snapshot cache with objects it needs as we go. |
| + TRACE_ROOT("[serializer/deserializer]"); |
| SerializerDeserializer::Iterate(isolate_, v); |
| // We don't do a v->Synchronize call here, because in debug mode that will |
| // output a flag to the snapshot. However at this point the serializer and |
| // deserializer are deliberately a little unsynchronized (see above) so the |
| // checking of the sync flag in the snapshot would fail. |
| + TRACE_ROOT("[]"); |
| } |
| @@ -5524,6 +5557,72 @@ void Heap::SetStackLimits() { |
| void Heap::NotifyDeserializationComplete() { deserialization_complete_ = true; } |
| +#ifdef TRACE_RETAINING_PATH |
| +void Heap::SetCurrentRetainer(HeapObject* obj) { current_retainer_ = obj; } |
| + |
| + |
| +void Heap::SetCurrentRootRetainer(std::string root) { |
| + current_root_retainer_ = root; |
| +} |
| + |
| + |
| +void Heap::PrintRetainingPath(HeapObject* obj, const char* comment) { |
| + PrintF("Retaining path for %s [%p]:\n", comment, static_cast<void*>(obj)); |
| + obj->ShortPrint(); |
| + PrintF("\n"); |
| + while (retainer_.count(obj) && retainer_[obj] != NULL) { |
| + PrintF("^^^^^^^^\n"); |
| + obj = retainer_[obj]; |
| +#ifdef OBJECT_PRINT |
| + obj->Print(); |
| +#else |
| + obj->ShortPrint(); |
| +#endif |
| + PrintF("\n"); |
| + } |
| + if (root_retainer_.count(obj)) { |
| + PrintF("^^^^^^^^\n"); |
| + PrintF("%s\n", root_retainer_[obj].c_str()); |
| + } |
| + PrintF("End of retaining path.\n"); |
| +} |
| + |
| + |
| +void Heap::AddRetainedObject(HeapObject* obj) { |
| + if (retainer_.count(obj)) return; |
| + retainer_[obj] = current_retainer_; |
| + if (current_retainer_ == NULL) { |
| + root_retainer_[obj] = current_root_retainer_; |
| + } |
| + const char* filter = FLAG_trace_retaining_path_for; |
| + if (obj->IsJSObject() && *filter != 0) { |
| + JSObject* jsobj = JSObject::cast(obj); |
| + String* name = jsobj->constructor_name(); |
| + if (!strcmp(filter, name->ToCString().get())) { |
| + PrintRetainingPath(obj, filter); |
| + } |
| + } |
| + if (FLAG_track_detached_contexts && obj->IsNativeContext()) { |
| + FixedArray* dc = detached_contexts(); |
| + int length = dc->length(); |
| + for (int i = 0; i < length; i += 2) { |
| + int mark_sweeps = Smi::cast(dc->get(i))->value(); |
| + if (mark_sweeps > 5 && WeakCell::cast(dc->get(i + 1))->value() == obj) { |
|
Hannes Payer (out of office)
2015/02/06 13:31:31
make 5 a constant
|
| + PrintRetainingPath(obj, "detached context"); |
| + } |
| + } |
| + } |
| +} |
| + |
| + |
| +void Heap::ClearRetainingInfo() { |
| + retainer_.clear(); |
| + root_retainer_.clear(); |
| + current_retainer_ = NULL; |
| + current_root_retainer_ = ""; |
| +} |
| +#endif |
| + |
|
Hannes Payer (out of office)
2015/02/06 13:31:32
+1 newline
|
| void Heap::TearDown() { |
| #ifdef VERIFY_HEAP |
| if (FLAG_verify_heap) { |