Chromium Code Reviews| Index: src/profile-generator.cc |
| diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
| index 9a205a4c52c0a7c92b54ceac902e1cbc226a9f08..384442ce3c7bbb909ab82b7060900b4202db6a63 100644 |
| --- a/src/profile-generator.cc |
| +++ b/src/profile-generator.cc |
| @@ -957,11 +957,6 @@ void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { |
| } |
| -HeapEntry* HeapGraphEdge::From() { |
| - return reinterpret_cast<HeapEntry*>(this - child_index_) - 1; |
| -} |
| - |
| - |
| void HeapEntry::Init(HeapSnapshot* snapshot, |
| Type type, |
| const char* name, |
| @@ -972,6 +967,7 @@ void HeapEntry::Init(HeapSnapshot* snapshot, |
| snapshot_ = snapshot; |
| type_ = type; |
| painted_ = false; |
| + reachable_from_window_ = false; |
| name_ = name; |
| self_size_ = self_size; |
| retained_size_ = 0; |
| @@ -2018,7 +2014,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| // We use JSGlobalProxy because this is what embedder (e.g. browser) |
| // uses for the global object. |
| JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); |
| - SetRootShortcutReference(proxy->map()->prototype()); |
| + SetWindowReference(proxy->map()->prototype()); |
| } else if (obj->IsJSObject()) { |
| JSObject* js_obj = JSObject::cast(obj); |
| ExtractClosureReferences(js_obj, entry); |
| @@ -2286,15 +2282,15 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, |
| Object* k = dictionary->KeyAt(i); |
| if (dictionary->IsKey(k)) { |
| Object* target = dictionary->ValueAt(i); |
| - SetPropertyReference( |
| - js_obj, entry, String::cast(k), target); |
| // We assume that global objects can only have slow properties. |
| - if (target->IsJSGlobalPropertyCell()) { |
| - SetPropertyShortcutReference(js_obj, |
| - entry, |
| - String::cast(k), |
| - JSGlobalPropertyCell::cast( |
| - target)->value()); |
| + Object* value = target->IsJSGlobalPropertyCell() |
| + ? JSGlobalPropertyCell::cast(target)->value() |
| + : target; |
| + if (String::cast(k)->length() > 0) { |
| + SetPropertyReference(js_obj, entry, String::cast(k), value); |
| + } else { |
| + TagObject(value, "(hidden properties)"); |
| + SetInternalReference(js_obj, entry, "hidden_properties", value); |
| } |
| } |
| } |
| @@ -2663,7 +2659,7 @@ void V8HeapExplorer::SetRootGcRootsReference() { |
| } |
| -void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) { |
| +void V8HeapExplorer::SetWindowReference(Object* child_obj) { |
| HeapEntry* child_entry = GetEntry(child_obj); |
| ASSERT(child_entry != NULL); |
| filler_->SetNamedAutoIndexReference( |
| @@ -2745,7 +2741,7 @@ void V8HeapExplorer::TagGlobalObjects() { |
| Handle<JSGlobalObject> global_obj = enumerator.at(i); |
| Object* obj_document; |
| if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && |
| - obj_document->IsJSObject()) { |
| + obj_document->IsJSObject()) { |
| JSObject* document = JSObject::cast(obj_document); |
| Object* obj_url; |
| if (document->GetProperty(*url_string)->ToObject(&obj_url) && |
| @@ -3299,19 +3295,61 @@ bool HeapSnapshotGenerator::FillReferences() { |
| } |
| -void HeapSnapshotGenerator::FillReversePostorderIndexes( |
| +bool HeapSnapshotGenerator::IsWindowReference(const HeapGraphEdge& edge) { |
| + ASSERT(edge.from() == snapshot_->root()); |
| + return edge.type() == HeapGraphEdge::kShortcut; |
| +} |
| + |
| + |
| +void HeapSnapshotGenerator::MarkWindowReachableObjects() { |
| + List<HeapEntry*> worklist; |
| + |
| + Vector<HeapGraphEdge> children = snapshot_->root()->children(); |
| + for (int i = 0; i < children.length(); ++i) { |
| + if (IsWindowReference(children[i])) { |
| + worklist.Add(children[i].to()); |
| + } |
| + } |
| + |
| + while (!worklist.is_empty()) { |
| + HeapEntry* entry = worklist.RemoveLast(); |
| + if (entry->reachable_from_window()) continue; |
| + entry->set_reachable_from_window(); |
| + Vector<HeapGraphEdge> children = entry->children(); |
| + for (int i = 0; i < children.length(); ++i) { |
| + HeapEntry* child = children[i].to(); |
| + if (!child->reachable_from_window()) { |
| + worklist.Add(child); |
| + } |
| + } |
| + } |
| +} |
| + |
| + |
| +static bool IsRetainingEdge(HeapGraphEdge* edge) { |
| + if (edge->type() == HeapGraphEdge::kShortcut) return false; |
| + // The edge is not retaining if it goes from system domain |
| + // (i.e. an object not reachable from window) to the user domain |
| + // (i.e. a reachable object). |
| + return edge->from()->reachable_from_window() |
| + || !edge->to()->reachable_from_window(); |
| +} |
| + |
| + |
| +void HeapSnapshotGenerator::FillPostorderIndexes( |
|
yurys
2012/04/16 13:23:37
I think it is still reverse postorder, isn't it?
alexeif
2012/04/16 13:37:23
Why reverse? I think it's direct postorder.
yurys
2012/04/16 13:41:01
From http://en.wikipedia.org/wiki/Tree_traversal#P
alexeif
2012/04/16 13:45:00
The children is not ordered in our case. So speaki
|
| Vector<HeapEntry*>* entries) { |
| snapshot_->ClearPaint(); |
| int current_entry = 0; |
| List<HeapEntry*> nodes_to_visit; |
| - nodes_to_visit.Add(snapshot_->root()); |
| + HeapEntry* root = snapshot_->root(); |
| + nodes_to_visit.Add(root); |
| snapshot_->root()->paint(); |
| while (!nodes_to_visit.is_empty()) { |
| HeapEntry* entry = nodes_to_visit.last(); |
| Vector<HeapGraphEdge> children = entry->children(); |
| bool has_new_edges = false; |
| for (int i = 0; i < children.length(); ++i) { |
| - if (children[i].type() == HeapGraphEdge::kShortcut) continue; |
| + if (entry != root && !IsRetainingEdge(&children[i])) continue; |
| HeapEntry* child = children[i].to(); |
| if (!child->painted()) { |
| nodes_to_visit.Add(child); |
| @@ -3346,6 +3384,7 @@ bool HeapSnapshotGenerator::BuildDominatorTree( |
| const Vector<HeapEntry*>& entries, |
| Vector<int>* dominators) { |
| if (entries.length() == 0) return true; |
| + HeapEntry* root = snapshot_->root(); |
| const int entries_length = entries.length(), root_index = entries_length - 1; |
| static const int kNoDominator = -1; |
| for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator; |
| @@ -3374,8 +3413,8 @@ bool HeapSnapshotGenerator::BuildDominatorTree( |
| int new_idom_index = kNoDominator; |
| Vector<HeapGraphEdge*> rets = entries[i]->retainers(); |
| for (int j = 0; j < rets.length(); ++j) { |
| - if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; |
| - int ret_index = rets[j]->From()->ordered_index(); |
| + if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue; |
| + int ret_index = rets[j]->from()->ordered_index(); |
| if (dominators->at(ret_index) != kNoDominator) { |
| new_idom_index = new_idom_index == kNoDominator |
| ? ret_index |
| @@ -3401,9 +3440,10 @@ bool HeapSnapshotGenerator::BuildDominatorTree( |
| bool HeapSnapshotGenerator::SetEntriesDominators() { |
| - // This array is used for maintaining reverse postorder of nodes. |
| + MarkWindowReachableObjects(); |
| + // This array is used for maintaining postorder of nodes. |
| ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); |
| - FillReversePostorderIndexes(&ordered_entries); |
| + FillPostorderIndexes(&ordered_entries); |
| ScopedVector<int> dominators(ordered_entries.length()); |
| if (!BuildDominatorTree(ordered_entries, &dominators)) return false; |
| for (int i = 0; i < ordered_entries.length(); ++i) { |