Chromium Code Reviews| Index: src/profile-generator.cc | 
| diff --git a/src/profile-generator.cc b/src/profile-generator.cc | 
| index dd2f7014dbd4ae1a36ae8f74bdeb53c27a7b58fd..12e48e48071c8ca211fea85355c289833177c6e4 100644 | 
| --- a/src/profile-generator.cc | 
| +++ b/src/profile-generator.cc | 
| @@ -992,8 +992,8 @@ void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, | 
| const char* name, | 
| HeapEntry* entry, | 
| int retainer_index) { | 
| - children_arr()[child_index].Init(child_index, type, name, entry); | 
| - entry->retainers_arr()[retainer_index] = children_arr() + child_index; | 
| + children()[child_index].Init(child_index, type, name, entry); | 
| + entry->retainers()[retainer_index] = children_arr() + child_index; | 
| } | 
| @@ -1002,14 +1002,14 @@ void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, | 
| int index, | 
| HeapEntry* entry, | 
| int retainer_index) { | 
| - children_arr()[child_index].Init(child_index, type, index, entry); | 
| - entry->retainers_arr()[retainer_index] = children_arr() + child_index; | 
| + children()[child_index].Init(child_index, type, index, entry); | 
| + entry->retainers()[retainer_index] = children_arr() + child_index; | 
| } | 
| void HeapEntry::SetUnidirElementReference( | 
| int child_index, int index, HeapEntry* entry) { | 
| - children_arr()[child_index].Init(child_index, index, entry); | 
| + children()[child_index].Init(child_index, index, entry); | 
| } | 
| @@ -1671,18 +1671,6 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, | 
| GetGcSubrootOrder(object), | 
| children_count, | 
| retainers_count); | 
| - } else if (object->IsJSGlobalObject()) { | 
| 
 
mnaganov (inactive)
2012/03/05 16:21:58
Will this fall through down to the generic case th
 
alexeif
2012/03/05 17:35:31
It should fall into JSObject at 1703 which is the
 
 | 
| - const char* tag = objects_tags_.GetTag(object); | 
| - const char* name = collection_->names()->GetName( | 
| - GetConstructorName(JSObject::cast(object))); | 
| - if (tag != NULL) { | 
| - name = collection_->names()->GetFormatted("%s / %s", name, tag); | 
| - } | 
| - return AddEntry(object, | 
| - HeapEntry::kObject, | 
| - name, | 
| - children_count, | 
| - retainers_count); | 
| } else if (object->IsJSFunction()) { | 
| JSFunction* func = JSFunction::cast(object); | 
| SharedFunctionInfo* shared = func->shared(); | 
| @@ -1703,8 +1691,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, | 
| } else if (object->IsJSObject()) { | 
| return AddEntry(object, | 
| HeapEntry::kObject, | 
| - collection_->names()->GetName( | 
| - GetConstructorName(JSObject::cast(object))), | 
| + "", | 
| children_count, | 
| retainers_count); | 
| } else if (object->IsString()) { | 
| @@ -2349,6 +2336,32 @@ bool V8HeapExplorer::IterateAndExtractReferences( | 
| } | 
| +bool V8HeapExplorer::IterateAndSetObjectNames(SnapshotFillerInterface* filler) { | 
| + HeapIterator iterator(HeapIterator::kFilterUnreachable); | 
| + filler_ = filler; | 
| + for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | 
| + SetObjectName(obj); | 
| + } | 
| + return true; | 
| +} | 
| + | 
| + | 
| +void V8HeapExplorer::SetObjectName(HeapObject* object) { | 
| + if (!object->IsJSObject() || object->IsJSRegExp() || object->IsJSFunction()) { | 
| + return; | 
| + } | 
| + const char* name = collection_->names()->GetName( | 
| + GetConstructorName(JSObject::cast(object))); | 
| + if (object->IsJSGlobalObject()) { | 
| + const char* tag = objects_tags_.GetTag(object); | 
| + if (tag != NULL) { | 
| + name = collection_->names()->GetFormatted("%s / %s", name, tag); | 
| + } | 
| + } | 
| + GetEntry(object)->set_name(name); | 
| +} | 
| + | 
| + | 
| void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj, | 
| HeapEntry* parent_entry, | 
| String* reference_name, | 
| @@ -2907,15 +2920,6 @@ void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) { | 
| } | 
| -HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot, | 
| - v8::ActivityControl* control) | 
| - : snapshot_(snapshot), | 
| - control_(control), | 
| - v8_heap_explorer_(snapshot_, this), | 
| - dom_explorer_(snapshot_, this) { | 
| -} | 
| - | 
| - | 
| class SnapshotCounter : public SnapshotFillerInterface { | 
| public: | 
| explicit SnapshotCounter(HeapEntriesMap* entries) : entries_(entries) { } | 
| @@ -3040,6 +3044,15 @@ class SnapshotFiller : public SnapshotFillerInterface { | 
| }; | 
| +HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot, | 
| + v8::ActivityControl* control) | 
| + : snapshot_(snapshot), | 
| + control_(control), | 
| + v8_heap_explorer_(snapshot_, this), | 
| + dom_explorer_(snapshot_, this) { | 
| +} | 
| + | 
| + | 
| bool HeapSnapshotGenerator::GenerateSnapshot() { | 
| v8_heap_explorer_.TagGlobalObjects(); | 
| @@ -3084,10 +3097,12 @@ bool HeapSnapshotGenerator::GenerateSnapshot() { | 
| debug_heap->Verify(); | 
| #endif | 
| - // Allocate and fill entries in the snapshot, allocate references. | 
| + // Allocate memory for entries and references. | 
| snapshot_->AllocateEntries(entries_.entries_count(), | 
| entries_.total_children_count(), | 
| entries_.total_retainers_count()); | 
| + | 
| + // Allocate heap objects to entries hash map. | 
| entries_.AllocateEntries(); | 
| // Pass 2. Fill references. | 
| @@ -3132,17 +3147,22 @@ void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) { | 
| bool HeapSnapshotGenerator::CountEntriesAndReferences() { | 
| SnapshotCounter counter(&entries_); | 
| v8_heap_explorer_.AddRootEntries(&counter); | 
| - return | 
| - v8_heap_explorer_.IterateAndExtractReferences(&counter) && | 
| - dom_explorer_.IterateAndExtractReferences(&counter); | 
| + return v8_heap_explorer_.IterateAndExtractReferences(&counter) | 
| + && dom_explorer_.IterateAndExtractReferences(&counter); | 
| } | 
| bool HeapSnapshotGenerator::FillReferences() { | 
| SnapshotFiller filler(snapshot_, &entries_); | 
| - return | 
| - v8_heap_explorer_.IterateAndExtractReferences(&filler) && | 
| - dom_explorer_.IterateAndExtractReferences(&filler); | 
| + // IterateAndExtractReferences cannot set object names because | 
| + // it makes call to JSObject::LocalLookupRealNamedProperty which | 
| + // in turn may relocate objects in property maps thus changing the heap | 
| + // layout and affecting retainer counts. This is not acceptable because | 
| + // number of retainers must not change between count and fill passes. | 
| + // To avoid this there's a separate postpass that set object names. | 
| + return v8_heap_explorer_.IterateAndExtractReferences(&filler) | 
| + && dom_explorer_.IterateAndExtractReferences(&filler) | 
| + && v8_heap_explorer_.IterateAndSetObjectNames(&filler); | 
| 
 
mnaganov (inactive)
2012/03/05 16:21:58
As we have discussed offline, please split Generat
 
alexeif
2012/03/05 17:35:31
I checked the AssertNoAllocation class and it does
 
 | 
| } | 
| @@ -3198,26 +3218,28 @@ bool HeapSnapshotGenerator::BuildDominatorTree( | 
| for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator; | 
| (*dominators)[root_index] = root_index; | 
| - // The painted flag is used to mark entries that need to be recalculated | 
| - // because of dominators change among their retainers. | 
| - for (int i = 0; i < entries_length; ++i) entries[i]->clear_paint(); | 
| - | 
| + // The affected array is used to mark entries which dominators | 
| + // have to be racalculated because of changes in their retainers. | 
| + ScopedVector<bool> affected(entries_length); | 
| + for (int i = 0; i < affected.length(); ++i) affected[i] = false; | 
| // Mark the root direct children as affected. | 
| Vector<HeapGraphEdge> children = entries[root_index]->children(); | 
| - for (int i = 0; i < children.length(); ++i) children[i].to()->paint(); | 
| + for (int i = 0; i < children.length(); ++i) { | 
| + affected[children[i].to()->ordered_index()] = true; | 
| + } | 
| bool changed = true; | 
| while (changed) { | 
| changed = false; | 
| + if (!ProgressReport(true)) return false; | 
| for (int i = root_index - 1; i >= 0; --i) { | 
| + if (!affected[i]) continue; | 
| + affected[i] = false; | 
| // If dominator of the entry has already been set to root, | 
| // then it can't propagate any further. | 
| if ((*dominators)[i] == root_index) continue; | 
| - HeapEntry* entry = entries[i]; | 
| - if (!entry->painted()) continue; | 
| - entry->clear_paint(); | 
| int new_idom_index = kNoDominator; | 
| - Vector<HeapGraphEdge*> rets = entry->retainers(); | 
| + 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(); | 
| @@ -3235,7 +3257,9 @@ bool HeapSnapshotGenerator::BuildDominatorTree( | 
| (*dominators)[i] = new_idom_index; | 
| changed = true; | 
| Vector<HeapGraphEdge> children = entries[i]->children(); | 
| - for (int j = 0; j < children.length(); ++j) children[j].to()->paint(); | 
| + for (int j = 0; j < children.length(); ++j) { | 
| + affected[children[j].to()->ordered_index()] = true; | 
| + } | 
| } | 
| } | 
| } |