Index: src/profile-generator.cc |
diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
index c91e83bb78fe37cc2c75933e297e2f70a1c788d6..2c6c6e395c2793f84cf1fee8f328b8cd72ae5ed5 100644 |
--- a/src/profile-generator.cc |
+++ b/src/profile-generator.cc |
@@ -931,78 +931,72 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
} |
-void HeapGraphEdge::Init( |
- int child_index, Type type, const char* name, HeapEntry* to) { |
+HeapGraphEdge::HeapGraphEdge( |
+ Type type, const char* name, int from, int to) : |
+ type_(type), |
+ from_index_(from), |
+ to_index_(to), |
+ name_(name) { |
ASSERT(type == kContextVariable |
- || type == kProperty |
- || type == kInternal |
- || type == kShortcut); |
- child_index_ = child_index; |
- type_ = type; |
- name_ = name; |
- to_ = to; |
+ || type == kProperty |
+ || type == kInternal |
+ || type == kShortcut); |
} |
-void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) { |
+HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to) : |
+ type_(type), |
+ from_index_(from), |
+ to_index_(to), |
+ index_(index) { |
ASSERT(type == kElement || type == kHidden || type == kWeak); |
- child_index_ = child_index; |
- type_ = type; |
- index_ = index; |
- to_ = to; |
} |
-void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { |
- Init(child_index, kElement, index, to); |
+void HeapGraphEdge::ReplaceToIndexWithEntry(HeapSnapshot* snapshot) { |
+ to_entry_ = &snapshot->entries()[to_index_]; |
} |
-void HeapEntry::Init(HeapSnapshot* snapshot, |
+const int HeapEntry::kNoEntry = -1; |
+ |
+HeapEntry::HeapEntry(HeapSnapshot* snapshot, |
Type type, |
const char* name, |
SnapshotObjectId id, |
- int self_size, |
- int children_count, |
- int retainers_count) { |
- snapshot_ = snapshot; |
- type_ = type; |
- painted_ = false; |
- user_reachable_ = false; |
- name_ = name; |
- self_size_ = self_size; |
- retained_size_ = 0; |
- entry_index_ = -1; |
- children_count_ = children_count; |
- retainers_count_ = retainers_count; |
- dominator_ = NULL; |
- id_ = id; |
-} |
+ int self_size) : |
+ painted_(false), |
+ user_reachable_(false), |
+ dominator_(kNoEntry), |
+ type_(type), |
+ retainers_count_(0), |
+ retainers_index_(-1), |
+ children_count_(0), |
+ children_index_(-1), |
+ self_size_(self_size), |
+ retained_size_(0), |
+ id_(id), |
+ snapshot_(snapshot), |
+ name_(name) { } |
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(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(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_index_(HeapEntry::kNoEntry), |
+ gc_roots_index_(HeapEntry::kNoEntry), |
+ natives_root_index_(HeapEntry::kNoEntry), |
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_indexes_[i] = HeapEntry::kNoEntry; |
} |
} |
-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,80 @@ void HeapSnapshot::ClearPaint() { |
} |
-HeapEntry* HeapSnapshot::AddRootEntry(int children_count) { |
- ASSERT(root_entry_ == NULL); |
+HeapEntry* HeapSnapshot::AddRootEntry() { |
+ ASSERT(root_index_ == HeapEntry::kNoEntry); |
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_index_ = entry->index(); |
+ ASSERT(root_index_ == 0); |
+ 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_index_ == HeapEntry::kNoEntry); |
+ HeapEntry* entry = AddEntry(HeapEntry::kObject, |
+ "(GC roots)", |
+ HeapObjectsMap::kGcRootsObjectId, |
+ 0); |
+ gc_roots_index_ = 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_indexes_[tag] == HeapEntry::kNoEntry); |
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_indexes_[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(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() { |
+ ASSERT(children().is_empty()); |
+ children().Allocate(edges().length()); |
+ ASSERT(retainers().is_empty()); |
+ retainers().Allocate(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); |
+ } |
+ ASSERT(edges().length() == children_index); |
+ ASSERT(edges().length() == retainers_index); |
+ for (int i = 0; i < edges().length(); ++i) { |
+ HeapGraphEdge* edge = &edges()[i]; |
+ edge->ReplaceToIndexWithEntry(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 +1259,10 @@ static int SortByIds(const T* entry1_ptr, |
List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { |
if (sorted_entries_.is_empty()) { |
- sorted_entries_.AddAll(entries_); |
+ sorted_entries_.Allocate(entries_.length()); |
+ for (int i = 0; i < entries_.length(); ++i) { |
+ sorted_entries_[i] = &entries_[i]; |
+ } |
sorted_entries_.Sort(SortByIds); |
} |
return &sorted_entries_; |
@@ -1299,6 +1274,22 @@ void HeapSnapshot::Print(int max_depth) { |
} |
+template<typename T, class P> |
+static size_t GetMemoryUsedByList(const List<T,P>& list) { |
+ return list.capacity() * sizeof(T); |
+} |
+ |
+ |
+size_t HeapSnapshot::RawSnapshotSize() const { |
+ return |
+ GetMemoryUsedByList(entries_) + |
+ GetMemoryUsedByList(edges_) + |
+ GetMemoryUsedByList(children_) + |
+ GetMemoryUsedByList(retainers_) + |
+ GetMemoryUsedByList(sorted_entries_); |
+} |
+ |
+ |
// We split IDs on evens for embedder objects (see |
// HeapObjectsMap::GenerateId) and odds for native objects. |
const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1; |
@@ -1567,99 +1558,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) { |
-} |
- |
- |
-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; |
+ : entries_(HeapThingsMatch) { |
} |
-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 HeapEntry::kNoEntry; |
+ 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 +1590,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 +1605,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 +1649,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 +1787,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 +1819,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 +1879,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 +1948,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 +1960,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 +1986,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 +2009,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 +2051,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 +2073,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 +2085,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 +2107,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 +2154,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 +2227,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 +2253,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 +2379,7 @@ bool V8HeapExplorer::IterateAndExtractReferences( |
filler_ = NULL; |
return false; |
} |
+ |
SetRootGcRootsReference(); |
RootsReferencesExtractor extractor; |
heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG); |
@@ -2538,7 +2387,7 @@ bool V8HeapExplorer::IterateAndExtractReferences( |
heap_->IterateRoots(&extractor, VISIT_ALL); |
extractor.FillReferences(this); |
filler_ = NULL; |
- return progress_->ProgressReport(false); |
+ return progress_->ProgressReport(true); |
} |
@@ -2586,55 +2435,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 +2485,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 +2502,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 +2541,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 +2558,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 +2567,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 +2583,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 +2593,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 +2614,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 +2738,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 +2746,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 +2839,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 != HeapEntry::kNoEntry); |
Object*** children = group->children_; |
for (size_t j = 0; j < group->length_; ++j) { |
Object* child = *children[j]; |
@@ -3019,9 +2849,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 +2929,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 +2947,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 +2960,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 +2980,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 +2996,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 +3003,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 != HeapEntry::kNoEntry ? &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 +3094,15 @@ bool HeapSnapshotGenerator::GenerateSnapshot() { |
debug_heap->Verify(); |
#endif |
- SetProgressTotal(2); // 2 passes. |
- |
-#ifdef DEBUG |
- debug_heap->Verify(); |
-#endif |
- |
- // Pass 1. Iterate heap contents to count entries and references. |
- if (!CountEntriesAndReferences()) return false; |
+ SetProgressTotal(1); // 1 pass. |
#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 +3134,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 +3156,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 +3176,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 +3207,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 +3219,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(); |
} |
@@ -3504,8 +3247,7 @@ bool HeapSnapshotGenerator::BuildDominatorTree( |
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; |
+ for (int i = 0; i < root_index; ++i) (*dominators)[i] = HeapEntry::kNoEntry; |
(*dominators)[root_index] = root_index; |
// The affected array is used to mark entries which dominators |
@@ -3513,28 +3255,28 @@ 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; |
// If dominator of the entry has already been set to root, |
// then it can't propagate any further. |
if ((*dominators)[i] == root_index) continue; |
- int new_idom_index = kNoDominator; |
+ int new_idom_index = HeapEntry::kNoEntry; |
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(); |
- if (dominators->at(ret_index) != kNoDominator) { |
- new_idom_index = new_idom_index == kNoDominator |
+ int ret_index = rets[j]->from()->postorder_index(); |
+ if (dominators->at(ret_index) != HeapEntry::kNoEntry) { |
+ new_idom_index = new_idom_index == HeapEntry::kNoEntry |
? ret_index |
: Intersect(ret_index, new_idom_index, *dominators); |
// If idom has already reached the root, it doesn't make sense |
@@ -3542,13 +3284,13 @@ bool HeapSnapshotGenerator::BuildDominatorTree( |
if (new_idom_index == root_index) break; |
} |
} |
- if (new_idom_index != kNoDominator |
+ if (new_idom_index != HeapEntry::kNoEntry |
&& 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,12 +3302,12 @@ 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; |
for (int i = 0; i < ordered_entries.length(); ++i) { |
- ASSERT(dominators[i] >= 0); |
+ ASSERT(dominators[i] != HeapEntry::kNoEntry); |
ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]); |
} |
return true; |
@@ -3576,17 +3318,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); |
} |
} |
@@ -3690,19 +3433,23 @@ class OutputStreamWriter { |
}; |
+// type, name|index, to_node. |
+const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3; |
+// type, name, id, self_size, retained_size, dominator, children_index. |
+const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 7; |
+ |
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { |
ASSERT(writer_ == NULL); |
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 +3467,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(); |
+ ASSERT(0 == snapshot_->root()->index()); |
writer_->AddCharacter('{'); |
writer_->AddString("\"snapshot\":{"); |
SerializeSnapshot(); |
@@ -3831,19 +3560,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 +3590,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 +3603,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 +3611,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 +3680,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()); |
} |