forked from facebook/hermes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchrome_snapshot_parser.py
111 lines (100 loc) · 3.13 KB
/
chrome_snapshot_parser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python3
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
import argparse
import json
"""
Takes in a Chrome heap snapshot and makes the output into more explorable JSON
"""
# The order of all these lists must match the order of fields that v8 outputs.
EDGE_FIELDS = ["type", "name_or_index", "to_node"]
EDGE_TYPES = [
"context",
"element",
"property",
"internal",
"hidden",
"shortcut",
"weak",
]
NODE_FIELDS = ["type", "name", "id", "self_size", "edge_count", "trace_node_id"]
NODE_TYPES = [
"hidden",
"array",
"string",
"object",
"code",
"closure",
"regexp",
"number",
"native",
"synthetic",
"concatenated string",
"sliced string",
"symbol",
"bigint",
]
LOCATION_FIELDS = ["object_index", "script_id", "line", "column"]
def main():
parser = argparse.ArgumentParser()
parser.add_argument("heapsnapshot")
parser.add_argument("out")
args = parser.parse_args()
with open(args.heapsnapshot, "r") as f:
root = json.load(f)
curr_node = 0
curr_edge = 0
nodes = []
while curr_node < len(root["nodes"]):
raw_type, name, id, self_size, edge_count, trace_node_id = root["nodes"][
curr_node : curr_node + len(NODE_FIELDS)
]
edges = []
end_edge = curr_edge + edge_count * len(EDGE_FIELDS)
while curr_edge < end_edge:
raw_edge_type, name_or_index, to_node = root["edges"][
curr_edge : curr_edge + len(EDGE_FIELDS)
]
real_type = EDGE_TYPES[raw_edge_type]
edges.append(
{
"type": real_type,
"name_or_index": root["strings"][name_or_index]
if real_type
in ("context", "property", "internal", "shortcut", "weak")
else name_or_index,
"to_node": to_node // len(NODE_FIELDS),
}
)
curr_edge += len(EDGE_FIELDS)
nodes.append(
{
"type": NODE_TYPES[raw_type],
"name": root["strings"][name],
"id": id,
"self_size": self_size,
"edges": edges,
"trace_node_id": trace_node_id,
}
)
curr_node += len(NODE_FIELDS)
# Iterate through locations and add the location resolution to nodes
curr_loc = 0
while curr_loc < len(root["locations"]):
object_index, script_id, line, column = root["locations"][
curr_loc : curr_loc + len(LOCATION_FIELDS)
]
nodes[object_index // len(NODE_FIELDS)]["location"] = {
"script_id": script_id,
# Line numbers and column numbers are 0-based internally,
# but 1-based when viewed.
"line": line + 1,
"column": column + 1,
}
curr_loc += len(LOCATION_FIELDS)
with open(args.out, "w") as f:
json.dump(nodes, f, indent=2)
if __name__ == "__main__":
main()