Index: src/profile-generator.cc |
diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
index be9c5d7dd77b00b867bce1ed6508a848713f321c..cbcc3758f0d9f468f2f441f9d82637000677e8b9 100644 |
--- a/src/profile-generator.cc |
+++ b/src/profile-generator.cc |
@@ -1134,6 +1134,7 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
gc_roots_entry_(NULL), |
natives_root_entry_(NULL), |
raw_entries_(NULL), |
+ number_of_edges_(0), |
max_snapshot_js_object_id_(0) { |
STATIC_CHECK( |
sizeof(HeapGraphEdge) == |
@@ -1167,6 +1168,7 @@ 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_); |
@@ -3470,14 +3472,37 @@ HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() { |
} |
+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); |
writer_->AddCharacter('{'); |
writer_->AddString("\"snapshot\":{"); |
SerializeSnapshot(); |
if (writer_->aborted()) return; |
writer_->AddString("},\n"); |
writer_->AddString("\"nodes\":["); |
- SerializeNodes(); |
+ SerializeNodes(nodes); |
+ if (writer_->aborted()) return; |
+ writer_->AddString("],\n"); |
+ writer_->AddString("\"edges\":["); |
+ SerializeEdges(nodes); |
if (writer_->aborted()) return; |
writer_->AddString("],\n"); |
writer_->AddString("\"strings\":["); |
@@ -3524,7 +3549,8 @@ static int itoa(int value, const Vector<char>& buffer, int buffer_pos) { |
} |
-void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) { |
+void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge, |
+ bool first_edge) { |
// The buffer needs space for 3 ints, 3 commas and \0 |
static const int kBufferSize = |
MaxDecimalDigitsIn<sizeof(int)>::kSigned * 3 + 3 + 1; // NOLINT |
@@ -3534,7 +3560,9 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) { |
|| edge->type() == HeapGraphEdge::kWeak |
? edge->index() : GetStringId(edge->name()); |
int buffer_pos = 0; |
- buffer[buffer_pos++] = ','; |
+ if (!first_edge) { |
+ buffer[buffer_pos++] = ','; |
+ } |
buffer_pos = itoa(edge->type(), buffer, buffer_pos); |
buffer[buffer_pos++] = ','; |
buffer_pos = itoa(edge_name_or_index, buffer, buffer_pos); |
@@ -3545,17 +3573,33 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) { |
} |
-void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { |
+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(); |
+ for (int j = 0; j < children.length(); ++j) { |
+ SerializeEdge(&children[j], first_edge); |
+ first_edge = false; |
+ if (writer_->aborted()) return; |
+ } |
+ } |
+} |
+ |
+ |
+void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry, |
+ int edges_index) { |
// The buffer needs space for 6 ints, 1 uint32_t, 7 commas, \n and \0 |
static const int kBufferSize = |
6 * MaxDecimalDigitsIn<sizeof(int)>::kSigned // NOLINT |
+ MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned // NOLINT |
+ 7 + 1 + 1; |
EmbeddedVector<char, kBufferSize> buffer; |
- Vector<HeapGraphEdge> children = entry->children(); |
int buffer_pos = 0; |
buffer[buffer_pos++] = '\n'; |
- buffer[buffer_pos++] = ','; |
+ if (entry->entry_index() != 0) { |
+ buffer[buffer_pos++] = ','; |
+ } |
buffer_pos = itoa(entry->type(), buffer, buffer_pos); |
buffer[buffer_pos++] = ','; |
buffer_pos = itoa(GetStringId(entry->name()), buffer, buffer_pos); |
@@ -3568,93 +3612,19 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { |
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_pos = itoa(edges_index, buffer, buffer_pos); |
buffer[buffer_pos++] = '\0'; |
writer_->AddString(buffer.start()); |
- for (int i = 0; i < children.length(); ++i) { |
- SerializeEdge(&children[i]); |
- if (writer_->aborted()) return; |
- } |
} |
-void HeapSnapshotJSONSerializer::SerializeNodes() { |
- // The first (zero) item of nodes array is an object describing node |
- // serialization layout. We use a set of macros to improve |
- // readability. |
-#define JSON_A(s) "["s"]" |
-#define JSON_O(s) "{"s"}" |
-#define JSON_S(s) "\""s"\"" |
- writer_->AddString(JSON_O( |
- JSON_S("fields") ":" JSON_A( |
- JSON_S("type") |
- "," JSON_S("name") |
- "," JSON_S("id") |
- "," JSON_S("self_size") |
- "," JSON_S("retained_size") |
- "," JSON_S("dominator") |
- "," JSON_S("children_count") |
- "," JSON_S("children")) |
- "," JSON_S("types") ":" JSON_A( |
- JSON_A( |
- JSON_S("hidden") |
- "," JSON_S("array") |
- "," JSON_S("string") |
- "," JSON_S("object") |
- "," JSON_S("code") |
- "," JSON_S("closure") |
- "," JSON_S("regexp") |
- "," JSON_S("number") |
- "," JSON_S("native") |
- "," JSON_S("synthetic")) |
- "," JSON_S("string") |
- "," JSON_S("number") |
- "," JSON_S("number") |
- "," JSON_S("number") |
- "," JSON_S("number") |
- "," JSON_S("number") |
- "," JSON_O( |
- JSON_S("fields") ":" JSON_A( |
- JSON_S("type") |
- "," JSON_S("name_or_index") |
- "," JSON_S("to_node")) |
- "," JSON_S("types") ":" JSON_A( |
- JSON_A( |
- JSON_S("context") |
- "," JSON_S("element") |
- "," JSON_S("property") |
- "," JSON_S("internal") |
- "," JSON_S("hidden") |
- "," JSON_S("shortcut") |
- "," JSON_S("weak")) |
- "," JSON_S("string_or_number") |
- "," JSON_S("node")))))); |
-#undef JSON_S |
-#undef JSON_O |
-#undef JSON_A |
- |
- const int node_fields_count = 7; |
- // type,name,id,self_size,retained_size,dominator,children_count. |
+void HeapSnapshotJSONSerializer::SerializeNodes(const List<HeapEntry*>& nodes) { |
const int edge_fields_count = 3; // type,name|index,to_node. |
- |
- 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 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; |
- } |
- } |
- |
+ int edges_index = 0; |
for (int i = 0; i < nodes.length(); ++i) { |
- SerializeNode(nodes[i]); |
+ HeapEntry* entry = nodes[i]; |
+ SerializeNode(entry, edges_index); |
+ edges_index += entry->children().length() * edge_fields_count; |
if (writer_->aborted()) return; |
} |
} |
@@ -3666,6 +3636,61 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() { |
writer_->AddString("\""); |
writer_->AddString(",\"uid\":"); |
writer_->AddNumber(snapshot_->uid()); |
+ writer_->AddString(",\"meta\":"); |
+ // The object describing node serialization layout. |
+ // We use a set of macros to improve readability. |
+#define JSON_A(s) "["s"]" |
+#define JSON_O(s) "{"s"}" |
+#define JSON_S(s) "\""s"\"" |
+ writer_->AddString(JSON_O( |
+ JSON_S("node_fields") ":" JSON_A( |
+ JSON_S("type") "," |
+ JSON_S("name") "," |
+ JSON_S("id") "," |
+ JSON_S("self_size") "," |
+ JSON_S("retained_size") "," |
+ JSON_S("dominator") "," |
+ JSON_S("edges_index")) "," |
+ JSON_S("node_types") ":" JSON_A( |
+ JSON_A( |
+ JSON_S("hidden") "," |
+ JSON_S("array") "," |
+ JSON_S("string") "," |
+ JSON_S("object") "," |
+ JSON_S("code") "," |
+ JSON_S("closure") "," |
+ JSON_S("regexp") "," |
+ JSON_S("number") "," |
+ JSON_S("native") "," |
+ JSON_S("synthetic")) "," |
+ JSON_S("string") "," |
+ JSON_S("number") "," |
+ JSON_S("number") "," |
+ JSON_S("number") "," |
+ JSON_S("number") "," |
+ JSON_S("number")) "," |
+ JSON_S("edge_fields") ":" JSON_A( |
+ JSON_S("type") "," |
+ JSON_S("name_or_index") "," |
+ JSON_S("to_node")) "," |
+ JSON_S("edge_types") ":" JSON_A( |
+ JSON_A( |
+ JSON_S("context") "," |
+ JSON_S("element") "," |
+ JSON_S("property") "," |
+ JSON_S("internal") "," |
+ JSON_S("hidden") "," |
+ JSON_S("shortcut") "," |
+ JSON_S("weak")) "," |
+ JSON_S("string_or_number") "," |
+ JSON_S("node")))); |
+#undef JSON_S |
+#undef JSON_O |
+#undef JSON_A |
+ writer_->AddString(",\"node_count\":"); |
+ writer_->AddNumber(snapshot_->entries()->length()); |
+ writer_->AddString(",\"edge_count\":"); |
+ writer_->AddNumber(snapshot_->number_of_edges()); |
} |