@@ -74,50 +74,36 @@ Future<SnapshotGraph> load(String uri) async {
7474 return reader.done;
7575}
7676
77- String makeJson (root) {
78- // 'root' can be arbitrarily deep, so we need to use an explicit stack
79- // instead of the call stack. We also must avoid using a JSON expression to
80- // avoid stack overflow in the JS engine parser.
81- final ids = new Map <dynamic , int >();
82- final sb = new StringBuffer ();
83- final worklist = new List <dynamic >();
84- worklist.add (root);
85-
86- var id = 0 ;
87- while (id < worklist.length) {
88- var object = worklist[id];
89- ids[object] = id++ ;
90- worklist.addAll (object.children);
77+ String makeData (dynamic root) {
78+ // 'root' can be arbitrarily deep, so we can't directly represent it as a
79+ // JSON tree, which cause a stack overflow here encoding it and in the JS
80+ // engine decoding it. Instead we flatten the tree into a list of tuples with
81+ // a parent pointer and re-inflate it in JS.
82+ final indices = < dynamic , int > {};
83+ final preorder = < dynamic > [];
84+ preorder.add (root);
85+
86+ for (var index = 0 ; index < preorder.length; index++ ) {
87+ final object = preorder[index];
88+ preorder.addAll (object.children);
9189 }
9290
93- while (! worklist.isEmpty) {
94- var object = worklist.removeLast ();
95- var id = ids[object];
96-
97- sb.write ('var node' );
98- sb.write (id.toString ());
99- sb.write (' = {"name":"' );
100- sb.write (object.description);
101- sb.write ('","type":"' );
102- sb.write (object.klass.name);
103- sb.write ('","size":' );
104- sb.write (object.retainedSize.toString ());
105- sb.write (',"children":[' );
106-
107- bool first = true ;
108- for (var child in object.children) {
109- if (! first) {
110- sb.write (',' );
111- }
112- first = false ;
113- sb.write ('node' );
114- sb.write (ids[child].toString ());
115- }
91+ final flattened = < dynamic > [];
92+ for (var index = 0 ; index < preorder.length; index++ ) {
93+ final object = preorder[index];
94+ indices[object] = index;
11695
117- sb.write (']};\n ' );
96+ flattened.add (object.description);
97+ flattened.add (object.klass.name);
98+ flattened.add (object.retainedSize);
99+ if (index == 0 ) {
100+ flattened.add (null );
101+ } else {
102+ flattened.add (indices[object.parent] as int );
103+ }
118104 }
119105
120- return sb. toString ( );
106+ return json. encode (flattened );
121107}
122108
123109var css = '''
@@ -362,28 +348,35 @@ function showDominatorTree(v) {
362348 content.appendChild(topTile);
363349}
364350
365- function linkParents(root ) {
351+ function inflateData(flattened ) {
366352 // 'root' can be arbitrarily deep, so we need to use an explicit stack
367353 // instead of the call stack.
368- let worklist = new Array();
369- worklist.push(root);
370-
371- while (worklist.length > 0) {
372- let node = worklist.pop();
373- node.children.forEach(function (child) {
374- child["parent"] = node;
375- worklist.push(child);
376- });
354+ let nodes = new Array();
355+ let i = 0;
356+ while (i < flattened.length) {
357+ let node = {
358+ "name": flattened[i++],
359+ "type": flattened[i++],
360+ "size": flattened[i++],
361+ "children": [],
362+ "parent": null
363+ };
364+ nodes.push(node);
365+
366+ let parentIndex = flattened[i++];
367+ if (parentIndex != null) {
368+ let parent = nodes[parentIndex];
369+ parent.children.push(node);
370+ node.parent = parent;
371+ }
377372 }
373+
374+ return nodes[0];
378375}
379376
380- var root = null;
381- (function() {
382- __JSON__
383- root = node0;
384- })();
377+ var root = __DATA__;
378+ root = inflateData(root);
385379
386- linkParents(root);
387380showDominatorTree(root);
388381''' ;
389382
@@ -422,7 +415,7 @@ main(List<String> args) async {
422415 final dir = await Directory .systemTemp.createTemp ('heap-snapshot' );
423416 final path = dir.path + '/merged-dominator.html' ;
424417 final file = await File (path).create ();
425- final tree = makeJson (snapshot.mergedRoot);
426- await file.writeAsString (html.replaceAll ('__JSON__ ' , tree));
418+ final tree = makeData (snapshot.mergedRoot);
419+ await file.writeAsString (html.replaceAll ('__DATA__ ' , tree));
427420 print ('Wrote file://' + path);
428421}
0 commit comments