Chromium Code Reviews| Index: src/profile-generator.cc |
| diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
| index c91e83bb78fe37cc2c75933e297e2f70a1c788d6..8ab50a0b0a96059f55050079ca068fabf2bfd0e6 100644 |
| --- a/src/profile-generator.cc |
| +++ b/src/profile-generator.cc |
| @@ -931,30 +931,29 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
| } |
| -void HeapGraphEdge::Init( |
| - int child_index, Type type, const char* name, HeapEntry* to) { |
| +void HeapGraphEdge::Init(Type type, const char* name, int from, int to) { |
| ASSERT(type == kContextVariable |
| - || type == kProperty |
| - || type == kInternal |
| - || type == kShortcut); |
| - child_index_ = child_index; |
| + || type == kProperty |
| + || type == kInternal |
| + || type == kShortcut); |
| type_ = type; |
| name_ = name; |
| + from_ = from; |
| to_ = to; |
| } |
| -void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) { |
| +void HeapGraphEdge::Init(Type type, int index, int from, int to) { |
| ASSERT(type == kElement || type == kHidden || type == kWeak); |
| - child_index_ = child_index; |
| type_ = type; |
| index_ = index; |
| + from_ = from; |
| to_ = to; |
| } |
| -void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { |
| - Init(child_index, kElement, index, to); |
| +void HeapGraphEdge::UpdateToEntry(HeapSnapshot* snapshot) { |
| + to_entry_ = &snapshot->entries()[to_]; |
| } |
| @@ -962,9 +961,7 @@ void HeapEntry::Init(HeapSnapshot* snapshot, |
| Type type, |
| const char* name, |
| SnapshotObjectId id, |
| - int self_size, |
| - int children_count, |
| - int retainers_count) { |
| + int self_size) { |
| snapshot_ = snapshot; |
| type_ = type; |
| painted_ = false; |
| @@ -972,37 +969,34 @@ void HeapEntry::Init(HeapSnapshot* snapshot, |
| name_ = name; |
| self_size_ = self_size; |
| retained_size_ = 0; |
| - entry_index_ = -1; |
| - children_count_ = children_count; |
| - retainers_count_ = retainers_count; |
| - dominator_ = NULL; |
| + children_index_ = -1; |
| + children_count_ = 0; |
| + retainers_index_ = -1; |
| + retainers_count_ = 0; |
| + dominator_ = -1; |
| id_ = id; |
| } |
| void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, |
| - int child_index, |
| const char* name, |
| - HeapEntry* entry, |
| - int retainer_index) { |
| - children()[child_index].Init(child_index, type, name, entry); |
| - entry->retainers()[retainer_index] = children_arr() + child_index; |
| + HeapEntry* entry) { |
| + HeapGraphEdge edge; |
| + edge.Init(type, name, this->index(), entry->index()); |
| + snapshot_->edges().Add(edge); |
| + ++children_count_; |
| + ++entry->retainers_count_; |
| } |
| void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, |
| - int child_index, |
| int index, |
| - HeapEntry* entry, |
| - int retainer_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()[child_index].Init(child_index, index, entry); |
| + HeapEntry* entry) { |
| + HeapGraphEdge edge; |
| + edge.Init(type, index, this->index(), entry->index()); |
| + snapshot_->edges().Add(edge); |
| + ++children_count_; |
| + ++entry->retainers_count_; |
| } |
| @@ -1013,7 +1007,8 @@ Handle<HeapObject> HeapEntry::GetHeapObject() { |
| void HeapEntry::Print( |
| const char* prefix, const char* edge_name, int max_depth, int indent) { |
| - OS::Print("%6d %7d @%6llu %*c %s%s: ", |
| + STATIC_CHECK(sizeof(unsigned) == sizeof(id())); |
| + OS::Print("%6d %7d @%6u %*c %s%s: ", |
| self_size(), retained_size(), id(), |
| indent, ' ', prefix, edge_name); |
| if (type() != kString) { |
| @@ -1031,9 +1026,9 @@ void HeapEntry::Print( |
| OS::Print("\"\n"); |
| } |
| if (--max_depth == 0) return; |
| - Vector<HeapGraphEdge> ch = children(); |
| + Vector<HeapGraphEdge*> ch = children(); |
| for (int i = 0; i < ch.length(); ++i) { |
| - HeapGraphEdge& edge = ch[i]; |
| + HeapGraphEdge& edge = *ch[i]; |
| const char* edge_prefix = ""; |
| EmbeddedVector<char, 64> index; |
| const char* edge_name = index.start(); |
| @@ -1089,15 +1084,6 @@ const char* HeapEntry::TypeAsString() { |
| } |
| -size_t HeapEntry::EntriesSize(int entries_count, |
| - int children_count, |
| - int retainers_count) { |
| - return sizeof(HeapEntry) * entries_count // NOLINT |
| - + sizeof(HeapGraphEdge) * children_count // NOLINT |
| - + sizeof(HeapGraphEdge*) * retainers_count; // NOLINT |
| -} |
| - |
| - |
| // It is very important to keep objects that form a heap snapshot |
| // as small as possible. |
| namespace { // Avoid littering the global namespace. |
| @@ -1106,7 +1092,7 @@ template <size_t ptr_size> struct SnapshotSizeConstants; |
| template <> struct SnapshotSizeConstants<4> { |
| static const int kExpectedHeapGraphEdgeSize = 12; |
| - static const int kExpectedHeapEntrySize = 36; |
| + static const int kExpectedHeapEntrySize = 40; |
| static const size_t kMaxSerializableSnapshotRawSize = 256 * MB; |
| }; |
| @@ -1127,11 +1113,9 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
| type_(type), |
| title_(title), |
| uid_(uid), |
| - root_entry_(NULL), |
| - gc_roots_entry_(NULL), |
| - natives_root_entry_(NULL), |
| - raw_entries_(NULL), |
| - number_of_edges_(0), |
| + root_entry_(-1), |
|
mnaganov (inactive)
2012/05/03 15:44:31
Please introduce a constant instead of the magic v
alexeif
2012/05/07 11:04:35
Done.
|
| + gc_roots_entry_(-1), |
| + natives_root_entry_(-1), |
| max_snapshot_js_object_id_(0) { |
| STATIC_CHECK( |
| sizeof(HeapGraphEdge) == |
| @@ -1140,16 +1124,11 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
| sizeof(HeapEntry) == |
| SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize); |
| for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) { |
| - gc_subroot_entries_[i] = NULL; |
| + gc_subroot_entries_[i] = -1; |
| } |
| } |
| -HeapSnapshot::~HeapSnapshot() { |
| - DeleteArray(raw_entries_); |
| -} |
| - |
| - |
| void HeapSnapshot::Delete() { |
| collection_->RemoveSnapshot(this); |
| delete this; |
| @@ -1161,19 +1140,8 @@ void HeapSnapshot::RememberLastJSObjectId() { |
| } |
| -void HeapSnapshot::AllocateEntries(int entries_count, |
| - int children_count, |
| - int retainers_count) { |
| - ASSERT(raw_entries_ == NULL); |
| - number_of_edges_ = children_count; |
| - raw_entries_size_ = |
| - HeapEntry::EntriesSize(entries_count, children_count, retainers_count); |
| - raw_entries_ = NewArray<char>(raw_entries_size_); |
| -} |
| - |
| - |
| -static void HeapEntryClearPaint(HeapEntry** entry_ptr) { |
| - (*entry_ptr)->clear_paint(); |
| +static void HeapEntryClearPaint(HeapEntry* entry_ptr) { |
| + entry_ptr->clear_paint(); |
| } |
| @@ -1182,76 +1150,83 @@ void HeapSnapshot::ClearPaint() { |
| } |
| -HeapEntry* HeapSnapshot::AddRootEntry(int children_count) { |
| - ASSERT(root_entry_ == NULL); |
| +HeapEntry* HeapSnapshot::AddRootEntry() { |
| + ASSERT(root_entry_ == -1); |
| ASSERT(entries_.is_empty()); // Root entry must be the first one. |
| - return (root_entry_ = AddEntry(HeapEntry::kObject, |
| - "", |
| - HeapObjectsMap::kInternalRootObjectId, |
| - 0, |
| - children_count, |
| - 0)); |
| + HeapEntry* entry = AddEntry(HeapEntry::kObject, |
| + "", |
| + HeapObjectsMap::kInternalRootObjectId, |
| + 0); |
| + root_entry_ = entry->index(); |
| + CHECK(root_entry_ == 0); |
|
mnaganov (inactive)
2012/05/03 15:44:31
Are you using CHECKs here and below intentionally?
alexeif
2012/05/07 11:04:35
I added them intentionally in places that are non
mnaganov (inactive)
2012/05/08 12:05:20
My feeling is that as V8 is geared towards speed,
alexeif
2012/05/09 12:38:07
Done.
|
| + return entry; |
| } |
| -HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count, |
| - int retainers_count) { |
| - ASSERT(gc_roots_entry_ == NULL); |
| - return (gc_roots_entry_ = AddEntry(HeapEntry::kObject, |
| - "(GC roots)", |
| - HeapObjectsMap::kGcRootsObjectId, |
| - 0, |
| - children_count, |
| - retainers_count)); |
| +HeapEntry* HeapSnapshot::AddGcRootsEntry() { |
| + ASSERT(gc_roots_entry_ == -1); |
| + HeapEntry* entry = AddEntry(HeapEntry::kObject, |
| + "(GC roots)", |
| + HeapObjectsMap::kGcRootsObjectId, |
| + 0); |
| + gc_roots_entry_ = entry->index(); |
| + return entry; |
| } |
| -HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag, |
| - int children_count, |
| - int retainers_count) { |
| - ASSERT(gc_subroot_entries_[tag] == NULL); |
| +HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag) { |
| + ASSERT(gc_subroot_entries_[tag] == -1); |
| ASSERT(0 <= tag && tag < VisitorSynchronization::kNumberOfSyncTags); |
| - return (gc_subroot_entries_[tag] = AddEntry( |
| + HeapEntry* entry = AddEntry( |
| HeapEntry::kObject, |
| VisitorSynchronization::kTagNames[tag], |
| HeapObjectsMap::GetNthGcSubrootId(tag), |
| - 0, |
| - children_count, |
| - retainers_count)); |
| + 0); |
| + gc_subroot_entries_[tag] = entry->index(); |
| + return entry; |
| } |
| HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, |
| const char* name, |
| SnapshotObjectId id, |
| - int size, |
| - int children_count, |
| - int retainers_count) { |
| - HeapEntry* entry = GetNextEntryToInit(); |
| - entry->Init(this, type, name, id, size, children_count, retainers_count); |
| - return entry; |
| + int size) { |
| + HeapEntry entry; |
| + entry.Init(this, type, name, id, size); |
| + entries_.Add(entry); |
| + return &entries_.last(); |
| } |
| -void HeapSnapshot::SetDominatorsToSelf() { |
| - for (int i = 0; i < entries_.length(); ++i) { |
| - HeapEntry* entry = entries_[i]; |
| - if (entry->dominator() == NULL) entry->set_dominator(entry); |
| +void HeapSnapshot::FillChildrenAndRetainers() { |
| + CHECK(children().is_empty()); |
| + children().Initialize(edges().length()); |
| + children().Rewind(edges().length()); |
|
mnaganov (inactive)
2012/05/03 15:44:31
Perhaps, add a helper method to the 'List' class f
alexeif
2012/05/07 11:04:35
Done.
|
| + CHECK(retainers().is_empty()); |
| + retainers().Initialize(edges().length()); |
| + retainers().Rewind(edges().length()); |
| + int children_index = 0; |
| + int retainers_index = 0; |
| + for (int i = 0; i < entries().length(); ++i) { |
| + HeapEntry* entry = &entries()[i]; |
| + children_index = entry->set_children_index(children_index); |
| + retainers_index = entry->set_retainers_index(retainers_index); |
| + } |
| + CHECK_EQ(edges().length(), children_index); |
| + CHECK_EQ(edges().length(), retainers_index); |
| + for (int i = 0; i < edges().length(); ++i) { |
| + HeapGraphEdge* edge = &edges()[i]; |
| + edge->UpdateToEntry(this); |
| + edge->from()->add_child(edge); |
| + edge->to()->add_retainer(edge); |
| } |
| } |
| -HeapEntry* HeapSnapshot::GetNextEntryToInit() { |
| - if (entries_.length() > 0) { |
| - HeapEntry* last_entry = entries_.last(); |
| - entries_.Add(reinterpret_cast<HeapEntry*>( |
| - reinterpret_cast<char*>(last_entry) + last_entry->EntrySize())); |
| - } else { |
| - entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_)); |
| +void HeapSnapshot::SetDominatorsToSelf() { |
| + for (int i = 0; i < entries_.length(); ++i) { |
| + entries_[i].set_dominator(&entries_[i]); |
| } |
| - ASSERT(reinterpret_cast<char*>(entries_.last()) < |
| - (raw_entries_ + raw_entries_size_)); |
| - return entries_.last(); |
| } |
| @@ -1287,7 +1262,9 @@ static int SortByIds(const T* entry1_ptr, |
| List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { |
| if (sorted_entries_.is_empty()) { |
| - sorted_entries_.AddAll(entries_); |
| + for (int i = 0; i < entries_.length(); ++i) { |
|
mnaganov (inactive)
2012/05/03 15:44:31
I suppose, it will be a bit faster to set sorted_e
alexeif
2012/05/07 11:04:35
Done.
|
| + sorted_entries_.Add(&entries_[i]); |
| + } |
| sorted_entries_.Sort(SortByIds); |
| } |
| return &sorted_entries_; |
| @@ -1299,6 +1276,16 @@ void HeapSnapshot::Print(int max_depth) { |
| } |
| +size_t HeapSnapshot::RawSnapshotSize() const { |
| + return |
| + entries_.capacity() * sizeof(HeapEntry) + |
|
mnaganov (inactive)
2012/05/03 15:44:31
Perhaps, add an utility method to the 'List' class
alexeif
2012/05/07 11:04:35
I'm not sure this function is generic enough to be
|
| + edges_.capacity() * sizeof(HeapGraphEdge) + |
| + children_.capacity() * sizeof(HeapGraphEdge*) + |
| + retainers_.capacity() * sizeof(HeapGraphEdge*) + |
| + sorted_entries_.capacity() * sizeof(HeapEntry*); |
| +} |
| + |
| + |
| // We split IDs on evens for embedder objects (see |
| // HeapObjectsMap::GenerateId) and odds for native objects. |
| const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1; |
| @@ -1567,99 +1554,22 @@ Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById( |
| } |
| -HeapEntry* const HeapEntriesMap::kHeapEntryPlaceholder = |
| - reinterpret_cast<HeapEntry*>(1); |
| - |
| HeapEntriesMap::HeapEntriesMap() |
| - : entries_(HeapThingsMatch), |
| - entries_count_(0), |
| - total_children_count_(0), |
| - total_retainers_count_(0) { |
| + : entries_(HeapThingsMatch) { |
| } |
| -HeapEntriesMap::~HeapEntriesMap() { |
| - for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) { |
| - delete reinterpret_cast<EntryInfo*>(p->value); |
| - } |
| -} |
| - |
| - |
| -void HeapEntriesMap::AllocateHeapEntryForMapEntry(HashMap::Entry* map_entry) { |
| - EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(map_entry->value); |
| - entry_info->entry = entry_info->allocator->AllocateEntry( |
| - map_entry->key, |
| - entry_info->children_count, |
| - entry_info->retainers_count); |
| - ASSERT(entry_info->entry != NULL); |
| - ASSERT(entry_info->entry != kHeapEntryPlaceholder); |
| - entry_info->children_count = 0; |
| - entry_info->retainers_count = 0; |
| -} |
| - |
| - |
| -void HeapEntriesMap::AllocateEntries(HeapThing root_object) { |
| - HashMap::Entry* root_entry = |
| - entries_.Lookup(root_object, Hash(root_object), false); |
| - ASSERT(root_entry != NULL); |
| - // Make sure root entry is allocated first. |
| - AllocateHeapEntryForMapEntry(root_entry); |
| - void* root_entry_value = root_entry->value; |
| - // Remove the root object from map while iterating through other entries. |
| - entries_.Remove(root_object, Hash(root_object)); |
| - root_entry = NULL; |
| - |
| - for (HashMap::Entry* p = entries_.Start(); |
| - p != NULL; |
| - p = entries_.Next(p)) { |
| - AllocateHeapEntryForMapEntry(p); |
| - } |
| - |
| - // Insert root entry back. |
| - root_entry = entries_.Lookup(root_object, Hash(root_object), true); |
| - root_entry->value = root_entry_value; |
| -} |
| - |
| - |
| -HeapEntry* HeapEntriesMap::Map(HeapThing thing) { |
| +int HeapEntriesMap::Map(HeapThing thing) { |
| HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false); |
| - if (cache_entry != NULL) { |
| - EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value); |
| - return entry_info->entry; |
| - } else { |
| - return NULL; |
| - } |
| + if (cache_entry == NULL) return -1; |
| + return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); |
| } |
| -void HeapEntriesMap::Pair( |
| - HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry) { |
| +void HeapEntriesMap::Pair(HeapThing thing, int entry) { |
| HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), true); |
| ASSERT(cache_entry->value == NULL); |
| - cache_entry->value = new EntryInfo(entry, allocator); |
| - ++entries_count_; |
| -} |
| - |
| - |
| -void HeapEntriesMap::CountReference(HeapThing from, HeapThing to, |
| - int* prev_children_count, |
| - int* prev_retainers_count) { |
| - HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), false); |
| - HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false); |
| - ASSERT(from_cache_entry != NULL); |
| - ASSERT(to_cache_entry != NULL); |
| - EntryInfo* from_entry_info = |
| - reinterpret_cast<EntryInfo*>(from_cache_entry->value); |
| - EntryInfo* to_entry_info = |
| - reinterpret_cast<EntryInfo*>(to_cache_entry->value); |
| - if (prev_children_count) |
| - *prev_children_count = from_entry_info->children_count; |
| - if (prev_retainers_count) |
| - *prev_retainers_count = to_entry_info->retainers_count; |
| - ++from_entry_info->children_count; |
| - ++to_entry_info->retainers_count; |
| - ++total_children_count_; |
| - ++total_retainers_count_; |
| + cache_entry->value = reinterpret_cast<void*>(static_cast<intptr_t>(entry)); |
| } |
| @@ -1676,20 +1586,14 @@ void HeapObjectsSet::Clear() { |
| bool HeapObjectsSet::Contains(Object* obj) { |
| if (!obj->IsHeapObject()) return false; |
| HeapObject* object = HeapObject::cast(obj); |
| - HashMap::Entry* cache_entry = |
| - entries_.Lookup(object, HeapEntriesMap::Hash(object), false); |
| - return cache_entry != NULL; |
| + return entries_.Lookup(object, HeapEntriesMap::Hash(object), false) != NULL; |
| } |
| void HeapObjectsSet::Insert(Object* obj) { |
| if (!obj->IsHeapObject()) return; |
| HeapObject* object = HeapObject::cast(obj); |
| - HashMap::Entry* cache_entry = |
| - entries_.Lookup(object, HeapEntriesMap::Hash(object), true); |
| - if (cache_entry->value == NULL) { |
| - cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder; |
| - } |
| + entries_.Lookup(object, HeapEntriesMap::Hash(object), true); |
| } |
| @@ -1697,12 +1601,9 @@ const char* HeapObjectsSet::GetTag(Object* obj) { |
| HeapObject* object = HeapObject::cast(obj); |
| HashMap::Entry* cache_entry = |
| entries_.Lookup(object, HeapEntriesMap::Hash(object), false); |
| - if (cache_entry != NULL |
| - && cache_entry->value != HeapEntriesMap::kHeapEntryPlaceholder) { |
| - return reinterpret_cast<const char*>(cache_entry->value); |
| - } else { |
| - return NULL; |
| - } |
| + return cache_entry != NULL |
| + ? reinterpret_cast<const char*>(cache_entry->value) |
| + : NULL; |
| } |
| @@ -1744,129 +1645,76 @@ V8HeapExplorer::~V8HeapExplorer() { |
| } |
| -HeapEntry* V8HeapExplorer::AllocateEntry( |
| - HeapThing ptr, int children_count, int retainers_count) { |
| - return AddEntry( |
| - reinterpret_cast<HeapObject*>(ptr), children_count, retainers_count); |
| +HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) { |
| + return AddEntry(reinterpret_cast<HeapObject*>(ptr)); |
| } |
| -HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| - int children_count, |
| - int retainers_count) { |
| +HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { |
| if (object == kInternalRootObject) { |
| - ASSERT(retainers_count == 0); |
| - return snapshot_->AddRootEntry(children_count); |
| + snapshot_->AddRootEntry(); |
| + return snapshot_->root(); |
| } else if (object == kGcRootsObject) { |
| - return snapshot_->AddGcRootsEntry(children_count, retainers_count); |
| + HeapEntry* entry = snapshot_->AddGcRootsEntry(); |
| + return entry; |
| } else if (object >= kFirstGcSubrootObject && object < kLastGcSubrootObject) { |
| - return snapshot_->AddGcSubrootEntry( |
| - GetGcSubrootOrder(object), |
| - children_count, |
| - retainers_count); |
| + HeapEntry* entry = snapshot_->AddGcSubrootEntry(GetGcSubrootOrder(object)); |
| + return entry; |
| } else if (object->IsJSFunction()) { |
| JSFunction* func = JSFunction::cast(object); |
| SharedFunctionInfo* shared = func->shared(); |
| const char* name = shared->bound() ? "native_bind" : |
| collection_->names()->GetName(String::cast(shared->name())); |
| - return AddEntry(object, |
| - HeapEntry::kClosure, |
| - name, |
| - children_count, |
| - retainers_count); |
| + return AddEntry(object, HeapEntry::kClosure, name); |
| } else if (object->IsJSRegExp()) { |
| JSRegExp* re = JSRegExp::cast(object); |
| return AddEntry(object, |
| HeapEntry::kRegExp, |
| - collection_->names()->GetName(re->Pattern()), |
| - children_count, |
| - retainers_count); |
| + collection_->names()->GetName(re->Pattern())); |
| } else if (object->IsJSObject()) { |
| - return AddEntry(object, |
| - HeapEntry::kObject, |
| - "", |
| - children_count, |
| - retainers_count); |
| + return AddEntry(object, HeapEntry::kObject, ""); |
| } else if (object->IsString()) { |
| return AddEntry(object, |
| HeapEntry::kString, |
| - collection_->names()->GetName(String::cast(object)), |
| - children_count, |
| - retainers_count); |
| + collection_->names()->GetName(String::cast(object))); |
| } else if (object->IsCode()) { |
| - return AddEntry(object, |
| - HeapEntry::kCode, |
| - "", |
| - children_count, |
| - retainers_count); |
| + return AddEntry(object, HeapEntry::kCode, ""); |
| } else if (object->IsSharedFunctionInfo()) { |
| - SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); |
| + String* name = String::cast(SharedFunctionInfo::cast(object)->name()); |
| return AddEntry(object, |
| HeapEntry::kCode, |
| - collection_->names()->GetName(String::cast(shared->name())), |
| - children_count, |
| - retainers_count); |
| + collection_->names()->GetName(name)); |
| } else if (object->IsScript()) { |
| - Script* script = Script::cast(object); |
| + Object* name = Script::cast(object)->name(); |
| return AddEntry(object, |
| HeapEntry::kCode, |
| - script->name()->IsString() ? |
| - collection_->names()->GetName( |
| - String::cast(script->name())) |
| - : "", |
| - children_count, |
| - retainers_count); |
| + name->IsString() |
| + ? collection_->names()->GetName(String::cast(name)) |
| + : ""); |
| } else if (object->IsGlobalContext()) { |
| - return AddEntry(object, |
| - HeapEntry::kHidden, |
| - "system / GlobalContext", |
| - children_count, |
| - retainers_count); |
| + return AddEntry(object, HeapEntry::kHidden, "system / GlobalContext"); |
| } else if (object->IsContext()) { |
| - return AddEntry(object, |
| - HeapEntry::kHidden, |
| - "system / Context", |
| - children_count, |
| - retainers_count); |
| + return AddEntry(object, HeapEntry::kHidden, "system / Context"); |
| } else if (object->IsFixedArray() || |
| object->IsFixedDoubleArray() || |
| object->IsByteArray() || |
| object->IsExternalArray()) { |
| const char* tag = objects_tags_.GetTag(object); |
| - return AddEntry(object, |
| - HeapEntry::kArray, |
| - tag != NULL ? tag : "", |
| - children_count, |
| - retainers_count); |
| + return AddEntry(object, HeapEntry::kArray, tag != NULL ? tag : ""); |
| } else if (object->IsHeapNumber()) { |
| - return AddEntry(object, |
| - HeapEntry::kHeapNumber, |
| - "number", |
| - children_count, |
| - retainers_count); |
| + return AddEntry(object, HeapEntry::kHeapNumber, "number"); |
| } |
| - return AddEntry(object, |
| - HeapEntry::kHidden, |
| - GetSystemEntryName(object), |
| - children_count, |
| - retainers_count); |
| + return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object)); |
| } |
| HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| HeapEntry::Type type, |
| - const char* name, |
| - int children_count, |
| - int retainers_count) { |
| + const char* name) { |
| int object_size = object->Size(); |
| SnapshotObjectId object_id = |
| collection_->GetObjectId(object->address(), object_size); |
| - return snapshot_->AddEntry(type, |
| - name, |
| - object_id, |
| - object_size, |
| - children_count, |
| - retainers_count); |
| + return snapshot_->AddEntry(type, name, object_id, object_size); |
| } |
| @@ -1935,10 +1783,10 @@ class IndexedReferencesExtractor : public ObjectVisitor { |
| public: |
| IndexedReferencesExtractor(V8HeapExplorer* generator, |
| HeapObject* parent_obj, |
| - HeapEntry* parent_entry) |
| + int parent) |
| : generator_(generator), |
| parent_obj_(parent_obj), |
| - parent_(parent_entry), |
| + parent_(parent), |
| next_index_(1) { |
| } |
| void VisitPointers(Object** start, Object** end) { |
| @@ -1967,14 +1815,15 @@ class IndexedReferencesExtractor : public ObjectVisitor { |
| } |
| V8HeapExplorer* generator_; |
| HeapObject* parent_obj_; |
| - HeapEntry* parent_; |
| + int parent_; |
| int next_index_; |
| }; |
| void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| - HeapEntry* entry = GetEntry(obj); |
| - if (entry == NULL) return; // No interest in this object. |
| + HeapEntry* heap_entry = GetEntry(obj); |
| + if (heap_entry == NULL) return; // No interest in this object. |
| + int entry = heap_entry->index(); |
| bool extract_indexed_refs = true; |
| if (obj->IsJSGlobalProxy()) { |
| @@ -2026,7 +1875,7 @@ void V8HeapExplorer::ExtractJSGlobalProxyReferences(JSGlobalProxy* proxy) { |
| void V8HeapExplorer::ExtractJSObjectReferences( |
| - HeapEntry* entry, JSObject* js_obj) { |
| + int entry, JSObject* js_obj) { |
| HeapObject* obj = js_obj; |
| ExtractClosureReferences(js_obj, entry); |
| ExtractPropertyReferences(js_obj, entry); |
| @@ -2095,7 +1944,7 @@ void V8HeapExplorer::ExtractJSObjectReferences( |
| } |
| -void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String* string) { |
| +void V8HeapExplorer::ExtractStringReferences(int entry, String* string) { |
| if (string->IsConsString()) { |
| ConsString* cs = ConsString::cast(string); |
| SetInternalReference(cs, entry, "first", cs->first()); |
| @@ -2107,8 +1956,7 @@ void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String* string) { |
| } |
| -void V8HeapExplorer::ExtractContextReferences( |
| - HeapEntry* entry, Context* context) { |
| +void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) { |
| #define EXTRACT_CONTEXT_FIELD(index, type, name) \ |
| SetInternalReference(context, entry, #name, context->get(Context::index), \ |
| FixedArray::OffsetOfElementAt(Context::index)); |
| @@ -2134,7 +1982,7 @@ void V8HeapExplorer::ExtractContextReferences( |
| } |
| -void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) { |
| +void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { |
| SetInternalReference(map, entry, |
| "prototype", map->prototype(), Map::kPrototypeOffset); |
| SetInternalReference(map, entry, |
| @@ -2157,7 +2005,7 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) { |
| void V8HeapExplorer::ExtractSharedFunctionInfoReferences( |
| - HeapEntry* entry, SharedFunctionInfo* shared) { |
| + int entry, SharedFunctionInfo* shared) { |
| HeapObject* obj = shared; |
| SetInternalReference(obj, entry, |
| "name", shared->name(), |
| @@ -2199,7 +2047,7 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences( |
| } |
| -void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) { |
| +void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) { |
| HeapObject* obj = script; |
| SetInternalReference(obj, entry, |
| "source", script->source(), |
| @@ -2221,7 +2069,7 @@ void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) { |
| void V8HeapExplorer::ExtractCodeCacheReferences( |
| - HeapEntry* entry, CodeCache* code_cache) { |
| + int entry, CodeCache* code_cache) { |
| TagObject(code_cache->default_cache(), "(default code cache)"); |
| SetInternalReference(code_cache, entry, |
| "default_cache", code_cache->default_cache(), |
| @@ -2233,7 +2081,7 @@ void V8HeapExplorer::ExtractCodeCacheReferences( |
| } |
| -void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) { |
| +void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) { |
| TagObject(code->relocation_info(), "(code relocation info)"); |
| SetInternalReference(code, entry, |
| "relocation_info", code->relocation_info(), |
| @@ -2255,13 +2103,12 @@ void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) { |
| void V8HeapExplorer::ExtractJSGlobalPropertyCellReferences( |
| - HeapEntry* entry, JSGlobalPropertyCell* cell) { |
| + int entry, JSGlobalPropertyCell* cell) { |
| SetInternalReference(cell, entry, "value", cell->value()); |
| } |
| -void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, |
| - HeapEntry* entry) { |
| +void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) { |
| if (!js_obj->IsJSFunction()) return; |
| JSFunction* func = JSFunction::cast(js_obj); |
| @@ -2303,8 +2150,7 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, |
| } |
| -void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, |
| - HeapEntry* entry) { |
| +void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { |
| if (js_obj->HasFastProperties()) { |
| DescriptorArray* descs = js_obj->map()->instance_descriptors(); |
| for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| @@ -2377,8 +2223,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, |
| } |
| -void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, |
| - HeapEntry* entry) { |
| +void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) { |
| if (js_obj->HasFastElements()) { |
| FixedArray* elements = FixedArray::cast(js_obj->elements()); |
| int length = js_obj->IsJSArray() ? |
| @@ -2404,8 +2249,7 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, |
| } |
| -void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, |
| - HeapEntry* entry) { |
| +void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, int entry) { |
| int length = js_obj->GetInternalFieldCount(); |
| for (int i = 0; i < length; ++i) { |
| Object* o = js_obj->GetInternalField(i); |
| @@ -2531,6 +2375,7 @@ bool V8HeapExplorer::IterateAndExtractReferences( |
| filler_ = NULL; |
| return false; |
| } |
| + |
| SetRootGcRootsReference(); |
| RootsReferencesExtractor extractor; |
| heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG); |
| @@ -2538,7 +2383,7 @@ bool V8HeapExplorer::IterateAndExtractReferences( |
| heap_->IterateRoots(&extractor, VISIT_ALL); |
| extractor.FillReferences(this); |
| filler_ = NULL; |
| - return progress_->ProgressReport(false); |
| + return progress_->ProgressReport(true); |
| } |
| @@ -2586,55 +2431,49 @@ bool V8HeapExplorer::IsEssentialObject(Object* object) { |
| void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj, |
| - HeapEntry* parent_entry, |
| + int parent_entry, |
| String* reference_name, |
| Object* child_obj) { |
| HeapEntry* child_entry = GetEntry(child_obj); |
| if (child_entry != NULL) { |
| filler_->SetNamedReference(HeapGraphEdge::kContextVariable, |
| - parent_obj, |
| parent_entry, |
| collection_->names()->GetName(reference_name), |
| - child_obj, |
| child_entry); |
| } |
| } |
| void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj, |
| - HeapEntry* parent_entry, |
| + int parent_entry, |
| const char* reference_name, |
| Object* child_obj) { |
| HeapEntry* child_entry = GetEntry(child_obj); |
| if (child_entry != NULL) { |
| filler_->SetNamedReference(HeapGraphEdge::kShortcut, |
| - parent_obj, |
| parent_entry, |
| reference_name, |
| - child_obj, |
| child_entry); |
| } |
| } |
| void V8HeapExplorer::SetElementReference(HeapObject* parent_obj, |
| - HeapEntry* parent_entry, |
| + int parent_entry, |
| int index, |
| Object* child_obj) { |
| HeapEntry* child_entry = GetEntry(child_obj); |
| if (child_entry != NULL) { |
| filler_->SetIndexedReference(HeapGraphEdge::kElement, |
| - parent_obj, |
| parent_entry, |
| index, |
| - child_obj, |
| child_entry); |
| } |
| } |
| void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, |
| - HeapEntry* parent_entry, |
| + int parent_entry, |
| const char* reference_name, |
| Object* child_obj, |
| int field_offset) { |
| @@ -2642,16 +2481,16 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, |
| if (child_entry == NULL) return; |
| if (IsEssentialObject(child_obj)) { |
| filler_->SetNamedReference(HeapGraphEdge::kInternal, |
| - parent_obj, parent_entry, |
| + parent_entry, |
| reference_name, |
| - child_obj, child_entry); |
| + child_entry); |
| } |
| IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); |
| } |
| void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, |
| - HeapEntry* parent_entry, |
| + int parent_entry, |
| int index, |
| Object* child_obj, |
| int field_offset) { |
| @@ -2659,42 +2498,38 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, |
| if (child_entry == NULL) return; |
| if (IsEssentialObject(child_obj)) { |
| filler_->SetNamedReference(HeapGraphEdge::kInternal, |
| - parent_obj, parent_entry, |
| + parent_entry, |
| collection_->names()->GetName(index), |
| - child_obj, child_entry); |
| + child_entry); |
| } |
| IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); |
| } |
| void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, |
| - HeapEntry* parent_entry, |
| + int parent_entry, |
| int index, |
| Object* child_obj) { |
| HeapEntry* child_entry = GetEntry(child_obj); |
| if (child_entry != NULL && IsEssentialObject(child_obj)) { |
| filler_->SetIndexedReference(HeapGraphEdge::kHidden, |
| - parent_obj, |
| parent_entry, |
| index, |
| - child_obj, |
| child_entry); |
| } |
| } |
| void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, |
| - HeapEntry* parent_entry, |
| + int parent_entry, |
| int index, |
| Object* child_obj, |
| int field_offset) { |
| HeapEntry* child_entry = GetEntry(child_obj); |
| if (child_entry != NULL) { |
| filler_->SetIndexedReference(HeapGraphEdge::kWeak, |
| - parent_obj, |
| parent_entry, |
| index, |
| - child_obj, |
| child_entry); |
| IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); |
| } |
| @@ -2702,7 +2537,7 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, |
| void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, |
| - HeapEntry* parent_entry, |
| + int parent_entry, |
| String* reference_name, |
| Object* child_obj, |
| const char* name_format_string, |
| @@ -2719,10 +2554,8 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, |
| collection_->names()->GetName(reference_name); |
| filler_->SetNamedReference(type, |
| - parent_obj, |
| parent_entry, |
| name, |
| - child_obj, |
| child_entry); |
| IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); |
| } |
| @@ -2730,16 +2563,14 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, |
| void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj, |
| - HeapEntry* parent_entry, |
| + int parent_entry, |
| String* reference_name, |
| Object* child_obj) { |
| HeapEntry* child_entry = GetEntry(child_obj); |
| if (child_entry != NULL) { |
| filler_->SetNamedReference(HeapGraphEdge::kShortcut, |
| - parent_obj, |
| parent_entry, |
| collection_->names()->GetName(reference_name), |
| - child_obj, |
| child_entry); |
| } |
| } |
| @@ -2748,8 +2579,8 @@ void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj, |
| void V8HeapExplorer::SetRootGcRootsReference() { |
| filler_->SetIndexedAutoIndexReference( |
| HeapGraphEdge::kElement, |
| - kInternalRootObject, snapshot_->root(), |
| - kGcRootsObject, snapshot_->gc_roots()); |
| + snapshot_->root()->index(), |
| + snapshot_->gc_roots()); |
| } |
| @@ -2758,16 +2589,16 @@ void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) { |
| ASSERT(child_entry != NULL); |
| filler_->SetNamedAutoIndexReference( |
| HeapGraphEdge::kShortcut, |
| - kInternalRootObject, snapshot_->root(), |
| - child_obj, child_entry); |
| + snapshot_->root()->index(), |
| + child_entry); |
| } |
| void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) { |
| filler_->SetIndexedAutoIndexReference( |
| HeapGraphEdge::kElement, |
| - kGcRootsObject, snapshot_->gc_roots(), |
| - GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag)); |
| + snapshot_->gc_roots()->index(), |
| + snapshot_->gc_subroot(tag)); |
| } |
| @@ -2779,14 +2610,14 @@ void V8HeapExplorer::SetGcSubrootReference( |
| if (name != NULL) { |
| filler_->SetNamedReference( |
| HeapGraphEdge::kInternal, |
| - GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag), |
| + snapshot_->gc_subroot(tag)->index(), |
| name, |
| - child_obj, child_entry); |
| + child_entry); |
| } else { |
| filler_->SetIndexedAutoIndexReference( |
| is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement, |
| - GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag), |
| - child_obj, child_entry); |
| + snapshot_->gc_subroot(tag)->index(), |
| + child_entry); |
| } |
| } |
| } |
| @@ -2903,8 +2734,7 @@ class BasicHeapEntriesAllocator : public HeapEntriesAllocator { |
| collection_(snapshot_->collection()), |
| entries_type_(entries_type) { |
| } |
| - virtual HeapEntry* AllocateEntry( |
| - HeapThing ptr, int children_count, int retainers_count); |
| + virtual HeapEntry* AllocateEntry(HeapThing ptr); |
| private: |
| HeapSnapshot* snapshot_; |
| HeapSnapshotsCollection* collection_; |
| @@ -2912,23 +2742,19 @@ class BasicHeapEntriesAllocator : public HeapEntriesAllocator { |
| }; |
| -HeapEntry* BasicHeapEntriesAllocator::AllocateEntry( |
| - HeapThing ptr, int children_count, int retainers_count) { |
| +HeapEntry* BasicHeapEntriesAllocator::AllocateEntry(HeapThing ptr) { |
| v8::RetainedObjectInfo* info = reinterpret_cast<v8::RetainedObjectInfo*>(ptr); |
| intptr_t elements = info->GetElementCount(); |
| intptr_t size = info->GetSizeInBytes(); |
| + const char* name = elements != -1 |
| + ? collection_->names()->GetFormatted( |
| + "%s / %" V8_PTR_PREFIX "d entries", info->GetLabel(), elements) |
| + : collection_->names()->GetCopy(info->GetLabel()); |
| return snapshot_->AddEntry( |
| entries_type_, |
| - elements != -1 ? |
| - collection_->names()->GetFormatted( |
| - "%s / %" V8_PTR_PREFIX "d entries", |
| - info->GetLabel(), |
| - info->GetElementCount()) : |
| - collection_->names()->GetCopy(info->GetLabel()), |
| + name, |
| HeapObjectsMap::GenerateId(info), |
| - size != -1 ? static_cast<int>(size) : 0, |
| - children_count, |
| - retainers_count); |
| + size != -1 ? static_cast<int>(size) : 0); |
| } |
| @@ -3009,9 +2835,9 @@ void NativeObjectsExplorer::FillImplicitReferences() { |
| for (int i = 0; i < groups->length(); ++i) { |
| ImplicitRefGroup* group = groups->at(i); |
| HeapObject* parent = *group->parent_; |
| - HeapEntry* parent_entry = |
| - filler_->FindOrAddEntry(parent, native_entries_allocator_); |
| - ASSERT(parent_entry != NULL); |
| + int parent_entry = |
| + filler_->FindOrAddEntry(parent, native_entries_allocator_)->index(); |
| + ASSERT(parent_entry != -1); |
| Object*** children = group->children_; |
| for (size_t j = 0; j < group->length_; ++j) { |
| Object* child = *children[j]; |
| @@ -3019,9 +2845,9 @@ void NativeObjectsExplorer::FillImplicitReferences() { |
| filler_->FindOrAddEntry(child, native_entries_allocator_); |
| filler_->SetNamedReference( |
| HeapGraphEdge::kInternal, |
| - parent, parent_entry, |
| + parent_entry, |
| "native", |
| - child, child_entry); |
| + child_entry); |
| } |
| } |
| } |
| @@ -3099,8 +2925,9 @@ NativeGroupRetainedObjectInfo* NativeObjectsExplorer::FindOrAddGroupInfo( |
| HEAP->HashSeed()); |
| HashMap::Entry* entry = native_groups_.Lookup(const_cast<char*>(label_copy), |
| hash, true); |
| - if (entry->value == NULL) |
| + if (entry->value == NULL) { |
| entry->value = new NativeGroupRetainedObjectInfo(label); |
| + } |
| return static_cast<NativeGroupRetainedObjectInfo*>(entry->value); |
| } |
| @@ -3116,8 +2943,8 @@ void NativeObjectsExplorer::SetNativeRootReference( |
| filler_->FindOrAddEntry(group_info, synthetic_entries_allocator_); |
| filler_->SetNamedAutoIndexReference( |
| HeapGraphEdge::kInternal, |
| - group_info, group_entry, |
| - info, child_entry); |
| + group_entry->index(), |
| + child_entry); |
| } |
| @@ -3129,12 +2956,12 @@ void NativeObjectsExplorer::SetWrapperNativeReferences( |
| filler_->FindOrAddEntry(info, native_entries_allocator_); |
| ASSERT(info_entry != NULL); |
| filler_->SetNamedReference(HeapGraphEdge::kInternal, |
| - wrapper, wrapper_entry, |
| + wrapper_entry->index(), |
| "native", |
| - info, info_entry); |
| + info_entry); |
| filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, |
| - info, info_entry, |
| - wrapper, wrapper_entry); |
| + info_entry->index(), |
| + wrapper_entry); |
| } |
| @@ -3149,8 +2976,8 @@ void NativeObjectsExplorer::SetRootNativeRootsReference() { |
| ASSERT(group_entry != NULL); |
| filler_->SetIndexedAutoIndexReference( |
| HeapGraphEdge::kElement, |
| - V8HeapExplorer::kInternalRootObject, snapshot_->root(), |
| - group_info, group_entry); |
| + snapshot_->root()->index(), |
| + group_entry); |
| } |
| } |
| @@ -3165,56 +2992,6 @@ void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) { |
| } |
| -class SnapshotCounter : public SnapshotFillerInterface { |
| - public: |
| - explicit SnapshotCounter(HeapEntriesMap* entries) : entries_(entries) { } |
| - HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
| - entries_->Pair(ptr, allocator, HeapEntriesMap::kHeapEntryPlaceholder); |
| - return HeapEntriesMap::kHeapEntryPlaceholder; |
| - } |
| - HeapEntry* FindEntry(HeapThing ptr) { |
| - return entries_->Map(ptr); |
| - } |
| - HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
| - HeapEntry* entry = FindEntry(ptr); |
| - return entry != NULL ? entry : AddEntry(ptr, allocator); |
| - } |
| - void SetIndexedReference(HeapGraphEdge::Type, |
| - HeapThing parent_ptr, |
| - HeapEntry*, |
| - int, |
| - HeapThing child_ptr, |
| - HeapEntry*) { |
| - entries_->CountReference(parent_ptr, child_ptr); |
| - } |
| - void SetIndexedAutoIndexReference(HeapGraphEdge::Type, |
| - HeapThing parent_ptr, |
| - HeapEntry*, |
| - HeapThing child_ptr, |
| - HeapEntry*) { |
| - entries_->CountReference(parent_ptr, child_ptr); |
| - } |
| - void SetNamedReference(HeapGraphEdge::Type, |
| - HeapThing parent_ptr, |
| - HeapEntry*, |
| - const char*, |
| - HeapThing child_ptr, |
| - HeapEntry*) { |
| - entries_->CountReference(parent_ptr, child_ptr); |
| - } |
| - void SetNamedAutoIndexReference(HeapGraphEdge::Type, |
| - HeapThing parent_ptr, |
| - HeapEntry*, |
| - HeapThing child_ptr, |
| - HeapEntry*) { |
| - entries_->CountReference(parent_ptr, child_ptr); |
| - } |
| - |
| - private: |
| - HeapEntriesMap* entries_; |
| -}; |
| - |
| - |
| class SnapshotFiller : public SnapshotFillerInterface { |
| public: |
| explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) |
| @@ -3222,64 +2999,48 @@ class SnapshotFiller : public SnapshotFillerInterface { |
| collection_(snapshot->collection()), |
| entries_(entries) { } |
| HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
| - UNREACHABLE(); |
| - return NULL; |
| + HeapEntry* entry = allocator->AllocateEntry(ptr); |
| + entries_->Pair(ptr, entry->index()); |
| + return entry; |
| } |
| HeapEntry* FindEntry(HeapThing ptr) { |
| - return entries_->Map(ptr); |
| + int index = entries_->Map(ptr); |
| + return index != -1 ? &snapshot_->entries()[index] : NULL; |
| } |
| HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
| HeapEntry* entry = FindEntry(ptr); |
| return entry != NULL ? entry : AddEntry(ptr, allocator); |
| } |
| void SetIndexedReference(HeapGraphEdge::Type type, |
| - HeapThing parent_ptr, |
| - HeapEntry* parent_entry, |
| + int parent, |
| int index, |
| - HeapThing child_ptr, |
| HeapEntry* child_entry) { |
| - int child_index, retainer_index; |
| - entries_->CountReference( |
| - parent_ptr, child_ptr, &child_index, &retainer_index); |
| - parent_entry->SetIndexedReference( |
| - type, child_index, index, child_entry, retainer_index); |
| + HeapEntry* parent_entry = &snapshot_->entries()[parent]; |
| + parent_entry->SetIndexedReference(type, index, child_entry); |
| } |
| void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, |
| - HeapThing parent_ptr, |
| - HeapEntry* parent_entry, |
| - HeapThing child_ptr, |
| + int parent, |
| HeapEntry* child_entry) { |
| - int child_index, retainer_index; |
| - entries_->CountReference( |
| - parent_ptr, child_ptr, &child_index, &retainer_index); |
| - parent_entry->SetIndexedReference( |
| - type, child_index, child_index + 1, child_entry, retainer_index); |
| + HeapEntry* parent_entry = &snapshot_->entries()[parent]; |
| + int index = parent_entry->children_count() + 1; |
| + parent_entry->SetIndexedReference(type, index, child_entry); |
| } |
| void SetNamedReference(HeapGraphEdge::Type type, |
| - HeapThing parent_ptr, |
| - HeapEntry* parent_entry, |
| + int parent, |
| const char* reference_name, |
| - HeapThing child_ptr, |
| HeapEntry* child_entry) { |
| - int child_index, retainer_index; |
| - entries_->CountReference( |
| - parent_ptr, child_ptr, &child_index, &retainer_index); |
| - parent_entry->SetNamedReference( |
| - type, child_index, reference_name, child_entry, retainer_index); |
| + HeapEntry* parent_entry = &snapshot_->entries()[parent]; |
| + parent_entry->SetNamedReference(type, reference_name, child_entry); |
| } |
| void SetNamedAutoIndexReference(HeapGraphEdge::Type type, |
| - HeapThing parent_ptr, |
| - HeapEntry* parent_entry, |
| - HeapThing child_ptr, |
| + int parent, |
| HeapEntry* child_entry) { |
| - int child_index, retainer_index; |
| - entries_->CountReference( |
| - parent_ptr, child_ptr, &child_index, &retainer_index); |
| - parent_entry->SetNamedReference(type, |
| - child_index, |
| - collection_->names()->GetName(child_index + 1), |
| - child_entry, |
| - retainer_index); |
| + HeapEntry* parent_entry = &snapshot_->entries()[parent]; |
| + int index = parent_entry->children_count() + 1; |
| + parent_entry->SetNamedReference( |
| + type, |
| + collection_->names()->GetName(index), |
| + child_entry); |
| } |
| private: |
| @@ -3329,30 +3090,15 @@ bool HeapSnapshotGenerator::GenerateSnapshot() { |
| debug_heap->Verify(); |
| #endif |
| - SetProgressTotal(2); // 2 passes. |
| + SetProgressTotal(1); // 1 pass. |
| #ifdef DEBUG |
| debug_heap->Verify(); |
| #endif |
| - // Pass 1. Iterate heap contents to count entries and references. |
| - if (!CountEntriesAndReferences()) return false; |
| - |
| -#ifdef DEBUG |
| - debug_heap->Verify(); |
| -#endif |
| - |
| - // 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(V8HeapExplorer::kInternalRootObject); |
| - |
| - // Pass 2. Fill references. |
| if (!FillReferences()) return false; |
| + snapshot_->FillChildrenAndRetainers(); |
| snapshot_->RememberLastJSObjectId(); |
| if (!SetEntriesDominators()) return false; |
| @@ -3384,23 +3130,16 @@ bool HeapSnapshotGenerator::ProgressReport(bool force) { |
| void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) { |
| if (control_ == NULL) return; |
| HeapIterator iterator(HeapIterator::kFilterUnreachable); |
| - progress_total_ = ( |
| + progress_total_ = iterations_count * ( |
| v8_heap_explorer_.EstimateObjectsCount(&iterator) + |
| - dom_explorer_.EstimateObjectsCount()) * iterations_count; |
| + dom_explorer_.EstimateObjectsCount()); |
| progress_counter_ = 0; |
| } |
| -bool HeapSnapshotGenerator::CountEntriesAndReferences() { |
| - SnapshotCounter counter(&entries_); |
| - v8_heap_explorer_.AddRootEntries(&counter); |
| - return v8_heap_explorer_.IterateAndExtractReferences(&counter) |
| - && dom_explorer_.IterateAndExtractReferences(&counter); |
| -} |
| - |
| - |
| bool HeapSnapshotGenerator::FillReferences() { |
| SnapshotFiller filler(snapshot_, &entries_); |
| + v8_heap_explorer_.AddRootEntries(&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 |
| @@ -3413,19 +3152,19 @@ bool HeapSnapshotGenerator::FillReferences() { |
| } |
| -bool HeapSnapshotGenerator::IsUserGlobalReference(const HeapGraphEdge& edge) { |
| - ASSERT(edge.from() == snapshot_->root()); |
| - return edge.type() == HeapGraphEdge::kShortcut; |
| +bool HeapSnapshotGenerator::IsUserGlobalReference(const HeapGraphEdge* edge) { |
| + ASSERT(edge->from() == snapshot_->root()); |
| + return edge->type() == HeapGraphEdge::kShortcut; |
| } |
| void HeapSnapshotGenerator::MarkUserReachableObjects() { |
| List<HeapEntry*> worklist; |
| - Vector<HeapGraphEdge> children = snapshot_->root()->children(); |
| + Vector<HeapGraphEdge*> children = snapshot_->root()->children(); |
| for (int i = 0; i < children.length(); ++i) { |
| if (IsUserGlobalReference(children[i])) { |
| - worklist.Add(children[i].to()); |
| + worklist.Add(children[i]->to()); |
| } |
| } |
| @@ -3433,9 +3172,9 @@ void HeapSnapshotGenerator::MarkUserReachableObjects() { |
| HeapEntry* entry = worklist.RemoveLast(); |
| if (entry->user_reachable()) continue; |
| entry->set_user_reachable(); |
| - Vector<HeapGraphEdge> children = entry->children(); |
| + Vector<HeapGraphEdge*> children = entry->children(); |
| for (int i = 0; i < children.length(); ++i) { |
| - HeapEntry* child = children[i].to(); |
| + HeapEntry* child = children[i]->to(); |
| if (!child->user_reachable()) { |
| worklist.Add(child); |
| } |
| @@ -3464,11 +3203,11 @@ void HeapSnapshotGenerator::FillPostorderIndexes( |
| snapshot_->root()->paint(); |
| while (!nodes_to_visit.is_empty()) { |
| HeapEntry* entry = nodes_to_visit.last(); |
| - Vector<HeapGraphEdge> children = entry->children(); |
| + Vector<HeapGraphEdge*> children = entry->children(); |
| bool has_new_edges = false; |
| for (int i = 0; i < children.length(); ++i) { |
| - if (entry != root && !IsRetainingEdge(&children[i])) continue; |
| - HeapEntry* child = children[i].to(); |
| + if (entry != root && !IsRetainingEdge(children[i])) continue; |
| + HeapEntry* child = children[i]->to(); |
| if (!child->painted()) { |
| nodes_to_visit.Add(child); |
| child->paint(); |
| @@ -3476,7 +3215,7 @@ void HeapSnapshotGenerator::FillPostorderIndexes( |
| } |
| } |
| if (!has_new_edges) { |
| - entry->set_ordered_index(current_entry); |
| + entry->set_postorder_index(current_entry); |
| (*entries)[current_entry++] = entry; |
| nodes_to_visit.RemoveLast(); |
| } |
| @@ -3513,15 +3252,15 @@ bool HeapSnapshotGenerator::BuildDominatorTree( |
| 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(); |
| + Vector<HeapGraphEdge*> children = entries[root_index]->children(); |
| for (int i = 0; i < children.length(); ++i) { |
| - affected[children[i].to()->ordered_index()] = true; |
| + affected[children[i]->to()->postorder_index()] = true; |
| } |
| bool changed = true; |
| while (changed) { |
| changed = false; |
| - if (!ProgressReport(true)) return false; |
| + if (!ProgressReport(false)) return false; |
| for (int i = root_index - 1; i >= 0; --i) { |
| if (!affected[i]) continue; |
| affected[i] = false; |
| @@ -3532,7 +3271,7 @@ bool HeapSnapshotGenerator::BuildDominatorTree( |
| Vector<HeapGraphEdge*> rets = entries[i]->retainers(); |
| for (int j = 0; j < rets.length(); ++j) { |
| if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue; |
| - int ret_index = rets[j]->from()->ordered_index(); |
| + int ret_index = rets[j]->from()->postorder_index(); |
| if (dominators->at(ret_index) != kNoDominator) { |
| new_idom_index = new_idom_index == kNoDominator |
| ? ret_index |
| @@ -3546,9 +3285,9 @@ bool HeapSnapshotGenerator::BuildDominatorTree( |
| && dominators->at(i) != new_idom_index) { |
| (*dominators)[i] = new_idom_index; |
| changed = true; |
| - Vector<HeapGraphEdge> children = entries[i]->children(); |
| + Vector<HeapGraphEdge*> children = entries[i]->children(); |
| for (int j = 0; j < children.length(); ++j) { |
| - affected[children[j].to()->ordered_index()] = true; |
| + affected[children[j]->to()->postorder_index()] = true; |
| } |
| } |
| } |
| @@ -3560,7 +3299,7 @@ bool HeapSnapshotGenerator::BuildDominatorTree( |
| bool HeapSnapshotGenerator::SetEntriesDominators() { |
| MarkUserReachableObjects(); |
| // This array is used for maintaining postorder of nodes. |
| - ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); |
| + ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries().length()); |
| FillPostorderIndexes(&ordered_entries); |
| ScopedVector<int> dominators(ordered_entries.length()); |
| if (!BuildDominatorTree(ordered_entries, &dominators)) return false; |
| @@ -3576,17 +3315,18 @@ bool HeapSnapshotGenerator::CalculateRetainedSizes() { |
| // As for the dominators tree we only know parent nodes, not |
| // children, to sum up total sizes we "bubble" node's self size |
| // adding it to all of its parents. |
| - List<HeapEntry*>& entries = *snapshot_->entries(); |
| + List<HeapEntry>& entries = snapshot_->entries(); |
| for (int i = 0; i < entries.length(); ++i) { |
| - HeapEntry* entry = entries[i]; |
| + HeapEntry* entry = &entries[i]; |
| entry->set_retained_size(entry->self_size()); |
| } |
| for (int i = 0; i < entries.length(); ++i) { |
| - HeapEntry* entry = entries[i]; |
| - int entry_size = entry->self_size(); |
| - for (HeapEntry* dominator = entry->dominator(); |
| - dominator != entry; |
| - entry = dominator, dominator = entry->dominator()) { |
| + int entry_size = entries[i].self_size(); |
| + HeapEntry* current = &entries[i]; |
| + for (HeapEntry* dominator = current->dominator(); |
| + dominator != current; |
| + current = dominator, dominator = current->dominator()) { |
| + ASSERT(current->dominator() != NULL); |
| dominator->add_retained_size(entry_size); |
| } |
| } |
| @@ -3695,14 +3435,13 @@ void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { |
| writer_ = new OutputStreamWriter(stream); |
| HeapSnapshot* original_snapshot = NULL; |
| - if (snapshot_->raw_entries_size() >= |
| + if (snapshot_->RawSnapshotSize() >= |
| SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize) { |
| // The snapshot is too big. Serialize a fake snapshot. |
| original_snapshot = snapshot_; |
| snapshot_ = CreateFakeSnapshot(); |
| } |
| - // Since nodes graph is cyclic, we need the first pass to enumerate |
| - // them. Strings can be serialized in one pass. |
| + |
| SerializeImpl(); |
| delete writer_; |
| @@ -3720,42 +3459,24 @@ HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() { |
| HeapSnapshot::kFull, |
| snapshot_->title(), |
| snapshot_->uid()); |
| - result->AllocateEntries(2, 1, 0); |
| - HeapEntry* root = result->AddRootEntry(1); |
| + result->AddRootEntry(); |
| const char* text = snapshot_->collection()->names()->GetFormatted( |
| "The snapshot is too big. " |
| "Maximum snapshot size is %" V8_PTR_PREFIX "u MB. " |
| "Actual snapshot size is %" V8_PTR_PREFIX "u MB.", |
| SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize / MB, |
| - (snapshot_->raw_entries_size() + MB - 1) / MB); |
| - HeapEntry* message = result->AddEntry( |
| - HeapEntry::kString, text, 0, 4, 0, 0); |
| - root->SetUnidirElementReference(0, 1, message); |
| + (snapshot_->RawSnapshotSize() + MB - 1) / MB); |
| + HeapEntry* message = result->AddEntry(HeapEntry::kString, text, 0, 4); |
| + result->root()->SetIndexedReference(HeapGraphEdge::kElement, 1, message); |
| + result->FillChildrenAndRetainers(); |
| result->SetDominatorsToSelf(); |
| return result; |
| } |
| -void HeapSnapshotJSONSerializer::CalculateNodeIndexes( |
| - const List<HeapEntry*>& nodes) { |
| - // type,name,id,self_size,retained_size,dominator,children_index. |
| - const int node_fields_count = 7; |
| - // Root must be the first. |
| - ASSERT(nodes.first() == snapshot_->root()); |
| - // Rewrite node indexes, so they refer to actual array positions. Do this |
| - // only once. |
| - if (nodes[0]->entry_index() == -1) { |
| - int index = 0; |
| - for (int i = 0; i < nodes.length(); ++i, index += node_fields_count) { |
| - nodes[i]->set_entry_index(index); |
| - } |
| - } |
| -} |
| - |
| - |
| void HeapSnapshotJSONSerializer::SerializeImpl() { |
| - List<HeapEntry*>& nodes = *(snapshot_->entries()); |
| - CalculateNodeIndexes(nodes); |
| + List<HeapEntry>& nodes = snapshot_->entries(); |
| + CHECK_EQ(0, snapshot_->root()->index()); |
| writer_->AddCharacter('{'); |
| writer_->AddString("\"snapshot\":{"); |
| SerializeSnapshot(); |
| @@ -3831,19 +3552,19 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge, |
| buffer[buffer_pos++] = ','; |
| buffer_pos = itoa(edge_name_or_index, buffer, buffer_pos); |
| buffer[buffer_pos++] = ','; |
| - buffer_pos = itoa(edge->to()->entry_index(), buffer, buffer_pos); |
| + buffer_pos = itoa(entry_index(edge->to()), buffer, buffer_pos); |
| buffer[buffer_pos++] = '\0'; |
| writer_->AddString(buffer.start()); |
| } |
| -void HeapSnapshotJSONSerializer::SerializeEdges(const List<HeapEntry*>& nodes) { |
| +void HeapSnapshotJSONSerializer::SerializeEdges(const List<HeapEntry>& nodes) { |
| bool first_edge = true; |
| for (int i = 0; i < nodes.length(); ++i) { |
| - HeapEntry* entry = nodes[i]; |
| - Vector<HeapGraphEdge> children = entry->children(); |
| + HeapEntry* entry = &nodes[i]; |
| + Vector<HeapGraphEdge*> children = entry->children(); |
| for (int j = 0; j < children.length(); ++j) { |
| - SerializeEdge(&children[j], first_edge); |
| + SerializeEdge(children[j], first_edge); |
| first_edge = false; |
| if (writer_->aborted()) return; |
| } |
| @@ -3861,7 +3582,7 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry, |
| EmbeddedVector<char, kBufferSize> buffer; |
| int buffer_pos = 0; |
| buffer[buffer_pos++] = '\n'; |
| - if (entry->entry_index() != 0) { |
| + if (entry_index(entry) != 0) { |
| buffer[buffer_pos++] = ','; |
| } |
| buffer_pos = itoa(entry->type(), buffer, buffer_pos); |
| @@ -3874,7 +3595,7 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry, |
| buffer[buffer_pos++] = ','; |
| buffer_pos = itoa(entry->retained_size(), buffer, buffer_pos); |
| buffer[buffer_pos++] = ','; |
| - buffer_pos = itoa(entry->dominator()->entry_index(), buffer, buffer_pos); |
| + buffer_pos = itoa(entry_index(entry->dominator()), buffer, buffer_pos); |
| buffer[buffer_pos++] = ','; |
| buffer_pos = itoa(edges_index, buffer, buffer_pos); |
| buffer[buffer_pos++] = '\0'; |
| @@ -3882,13 +3603,12 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry, |
| } |
| -void HeapSnapshotJSONSerializer::SerializeNodes(const List<HeapEntry*>& nodes) { |
| - const int edge_fields_count = 3; // type,name|index,to_node. |
| +void HeapSnapshotJSONSerializer::SerializeNodes(const List<HeapEntry>& nodes) { |
| int edges_index = 0; |
| for (int i = 0; i < nodes.length(); ++i) { |
| - HeapEntry* entry = nodes[i]; |
| + HeapEntry* entry = &nodes[i]; |
| SerializeNode(entry, edges_index); |
| - edges_index += entry->children().length() * edge_fields_count; |
| + edges_index += entry->children().length() * kEdgeFieldsCount; |
| if (writer_->aborted()) return; |
| } |
| } |
| @@ -3952,9 +3672,9 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() { |
| #undef JSON_O |
| #undef JSON_A |
| writer_->AddString(",\"node_count\":"); |
| - writer_->AddNumber(snapshot_->entries()->length()); |
| + writer_->AddNumber(snapshot_->entries().length()); |
| writer_->AddString(",\"edge_count\":"); |
| - writer_->AddNumber(snapshot_->number_of_edges()); |
| + writer_->AddNumber(snapshot_->edges().length()); |
| } |