name_ = name;
self_size_ = self_size;
retained_size_ = 0;
+ entry_index_ = -1;
children_count_ = children_count;
retainers_count_ = retainers_count;
dominator_ = NULL;
template <> struct SnapshotSizeConstants<4> {
static const int kExpectedHeapGraphEdgeSize = 12;
- static const int kExpectedHeapEntrySize = 32;
+ static const int kExpectedHeapEntrySize = 36;
static const size_t kMaxSerializableSnapshotRawSize = 256 * MB;
};
gc_roots_entry_(NULL),
natives_root_entry_(NULL),
raw_entries_(NULL),
- entries_sorted_(false),
max_snapshot_js_object_id_(0) {
STATIC_CHECK(
sizeof(HeapGraphEdge) ==
HeapEntry* HeapSnapshot::AddRootEntry(int children_count) {
ASSERT(root_entry_ == NULL);
+ ASSERT(entries_.is_empty()); // Root entry must be the first one.
return (root_entry_ = AddEntry(HeapEntry::kObject,
"",
HeapObjectsMap::kInternalRootObjectId,
List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() {
- if (!entries_sorted_) {
- entries_.Sort(SortByIds);
- entries_sorted_ = true;
+ if (sorted_entries_.is_empty()) {
+ sorted_entries_.AddAll(entries_);
+ sorted_entries_.Sort(SortByIds);
}
- return &entries_;
+ return &sorted_entries_;
}
}
-void HeapEntriesMap::AllocateEntries() {
- for (HashMap::Entry* p = entries_.Start();
- p != NULL;
- p = entries_.Next(p)) {
- EntryInfo* entry_info = 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(
- p->key,
+ 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_.total_retainers_count());
// Allocate heap objects to entries hash map.
- entries_.AllocateEntries();
+ entries_.AllocateEntries(V8HeapExplorer::kInternalRootObject);
// Pass 2. Fill references.
if (!FillReferences()) return false;
}
// Since nodes graph is cyclic, we need the first pass to enumerate
// them. Strings can be serialized in one pass.
- EnumerateNodes();
SerializeImpl();
delete writer_;
}
-class HeapSnapshotJSONSerializerEnumerator {
- public:
- explicit HeapSnapshotJSONSerializerEnumerator(HeapSnapshotJSONSerializer* s)
- : s_(s) {
- }
- void Apply(HeapEntry** entry) {
- s_->GetNodeId(*entry);
- }
- private:
- HeapSnapshotJSONSerializer* s_;
-};
-
-void HeapSnapshotJSONSerializer::EnumerateNodes() {
- GetNodeId(snapshot_->root()); // Make sure root gets the first id.
- HeapSnapshotJSONSerializerEnumerator iter(this);
- snapshot_->IterateEntries(&iter);
-}
-
-
-int HeapSnapshotJSONSerializer::GetNodeId(HeapEntry* entry) {
- HashMap::Entry* cache_entry = nodes_.Lookup(entry, ObjectHash(entry), true);
- if (cache_entry->value == NULL) {
- cache_entry->value = reinterpret_cast<void*>(next_node_id_++);
- }
- return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
-}
-
-
int HeapSnapshotJSONSerializer::GetStringId(const char* s) {
HashMap::Entry* cache_entry = strings_.Lookup(
const_cast<char*>(s), ObjectHash(s), true);
buffer[buffer_pos++] = ',';
buffer_pos = itoa(edge_name_or_index, buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = itoa(GetNodeId(edge->to()), buffer, buffer_pos);
+ buffer_pos = itoa(edge->to()->entry_index(), buffer, buffer_pos);
buffer[buffer_pos++] = '\0';
writer_->AddString(buffer.start());
}
buffer[buffer_pos++] = ',';
buffer_pos = itoa(entry->retained_size(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = itoa(GetNodeId(entry->dominator()), buffer, buffer_pos);
+ buffer_pos = itoa(entry->dominator()->entry_index(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
buffer_pos = itoa(children.length(), buffer, buffer_pos);
buffer[buffer_pos++] = '\0';
const int node_fields_count = 7;
// type,name,id,self_size,retained_size,dominator,children_count.
const int edge_fields_count = 3; // type,name|index,to_node.
- List<HashMap::Entry*> sorted_nodes;
- SortHashMap(&nodes_, &sorted_nodes);
- // Rewrite node ids, so they refer to actual array positions.
- if (sorted_nodes.length() > 1) {
+
+ List<HeapEntry*>& nodes = *(snapshot_->entries());
+ // 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) {
// Nodes start from array index 1.
- int prev_value = 1;
- sorted_nodes[0]->value = reinterpret_cast<void*>(prev_value);
- for (int i = 1; i < sorted_nodes.length(); ++i) {
- HeapEntry* prev_heap_entry =
- reinterpret_cast<HeapEntry*>(sorted_nodes[i-1]->key);
- prev_value += node_fields_count +
- prev_heap_entry->children().length() * edge_fields_count;
- sorted_nodes[i]->value = reinterpret_cast<void*>(prev_value);
+ int index = 1;
+ for (int i = 0; i < nodes.length(); ++i) {
+ HeapEntry* node = nodes[i];
+ node->set_entry_index(index);
+ index += node_fields_count +
+ node->children().length() * edge_fields_count;
}
}
- for (int i = 0; i < sorted_nodes.length(); ++i) {
- SerializeNode(reinterpret_cast<HeapEntry*>(sorted_nodes[i]->key));
+
+ for (int i = 0; i < nodes.length(); ++i) {
+ SerializeNode(nodes[i]);
if (writer_->aborted()) return;
}
}
void set_retained_size(int value) { retained_size_ = value; }
int ordered_index() { return ordered_index_; }
void set_ordered_index(int value) { ordered_index_ = value; }
+ int entry_index() { return entry_index_; }
+ void set_entry_index(int value) { entry_index_ = value; }
Vector<HeapGraphEdge> children() {
return Vector<HeapGraphEdge>(children_arr(), children_count_); }
int ordered_index_; // Used during dominator tree building.
int retained_size_; // At that moment, there is no retained size yet.
};
+ int entry_index_;
SnapshotObjectId id_;
HeapEntry* dominator_;
HeapSnapshot* snapshot_;
void ClearPaint();
HeapEntry* GetEntryById(SnapshotObjectId id);
List<HeapEntry*>* GetSortedEntriesList();
- template<class Visitor>
- void IterateEntries(Visitor* visitor) { entries_.Iterate(visitor); }
void SetDominatorsToSelf();
void Print(int max_depth);
HeapEntry* gc_subroot_entries_[VisitorSynchronization::kNumberOfSyncTags];
char* raw_entries_;
List<HeapEntry*> entries_;
- bool entries_sorted_;
+ List<HeapEntry*> sorted_entries_;
size_t raw_entries_size_;
SnapshotObjectId max_snapshot_js_object_id_;
HeapEntriesMap();
~HeapEntriesMap();
- void AllocateEntries();
+ void AllocateEntries(HeapThing root_object);
HeapEntry* Map(HeapThing thing);
void Pair(HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry);
void CountReference(HeapThing from, HeapThing to,
int retainers_count;
};
+ static inline void AllocateHeapEntryForMapEntry(HashMap::Entry* map_entry);
+
static uint32_t Hash(HeapThing thing) {
return ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
public:
explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
: snapshot_(snapshot),
- nodes_(ObjectsMatch),
strings_(ObjectsMatch),
next_node_id_(1),
next_string_id_(1),
v8::internal::kZeroHashSeed);
}
- void EnumerateNodes();
HeapSnapshot* CreateFakeSnapshot();
- int GetNodeId(HeapEntry* entry);
int GetStringId(const char* s);
void SerializeEdge(HeapGraphEdge* edge);
void SerializeImpl();
static const int kMaxSerializableSnapshotRawSize;
HeapSnapshot* snapshot_;
- HashMap nodes_;
HashMap strings_;
int next_node_id_;
int next_string_id_;