| Index: src/profile-generator.cc
|
| ===================================================================
|
| --- src/profile-generator.cc (revision 11244)
|
| +++ src/profile-generator.cc (working copy)
|
| @@ -975,6 +975,7 @@
|
| name_ = name;
|
| self_size_ = self_size;
|
| retained_size_ = 0;
|
| + entry_index_ = -1;
|
| children_count_ = children_count;
|
| retainers_count_ = retainers_count;
|
| dominator_ = NULL;
|
| @@ -1108,7 +1109,7 @@
|
|
|
| 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;
|
| };
|
|
|
| @@ -1133,7 +1134,6 @@
|
| gc_roots_entry_(NULL),
|
| natives_root_entry_(NULL),
|
| raw_entries_(NULL),
|
| - entries_sorted_(false),
|
| max_snapshot_js_object_id_(0) {
|
| STATIC_CHECK(
|
| sizeof(HeapGraphEdge) ==
|
| @@ -1185,6 +1185,7 @@
|
|
|
| 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,
|
| @@ -1285,11 +1286,11 @@
|
|
|
|
|
| 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_;
|
| }
|
|
|
|
|
| @@ -1514,20 +1515,39 @@
|
| }
|
|
|
|
|
| -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;
|
| }
|
|
|
|
|
| @@ -3106,7 +3126,7 @@
|
| 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;
|
| @@ -3417,7 +3437,6 @@
|
| }
|
| // Since nodes graph is cyclic, we need the first pass to enumerate
|
| // them. Strings can be serialized in one pass.
|
| - EnumerateNodes();
|
| SerializeImpl();
|
|
|
| delete writer_;
|
| @@ -3470,34 +3489,6 @@
|
| }
|
|
|
|
|
| -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);
|
| @@ -3548,7 +3539,7 @@
|
| 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());
|
| }
|
| @@ -3575,7 +3566,7 @@
|
| 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';
|
| @@ -3645,23 +3636,25 @@
|
| 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;
|
| }
|
| }
|
|
|