blob: bfd7259433b15a2297af4ee3a01e08acd5fc52f9 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
Tim van der Lippef9f55f12020-01-22 12:24:3930
Tim van der Lippee2a36ca2020-01-24 13:41:2531import * as Common from '../common/common.js';
32import * as HeapSnapshotModel from '../heap_snapshot_model/heap_snapshot_model.js';
33
Tim van der Lippef9f55f12020-01-22 12:24:3934import {AllocationProfile} from './AllocationProfile.js';
35import {HeapSnapshotWorkerDispatcher} from './HeapSnapshotWorkerDispatcher.js'; // eslint-disable-line no-unused-vars
36
Blink Reformat4c46d092018-04-07 15:32:3737/**
38 * @interface
39 */
Tim van der Lippefd903612019-11-07 11:29:0640export class HeapSnapshotItem {
Blink Reformat4c46d092018-04-07 15:32:3741 /**
42 * @return {number}
43 */
Tim van der Lippefd903612019-11-07 11:29:0644 itemIndex() {
45 }
Blink Reformat4c46d092018-04-07 15:32:3746
47 /**
48 * @return {!Object}
49 */
50 serialize() {}
Tim van der Lippefd903612019-11-07 11:29:0651}
Blink Reformat4c46d092018-04-07 15:32:3752
53/**
Tim van der Lippefd903612019-11-07 11:29:0654 * @implements {HeapSnapshotItem}
Blink Reformat4c46d092018-04-07 15:32:3755 * @unrestricted
56 */
Tim van der Lippefd903612019-11-07 11:29:0657export class HeapSnapshotEdge {
Blink Reformat4c46d092018-04-07 15:32:3758 /**
Tim van der Lippefd903612019-11-07 11:29:0659 * @param {!HeapSnapshot} snapshot
Blink Reformat4c46d092018-04-07 15:32:3760 * @param {number=} edgeIndex
61 */
62 constructor(snapshot, edgeIndex) {
63 this._snapshot = snapshot;
64 this._edges = snapshot.containmentEdges;
65 this.edgeIndex = edgeIndex || 0;
66 }
67
68 /**
Tim van der Lippefd903612019-11-07 11:29:0669 * @return {!HeapSnapshotEdge}
Blink Reformat4c46d092018-04-07 15:32:3770 */
71 clone() {
Tim van der Lippefd903612019-11-07 11:29:0672 return new HeapSnapshotEdge(this._snapshot, this.edgeIndex);
Blink Reformat4c46d092018-04-07 15:32:3773 }
74
75 /**
76 * @return {boolean}
77 */
78 hasStringName() {
79 throw new Error('Not implemented');
80 }
81
82 /**
83 * @return {string}
84 */
85 name() {
86 throw new Error('Not implemented');
87 }
88
89 /**
Tim van der Lippefd903612019-11-07 11:29:0690 * @return {!HeapSnapshotNode}
Blink Reformat4c46d092018-04-07 15:32:3791 */
92 node() {
93 return this._snapshot.createNode(this.nodeIndex());
94 }
95
96 /**
97 * @return {number}
98 */
99 nodeIndex() {
100 return this._edges[this.edgeIndex + this._snapshot._edgeToNodeOffset];
101 }
102
103 /**
104 * @override
105 * @return {string}
106 */
107 toString() {
108 return 'HeapSnapshotEdge: ' + this.name();
109 }
110
111 /**
112 * @return {string}
113 */
114 type() {
115 return this._snapshot._edgeTypes[this.rawType()];
116 }
117
118 /**
119 * @override
120 * @return {number}
121 */
122 itemIndex() {
123 return this.edgeIndex;
124 }
125
126 /**
127 * @override
Tim van der Lippee2a36ca2020-01-24 13:41:25128 * @return {!HeapSnapshotModel.HeapSnapshotModel.Edge}
Blink Reformat4c46d092018-04-07 15:32:37129 */
130 serialize() {
Tim van der Lippee2a36ca2020-01-24 13:41:25131 return new HeapSnapshotModel.HeapSnapshotModel.Edge(
132 this.name(), this.node().serialize(), this.type(), this.edgeIndex);
Blink Reformat4c46d092018-04-07 15:32:37133 }
134
135 /**
136 * @protected
137 * @return {number}
138 */
139 rawType() {
140 return this._edges[this.edgeIndex + this._snapshot._edgeTypeOffset];
141 }
Tim van der Lippefd903612019-11-07 11:29:06142}
Blink Reformat4c46d092018-04-07 15:32:37143
144/**
145 * @interface
146 */
Tim van der Lippefd903612019-11-07 11:29:06147export class HeapSnapshotItemIterator {
Blink Reformat4c46d092018-04-07 15:32:37148 /**
149 * @return {boolean}
150 */
Tim van der Lippefd903612019-11-07 11:29:06151 hasNext() {
152 }
Blink Reformat4c46d092018-04-07 15:32:37153
154 /**
Tim van der Lippefd903612019-11-07 11:29:06155 * @return {!HeapSnapshotItem}
Blink Reformat4c46d092018-04-07 15:32:37156 */
Tim van der Lippefd903612019-11-07 11:29:06157 item() {
158 }
Blink Reformat4c46d092018-04-07 15:32:37159
160 next() {}
Tim van der Lippefd903612019-11-07 11:29:06161}
Blink Reformat4c46d092018-04-07 15:32:37162
163/**
164 * @interface
165 */
Tim van der Lippefd903612019-11-07 11:29:06166export class HeapSnapshotItemIndexProvider {
Blink Reformat4c46d092018-04-07 15:32:37167 /**
168 * @param {number} newIndex
Tim van der Lippefd903612019-11-07 11:29:06169 * @return {!HeapSnapshotItem}
Blink Reformat4c46d092018-04-07 15:32:37170 */
Tim van der Lippefd903612019-11-07 11:29:06171 itemForIndex(newIndex) {
172 }
173}
Blink Reformat4c46d092018-04-07 15:32:37174
175/**
Tim van der Lippefd903612019-11-07 11:29:06176 * @implements {HeapSnapshotItemIndexProvider}
Blink Reformat4c46d092018-04-07 15:32:37177 * @unrestricted
178 */
Tim van der Lippefd903612019-11-07 11:29:06179export class HeapSnapshotNodeIndexProvider {
Blink Reformat4c46d092018-04-07 15:32:37180 /**
Tim van der Lippefd903612019-11-07 11:29:06181 * @param {!HeapSnapshot} snapshot
Blink Reformat4c46d092018-04-07 15:32:37182 */
183 constructor(snapshot) {
184 this._node = snapshot.createNode();
185 }
186
187 /**
188 * @override
189 * @param {number} index
Tim van der Lippefd903612019-11-07 11:29:06190 * @return {!HeapSnapshotNode}
Blink Reformat4c46d092018-04-07 15:32:37191 */
192 itemForIndex(index) {
193 this._node.nodeIndex = index;
194 return this._node;
195 }
Tim van der Lippefd903612019-11-07 11:29:06196}
Blink Reformat4c46d092018-04-07 15:32:37197
198/**
Tim van der Lippefd903612019-11-07 11:29:06199 * @implements {HeapSnapshotItemIndexProvider}
Blink Reformat4c46d092018-04-07 15:32:37200 * @unrestricted
201 */
Tim van der Lippefd903612019-11-07 11:29:06202export class HeapSnapshotEdgeIndexProvider {
Blink Reformat4c46d092018-04-07 15:32:37203 /**
Tim van der Lippefd903612019-11-07 11:29:06204 * @param {!HeapSnapshot} snapshot
Blink Reformat4c46d092018-04-07 15:32:37205 */
206 constructor(snapshot) {
207 this._edge = snapshot.createEdge(0);
208 }
209
210 /**
211 * @override
212 * @param {number} index
Tim van der Lippefd903612019-11-07 11:29:06213 * @return {!HeapSnapshotEdge}
Blink Reformat4c46d092018-04-07 15:32:37214 */
215 itemForIndex(index) {
216 this._edge.edgeIndex = index;
217 return this._edge;
218 }
Tim van der Lippefd903612019-11-07 11:29:06219}
Blink Reformat4c46d092018-04-07 15:32:37220
221/**
Tim van der Lippefd903612019-11-07 11:29:06222 * @implements {HeapSnapshotItemIndexProvider}
Blink Reformat4c46d092018-04-07 15:32:37223 * @unrestricted
224 */
Tim van der Lippefd903612019-11-07 11:29:06225export class HeapSnapshotRetainerEdgeIndexProvider {
Blink Reformat4c46d092018-04-07 15:32:37226 /**
Tim van der Lippefd903612019-11-07 11:29:06227 * @param {!HeapSnapshot} snapshot
Blink Reformat4c46d092018-04-07 15:32:37228 */
229 constructor(snapshot) {
230 this._retainerEdge = snapshot.createRetainingEdge(0);
231 }
232
233 /**
234 * @override
235 * @param {number} index
Tim van der Lippefd903612019-11-07 11:29:06236 * @return {!HeapSnapshotRetainerEdge}
Blink Reformat4c46d092018-04-07 15:32:37237 */
238 itemForIndex(index) {
239 this._retainerEdge.setRetainerIndex(index);
240 return this._retainerEdge;
241 }
Tim van der Lippefd903612019-11-07 11:29:06242}
Blink Reformat4c46d092018-04-07 15:32:37243
244/**
Tim van der Lippefd903612019-11-07 11:29:06245 * @implements {HeapSnapshotItemIterator}
Blink Reformat4c46d092018-04-07 15:32:37246 * @unrestricted
247 */
Tim van der Lippefd903612019-11-07 11:29:06248export class HeapSnapshotEdgeIterator {
Blink Reformat4c46d092018-04-07 15:32:37249 /**
Tim van der Lippefd903612019-11-07 11:29:06250 * @param {!HeapSnapshotNode} node
Blink Reformat4c46d092018-04-07 15:32:37251 */
252 constructor(node) {
253 this._sourceNode = node;
254 this.edge = node._snapshot.createEdge(node.edgeIndexesStart());
255 }
256
257 /**
258 * @override
259 * @return {boolean}
260 */
261 hasNext() {
262 return this.edge.edgeIndex < this._sourceNode.edgeIndexesEnd();
263 }
264
265 /**
266 * @override
Tim van der Lippefd903612019-11-07 11:29:06267 * @return {!HeapSnapshotEdge}
Blink Reformat4c46d092018-04-07 15:32:37268 */
269 item() {
270 return this.edge;
271 }
272
273 /**
274 * @override
275 */
276 next() {
277 this.edge.edgeIndex += this.edge._snapshot._edgeFieldsCount;
278 }
Tim van der Lippefd903612019-11-07 11:29:06279}
Blink Reformat4c46d092018-04-07 15:32:37280
281/**
Tim van der Lippefd903612019-11-07 11:29:06282 * @implements {HeapSnapshotItem}
Blink Reformat4c46d092018-04-07 15:32:37283 * @unrestricted
284 */
Tim van der Lippefd903612019-11-07 11:29:06285export class HeapSnapshotRetainerEdge {
Blink Reformat4c46d092018-04-07 15:32:37286 /**
Tim van der Lippefd903612019-11-07 11:29:06287 * @param {!HeapSnapshot} snapshot
Blink Reformat4c46d092018-04-07 15:32:37288 * @param {number} retainerIndex
289 */
290 constructor(snapshot, retainerIndex) {
291 this._snapshot = snapshot;
292 this.setRetainerIndex(retainerIndex);
293 }
294
295 /**
Tim van der Lippefd903612019-11-07 11:29:06296 * @return {!HeapSnapshotRetainerEdge}
Blink Reformat4c46d092018-04-07 15:32:37297 */
298 clone() {
Tim van der Lippefd903612019-11-07 11:29:06299 return new HeapSnapshotRetainerEdge(this._snapshot, this.retainerIndex());
Blink Reformat4c46d092018-04-07 15:32:37300 }
301
302 /**
303 * @return {boolean}
304 */
305 hasStringName() {
306 return this._edge().hasStringName();
307 }
308
309 /**
310 * @return {string}
311 */
312 name() {
313 return this._edge().name();
314 }
315
316 /**
Tim van der Lippefd903612019-11-07 11:29:06317 * @return {!HeapSnapshotNode}
Blink Reformat4c46d092018-04-07 15:32:37318 */
319 node() {
320 return this._node();
321 }
322
323 /**
324 * @return {number}
325 */
326 nodeIndex() {
327 return this._retainingNodeIndex;
328 }
329
330 /**
331 * @return {number}
332 */
333 retainerIndex() {
334 return this._retainerIndex;
335 }
336
337 /**
338 * @param {number} retainerIndex
339 */
340 setRetainerIndex(retainerIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34341 if (retainerIndex === this._retainerIndex) {
Blink Reformat4c46d092018-04-07 15:32:37342 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34343 }
Blink Reformat4c46d092018-04-07 15:32:37344 this._retainerIndex = retainerIndex;
345 this._globalEdgeIndex = this._snapshot._retainingEdges[retainerIndex];
346 this._retainingNodeIndex = this._snapshot._retainingNodes[retainerIndex];
347 this._edgeInstance = null;
348 this._nodeInstance = null;
349 }
350
351 /**
352 * @param {number} edgeIndex
353 */
354 set edgeIndex(edgeIndex) {
355 this.setRetainerIndex(edgeIndex);
356 }
357
358 _node() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34359 if (!this._nodeInstance) {
Blink Reformat4c46d092018-04-07 15:32:37360 this._nodeInstance = this._snapshot.createNode(this._retainingNodeIndex);
Tim van der Lippe1d6e57a2019-09-30 11:55:34361 }
Blink Reformat4c46d092018-04-07 15:32:37362 return this._nodeInstance;
363 }
364
365 _edge() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34366 if (!this._edgeInstance) {
Blink Reformat4c46d092018-04-07 15:32:37367 this._edgeInstance = this._snapshot.createEdge(this._globalEdgeIndex);
Tim van der Lippe1d6e57a2019-09-30 11:55:34368 }
Blink Reformat4c46d092018-04-07 15:32:37369 return this._edgeInstance;
370 }
371
372 /**
373 * @override
374 * @return {string}
375 */
376 toString() {
377 return this._edge().toString();
378 }
379
380 /**
381 * @override
382 * @return {number}
383 */
384 itemIndex() {
385 return this._retainerIndex;
386 }
387
388 /**
389 * @override
Tim van der Lippee2a36ca2020-01-24 13:41:25390 * @return {!HeapSnapshotModel.HeapSnapshotModel.Edge}
Blink Reformat4c46d092018-04-07 15:32:37391 */
392 serialize() {
Tim van der Lippee2a36ca2020-01-24 13:41:25393 return new HeapSnapshotModel.HeapSnapshotModel.Edge(
394 this.name(), this.node().serialize(), this.type(), this._globalEdgeIndex);
Blink Reformat4c46d092018-04-07 15:32:37395 }
396
397 /**
398 * @return {string}
399 */
400 type() {
401 return this._edge().type();
402 }
Tim van der Lippefd903612019-11-07 11:29:06403}
Blink Reformat4c46d092018-04-07 15:32:37404
405/**
Tim van der Lippefd903612019-11-07 11:29:06406 * @implements {HeapSnapshotItemIterator}
Blink Reformat4c46d092018-04-07 15:32:37407 * @unrestricted
408 */
Tim van der Lippefd903612019-11-07 11:29:06409export class HeapSnapshotRetainerEdgeIterator {
Blink Reformat4c46d092018-04-07 15:32:37410 /**
Tim van der Lippefd903612019-11-07 11:29:06411 * @param {!HeapSnapshotNode} retainedNode
Blink Reformat4c46d092018-04-07 15:32:37412 */
413 constructor(retainedNode) {
414 const snapshot = retainedNode._snapshot;
415 const retainedNodeOrdinal = retainedNode.ordinal();
416 const retainerIndex = snapshot._firstRetainerIndex[retainedNodeOrdinal];
417 this._retainersEnd = snapshot._firstRetainerIndex[retainedNodeOrdinal + 1];
418 this.retainer = snapshot.createRetainingEdge(retainerIndex);
419 }
420
421 /**
422 * @override
423 * @return {boolean}
424 */
425 hasNext() {
426 return this.retainer.retainerIndex() < this._retainersEnd;
427 }
428
429 /**
430 * @override
Tim van der Lippefd903612019-11-07 11:29:06431 * @return {!HeapSnapshotRetainerEdge}
Blink Reformat4c46d092018-04-07 15:32:37432 */
433 item() {
434 return this.retainer;
435 }
436
437 /**
438 * @override
439 */
440 next() {
441 this.retainer.setRetainerIndex(this.retainer.retainerIndex() + 1);
442 }
Tim van der Lippefd903612019-11-07 11:29:06443}
Blink Reformat4c46d092018-04-07 15:32:37444
445/**
Tim van der Lippefd903612019-11-07 11:29:06446 * @implements {HeapSnapshotItem}
Blink Reformat4c46d092018-04-07 15:32:37447 * @unrestricted
448 */
Tim van der Lippefd903612019-11-07 11:29:06449export class HeapSnapshotNode {
Blink Reformat4c46d092018-04-07 15:32:37450 /**
Tim van der Lippefd903612019-11-07 11:29:06451 * @param {!HeapSnapshot} snapshot
Blink Reformat4c46d092018-04-07 15:32:37452 * @param {number=} nodeIndex
453 */
454 constructor(snapshot, nodeIndex) {
455 this._snapshot = snapshot;
456 this.nodeIndex = nodeIndex || 0;
457 }
458
459 /**
460 * @return {number}
461 */
462 distance() {
463 return this._snapshot._nodeDistances[this.nodeIndex / this._snapshot._nodeFieldCount];
464 }
465
466 /**
467 * @return {string}
468 */
469 className() {
470 throw new Error('Not implemented');
471 }
472
473 /**
474 * @return {number}
475 */
476 classIndex() {
477 throw new Error('Not implemented');
478 }
479
480 /**
481 * @return {number}
482 */
483 dominatorIndex() {
484 const nodeFieldCount = this._snapshot._nodeFieldCount;
485 return this._snapshot._dominatorsTree[this.nodeIndex / this._snapshot._nodeFieldCount] * nodeFieldCount;
486 }
487
488 /**
Tim van der Lippefd903612019-11-07 11:29:06489 * @return {!HeapSnapshotEdgeIterator}
Blink Reformat4c46d092018-04-07 15:32:37490 */
491 edges() {
Tim van der Lippefd903612019-11-07 11:29:06492 return new HeapSnapshotEdgeIterator(this);
Blink Reformat4c46d092018-04-07 15:32:37493 }
494
495 /**
496 * @return {number}
497 */
498 edgesCount() {
499 return (this.edgeIndexesEnd() - this.edgeIndexesStart()) / this._snapshot._edgeFieldsCount;
500 }
501
502 /**
503 * @return {number}
504 */
505 id() {
506 throw new Error('Not implemented');
507 }
508
509 /**
510 * @return {boolean}
511 */
512 isRoot() {
513 return this.nodeIndex === this._snapshot._rootNodeIndex;
514 }
515
516 /**
517 * @return {string}
518 */
519 name() {
520 return this._snapshot.strings[this._name()];
521 }
522
523 /**
524 * @return {number}
525 */
526 retainedSize() {
527 return this._snapshot._retainedSizes[this.ordinal()];
528 }
529
530 /**
Tim van der Lippefd903612019-11-07 11:29:06531 * @return {!HeapSnapshotRetainerEdgeIterator}
Blink Reformat4c46d092018-04-07 15:32:37532 */
533 retainers() {
Tim van der Lippefd903612019-11-07 11:29:06534 return new HeapSnapshotRetainerEdgeIterator(this);
Blink Reformat4c46d092018-04-07 15:32:37535 }
536
537 /**
538 * @return {number}
539 */
540 retainersCount() {
541 const snapshot = this._snapshot;
542 const ordinal = this.ordinal();
543 return snapshot._firstRetainerIndex[ordinal + 1] - snapshot._firstRetainerIndex[ordinal];
544 }
545
546 /**
547 * @return {number}
548 */
549 selfSize() {
550 const snapshot = this._snapshot;
551 return snapshot.nodes[this.nodeIndex + snapshot._nodeSelfSizeOffset];
552 }
553
554 /**
555 * @return {string}
556 */
557 type() {
558 return this._snapshot._nodeTypes[this.rawType()];
559 }
560
561 /**
562 * @return {number}
563 */
564 traceNodeId() {
565 const snapshot = this._snapshot;
566 return snapshot.nodes[this.nodeIndex + snapshot._nodeTraceNodeIdOffset];
567 }
568
569 /**
570 * @override
571 * @return {number}
572 */
573 itemIndex() {
574 return this.nodeIndex;
575 }
576
577 /**
578 * @override
Tim van der Lippee2a36ca2020-01-24 13:41:25579 * @return {!HeapSnapshotModel.HeapSnapshotModel.Node}
Blink Reformat4c46d092018-04-07 15:32:37580 */
581 serialize() {
Tim van der Lippee2a36ca2020-01-24 13:41:25582 return new HeapSnapshotModel.HeapSnapshotModel.Node(
Blink Reformat4c46d092018-04-07 15:32:37583 this.id(), this.name(), this.distance(), this.nodeIndex, this.retainedSize(), this.selfSize(), this.type());
584 }
585
586 /**
587 * @return {number}
588 */
589 _name() {
590 const snapshot = this._snapshot;
591 return snapshot.nodes[this.nodeIndex + snapshot._nodeNameOffset];
592 }
593
594 /**
595 * @return {number}
596 */
597 edgeIndexesStart() {
598 return this._snapshot._firstEdgeIndexes[this.ordinal()];
599 }
600
601 /**
602 * @return {number}
603 */
604 edgeIndexesEnd() {
605 return this._snapshot._firstEdgeIndexes[this.ordinal() + 1];
606 }
607
608 /**
609 * @return {number}
610 */
611 ordinal() {
612 return this.nodeIndex / this._snapshot._nodeFieldCount;
613 }
614
615 /**
616 * @return {number}
617 */
618 _nextNodeIndex() {
619 return this.nodeIndex + this._snapshot._nodeFieldCount;
620 }
621
622 /**
623 * @protected
624 * @return {number}
625 */
626 rawType() {
627 const snapshot = this._snapshot;
628 return snapshot.nodes[this.nodeIndex + snapshot._nodeTypeOffset];
629 }
Tim van der Lippefd903612019-11-07 11:29:06630}
Blink Reformat4c46d092018-04-07 15:32:37631
632/**
Tim van der Lippefd903612019-11-07 11:29:06633 * @implements {HeapSnapshotItemIterator}
Blink Reformat4c46d092018-04-07 15:32:37634 * @unrestricted
635 */
Tim van der Lippefd903612019-11-07 11:29:06636export class HeapSnapshotNodeIterator {
Blink Reformat4c46d092018-04-07 15:32:37637 /**
Tim van der Lippefd903612019-11-07 11:29:06638 * @param {!HeapSnapshotNode} node
Blink Reformat4c46d092018-04-07 15:32:37639 */
640 constructor(node) {
641 this.node = node;
642 this._nodesLength = node._snapshot.nodes.length;
643 }
644
645 /**
646 * @override
647 * @return {boolean}
648 */
649 hasNext() {
650 return this.node.nodeIndex < this._nodesLength;
651 }
652
653 /**
654 * @override
Tim van der Lippefd903612019-11-07 11:29:06655 * @return {!HeapSnapshotNode}
Blink Reformat4c46d092018-04-07 15:32:37656 */
657 item() {
658 return this.node;
659 }
660
661 /**
662 * @override
663 */
664 next() {
665 this.node.nodeIndex = this.node._nextNodeIndex();
666 }
Tim van der Lippefd903612019-11-07 11:29:06667}
Blink Reformat4c46d092018-04-07 15:32:37668
669/**
Tim van der Lippefd903612019-11-07 11:29:06670 * @implements {HeapSnapshotItemIterator}
Blink Reformat4c46d092018-04-07 15:32:37671 * @unrestricted
672 */
Tim van der Lippefd903612019-11-07 11:29:06673export class HeapSnapshotIndexRangeIterator {
Blink Reformat4c46d092018-04-07 15:32:37674 /**
Tim van der Lippefd903612019-11-07 11:29:06675 * @param {!HeapSnapshotItemIndexProvider} itemProvider
Blink Reformat4c46d092018-04-07 15:32:37676 * @param {!Array.<number>|!Uint32Array} indexes
677 */
678 constructor(itemProvider, indexes) {
679 this._itemProvider = itemProvider;
680 this._indexes = indexes;
681 this._position = 0;
682 }
683
684 /**
685 * @override
686 * @return {boolean}
687 */
688 hasNext() {
689 return this._position < this._indexes.length;
690 }
691
692 /**
693 * @override
Tim van der Lippefd903612019-11-07 11:29:06694 * @return {!HeapSnapshotItem}
Blink Reformat4c46d092018-04-07 15:32:37695 */
696 item() {
697 const index = this._indexes[this._position];
698 return this._itemProvider.itemForIndex(index);
699 }
700
701 /**
702 * @override
703 */
704 next() {
705 ++this._position;
706 }
Tim van der Lippefd903612019-11-07 11:29:06707}
Blink Reformat4c46d092018-04-07 15:32:37708
709/**
Tim van der Lippefd903612019-11-07 11:29:06710 * @implements {HeapSnapshotItemIterator}
Blink Reformat4c46d092018-04-07 15:32:37711 * @unrestricted
712 */
Tim van der Lippefd903612019-11-07 11:29:06713export class HeapSnapshotFilteredIterator {
Blink Reformat4c46d092018-04-07 15:32:37714 /**
Tim van der Lippefd903612019-11-07 11:29:06715 * @param {!HeapSnapshotItemIterator} iterator
716 * @param {function(!HeapSnapshotItem):boolean=} filter
Blink Reformat4c46d092018-04-07 15:32:37717 */
718 constructor(iterator, filter) {
719 this._iterator = iterator;
720 this._filter = filter;
721 this._skipFilteredItems();
722 }
723
724 /**
725 * @override
726 * @return {boolean}
727 */
728 hasNext() {
729 return this._iterator.hasNext();
730 }
731
732 /**
733 * @override
Tim van der Lippefd903612019-11-07 11:29:06734 * @return {!HeapSnapshotItem}
Blink Reformat4c46d092018-04-07 15:32:37735 */
736 item() {
737 return this._iterator.item();
738 }
739
740 /**
741 * @override
742 */
743 next() {
744 this._iterator.next();
745 this._skipFilteredItems();
746 }
747
748 _skipFilteredItems() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34749 while (this._iterator.hasNext() && !this._filter(this._iterator.item())) {
Blink Reformat4c46d092018-04-07 15:32:37750 this._iterator.next();
Tim van der Lippe1d6e57a2019-09-30 11:55:34751 }
Blink Reformat4c46d092018-04-07 15:32:37752 }
Tim van der Lippefd903612019-11-07 11:29:06753}
Blink Reformat4c46d092018-04-07 15:32:37754
755/**
756 * @unrestricted
757 */
Tim van der Lippefd903612019-11-07 11:29:06758export class HeapSnapshotProgress {
Blink Reformat4c46d092018-04-07 15:32:37759 /**
Tim van der Lippef9f55f12020-01-22 12:24:39760 * @param {!HeapSnapshotWorkerDispatcher=} dispatcher
Blink Reformat4c46d092018-04-07 15:32:37761 */
762 constructor(dispatcher) {
763 this._dispatcher = dispatcher;
764 }
765
766 /**
767 * @param {string} status
768 */
769 updateStatus(status) {
Tim van der Lippee2a36ca2020-01-24 13:41:25770 this._sendUpdateEvent(Common.UIString.serializeUIString(status));
Blink Reformat4c46d092018-04-07 15:32:37771 }
772
773 /**
774 * @param {string} title
775 * @param {number} value
776 * @param {number} total
777 */
778 updateProgress(title, value, total) {
779 const percentValue = ((total ? (value / total) : 0) * 100).toFixed(0);
Tim van der Lippee2a36ca2020-01-24 13:41:25780 this._sendUpdateEvent(Common.UIString.serializeUIString(title, [percentValue]));
Blink Reformat4c46d092018-04-07 15:32:37781 }
782
783 /**
784 * @param {string} error
785 */
786 reportProblem(error) {
787 // May be undefined in tests.
Tim van der Lippe1d6e57a2019-09-30 11:55:34788 if (this._dispatcher) {
Tim van der Lippee2a36ca2020-01-24 13:41:25789 this._dispatcher.sendEvent(HeapSnapshotModel.HeapSnapshotModel.HeapSnapshotProgressEvent.BrokenSnapshot, error);
Tim van der Lippe1d6e57a2019-09-30 11:55:34790 }
Blink Reformat4c46d092018-04-07 15:32:37791 }
792
793 /**
Mandy Chen118a23f2019-09-18 17:25:30794 * @param {string} serializedText
Blink Reformat4c46d092018-04-07 15:32:37795 */
Mandy Chen118a23f2019-09-18 17:25:30796 _sendUpdateEvent(serializedText) {
Blink Reformat4c46d092018-04-07 15:32:37797 // May be undefined in tests.
Tim van der Lippe1d6e57a2019-09-30 11:55:34798 if (this._dispatcher) {
Tim van der Lippee2a36ca2020-01-24 13:41:25799 this._dispatcher.sendEvent(HeapSnapshotModel.HeapSnapshotModel.HeapSnapshotProgressEvent.Update, serializedText);
Tim van der Lippe1d6e57a2019-09-30 11:55:34800 }
Blink Reformat4c46d092018-04-07 15:32:37801 }
Tim van der Lippefd903612019-11-07 11:29:06802}
Blink Reformat4c46d092018-04-07 15:32:37803
804/**
805 * @unrestricted
806 */
Tim van der Lippefd903612019-11-07 11:29:06807export class HeapSnapshotProblemReport {
Blink Reformat4c46d092018-04-07 15:32:37808 /**
809 * @param {string} title
810 */
811 constructor(title) {
812 this._errors = [title];
813 }
814
815 /**
816 * @param {string} error
817 */
818 addError(error) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34819 if (this._errors.length > 100) {
Blink Reformat4c46d092018-04-07 15:32:37820 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34821 }
Blink Reformat4c46d092018-04-07 15:32:37822 this._errors.push(error);
823 }
824
825 /**
826 * @override
827 * @return {string}
828 */
829 toString() {
830 return this._errors.join('\n ');
831 }
Tim van der Lippefd903612019-11-07 11:29:06832}
Blink Reformat4c46d092018-04-07 15:32:37833
834/**
835 * @unrestricted
836 */
Tim van der Lippefd903612019-11-07 11:29:06837export class HeapSnapshot {
Blink Reformat4c46d092018-04-07 15:32:37838 /**
839 * @param {!Object} profile
Tim van der Lippefd903612019-11-07 11:29:06840 * @param {!HeapSnapshotProgress} progress
Blink Reformat4c46d092018-04-07 15:32:37841 */
842 constructor(profile, progress) {
843 /** @type {!Uint32Array} */
844 this.nodes = profile.nodes;
845 /** @type {!Uint32Array} */
846 this.containmentEdges = profile.edges;
847 /** @type {!HeapSnapshotMetainfo} */
848 this._metaNode = profile.snapshot.meta;
849 /** @type {!Array.<number>} */
850 this._rawSamples = profile.samples;
Tim van der Lippee2a36ca2020-01-24 13:41:25851 /** @type {?HeapSnapshotModel.HeapSnapshotModel.Samples} */
Blink Reformat4c46d092018-04-07 15:32:37852 this._samples = null;
853 /** @type {!Array.<string>} */
854 this.strings = profile.strings;
Dominik Inführ1a302102018-08-27 16:24:00855 /** @type {!Array.<number>} */
856 this._locations = profile.locations;
Blink Reformat4c46d092018-04-07 15:32:37857 this._progress = progress;
858
859 this._noDistance = -5;
860 this._rootNodeIndex = 0;
Tim van der Lippe1d6e57a2019-09-30 11:55:34861 if (profile.snapshot.root_index) {
Blink Reformat4c46d092018-04-07 15:32:37862 this._rootNodeIndex = profile.snapshot.root_index;
Tim van der Lippe1d6e57a2019-09-30 11:55:34863 }
Blink Reformat4c46d092018-04-07 15:32:37864
865 this._snapshotDiffs = {};
866 this._aggregatesForDiff = null;
867 this._aggregates = {};
868 this._aggregatesSortedFlags = {};
869 this._profile = profile;
870 }
871
872 /**
873 * @protected
874 */
875 initialize() {
876 const meta = this._metaNode;
877
878 this._nodeTypeOffset = meta.node_fields.indexOf('type');
879 this._nodeNameOffset = meta.node_fields.indexOf('name');
880 this._nodeIdOffset = meta.node_fields.indexOf('id');
881 this._nodeSelfSizeOffset = meta.node_fields.indexOf('self_size');
882 this._nodeEdgeCountOffset = meta.node_fields.indexOf('edge_count');
883 this._nodeTraceNodeIdOffset = meta.node_fields.indexOf('trace_node_id');
884 this._nodeFieldCount = meta.node_fields.length;
885
886 this._nodeTypes = meta.node_types[this._nodeTypeOffset];
887 this._nodeArrayType = this._nodeTypes.indexOf('array');
888 this._nodeHiddenType = this._nodeTypes.indexOf('hidden');
889 this._nodeObjectType = this._nodeTypes.indexOf('object');
890 this._nodeNativeType = this._nodeTypes.indexOf('native');
891 this._nodeConsStringType = this._nodeTypes.indexOf('concatenated string');
892 this._nodeSlicedStringType = this._nodeTypes.indexOf('sliced string');
893 this._nodeCodeType = this._nodeTypes.indexOf('code');
894 this._nodeSyntheticType = this._nodeTypes.indexOf('synthetic');
895
896 this._edgeFieldsCount = meta.edge_fields.length;
897 this._edgeTypeOffset = meta.edge_fields.indexOf('type');
898 this._edgeNameOffset = meta.edge_fields.indexOf('name_or_index');
899 this._edgeToNodeOffset = meta.edge_fields.indexOf('to_node');
900
901 this._edgeTypes = meta.edge_types[this._edgeTypeOffset];
902 this._edgeTypes.push('invisible');
903 this._edgeElementType = this._edgeTypes.indexOf('element');
904 this._edgeHiddenType = this._edgeTypes.indexOf('hidden');
905 this._edgeInternalType = this._edgeTypes.indexOf('internal');
906 this._edgeShortcutType = this._edgeTypes.indexOf('shortcut');
907 this._edgeWeakType = this._edgeTypes.indexOf('weak');
908 this._edgeInvisibleType = this._edgeTypes.indexOf('invisible');
909
Dominik Inführ1a302102018-08-27 16:24:00910 const location_fields = meta.location_fields || [];
911
912 this._locationIndexOffset = location_fields.indexOf('object_index');
913 this._locationScriptIdOffset = location_fields.indexOf('script_id');
914 this._locationLineOffset = location_fields.indexOf('line');
915 this._locationColumnOffset = location_fields.indexOf('column');
916 this._locationFieldCount = location_fields.length;
917
Blink Reformat4c46d092018-04-07 15:32:37918 this.nodeCount = this.nodes.length / this._nodeFieldCount;
919 this._edgeCount = this.containmentEdges.length / this._edgeFieldsCount;
920
921 this._retainedSizes = new Float64Array(this.nodeCount);
922 this._firstEdgeIndexes = new Uint32Array(this.nodeCount + 1);
923 this._retainingNodes = new Uint32Array(this._edgeCount);
924 this._retainingEdges = new Uint32Array(this._edgeCount);
925 this._firstRetainerIndex = new Uint32Array(this.nodeCount + 1);
926 this._nodeDistances = new Int32Array(this.nodeCount);
927 this._firstDominatedNodeIndex = new Uint32Array(this.nodeCount + 1);
928 this._dominatedNodes = new Uint32Array(this.nodeCount - 1);
929
Mathias Bynens23ee1aa2020-03-02 12:06:38930 this._progress.updateStatus(ls`Building edge indexes…`);
Blink Reformat4c46d092018-04-07 15:32:37931 this._buildEdgeIndexes();
Mathias Bynens23ee1aa2020-03-02 12:06:38932 this._progress.updateStatus(ls`Building retainers…`);
Blink Reformat4c46d092018-04-07 15:32:37933 this._buildRetainers();
Mathias Bynens23ee1aa2020-03-02 12:06:38934 this._progress.updateStatus(ls`Calculating node flags…`);
Blink Reformat4c46d092018-04-07 15:32:37935 this.calculateFlags();
Mathias Bynens23ee1aa2020-03-02 12:06:38936 this._progress.updateStatus(ls`Calculating distances…`);
Blink Reformat4c46d092018-04-07 15:32:37937 this.calculateDistances();
Mathias Bynens23ee1aa2020-03-02 12:06:38938 this._progress.updateStatus(ls`Building postorder index…`);
Blink Reformat4c46d092018-04-07 15:32:37939 const result = this._buildPostOrderIndex();
940 // Actually it is array that maps node ordinal number to dominator node ordinal number.
Mathias Bynens23ee1aa2020-03-02 12:06:38941 this._progress.updateStatus(ls`Building dominator tree…`);
Blink Reformat4c46d092018-04-07 15:32:37942 this._dominatorsTree =
943 this._buildDominatorTree(result.postOrderIndex2NodeOrdinal, result.nodeOrdinal2PostOrderIndex);
Mathias Bynens23ee1aa2020-03-02 12:06:38944 this._progress.updateStatus(ls`Calculating retained sizes…`);
Blink Reformat4c46d092018-04-07 15:32:37945 this._calculateRetainedSizes(result.postOrderIndex2NodeOrdinal);
Mathias Bynens23ee1aa2020-03-02 12:06:38946 this._progress.updateStatus(ls`Building dominated nodes…`);
Blink Reformat4c46d092018-04-07 15:32:37947 this._buildDominatedNodes();
Mathias Bynens23ee1aa2020-03-02 12:06:38948 this._progress.updateStatus(ls`Calculating statistics…`);
Blink Reformat4c46d092018-04-07 15:32:37949 this.calculateStatistics();
Mathias Bynens23ee1aa2020-03-02 12:06:38950 this._progress.updateStatus(ls`Calculating samples…`);
Blink Reformat4c46d092018-04-07 15:32:37951 this._buildSamples();
Mathias Bynens23ee1aa2020-03-02 12:06:38952 this._progress.updateStatus(ls`Building locations…`);
Dominik Inführ1a302102018-08-27 16:24:00953 this._buildLocationMap();
Mandy Chen74618602019-09-23 18:11:18954 this._progress.updateStatus(ls`Finished processing.`);
Blink Reformat4c46d092018-04-07 15:32:37955
956 if (this._profile.snapshot.trace_function_count) {
Mathias Bynens23ee1aa2020-03-02 12:06:38957 this._progress.updateStatus(ls`Building allocation statistics…`);
Blink Reformat4c46d092018-04-07 15:32:37958 const nodes = this.nodes;
959 const nodesLength = nodes.length;
960 const nodeFieldCount = this._nodeFieldCount;
961 const node = this.rootNode();
962 const liveObjects = {};
963 for (let nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
964 node.nodeIndex = nodeIndex;
965 const traceNodeId = node.traceNodeId();
966 let stats = liveObjects[traceNodeId];
Tim van der Lippe1d6e57a2019-09-30 11:55:34967 if (!stats) {
Blink Reformat4c46d092018-04-07 15:32:37968 liveObjects[traceNodeId] = stats = {count: 0, size: 0, ids: []};
Tim van der Lippe1d6e57a2019-09-30 11:55:34969 }
Blink Reformat4c46d092018-04-07 15:32:37970 stats.count++;
971 stats.size += node.selfSize();
972 stats.ids.push(node.id());
973 }
Tim van der Lippef9f55f12020-01-22 12:24:39974 this._allocationProfile = new AllocationProfile(this._profile, liveObjects);
Mandy Chen74618602019-09-23 18:11:18975 this._progress.updateStatus(ls`Done`);
Blink Reformat4c46d092018-04-07 15:32:37976 }
977 }
978
979 _buildEdgeIndexes() {
980 const nodes = this.nodes;
981 const nodeCount = this.nodeCount;
982 const firstEdgeIndexes = this._firstEdgeIndexes;
983 const nodeFieldCount = this._nodeFieldCount;
984 const edgeFieldsCount = this._edgeFieldsCount;
985 const nodeEdgeCountOffset = this._nodeEdgeCountOffset;
986 firstEdgeIndexes[nodeCount] = this.containmentEdges.length;
987 for (let nodeOrdinal = 0, edgeIndex = 0; nodeOrdinal < nodeCount; ++nodeOrdinal) {
988 firstEdgeIndexes[nodeOrdinal] = edgeIndex;
989 edgeIndex += nodes[nodeOrdinal * nodeFieldCount + nodeEdgeCountOffset] * edgeFieldsCount;
990 }
991 }
992
993 _buildRetainers() {
994 const retainingNodes = this._retainingNodes;
995 const retainingEdges = this._retainingEdges;
996 // Index of the first retainer in the _retainingNodes and _retainingEdges
997 // arrays. Addressed by retained node index.
998 const firstRetainerIndex = this._firstRetainerIndex;
999
1000 const containmentEdges = this.containmentEdges;
1001 const edgeFieldsCount = this._edgeFieldsCount;
1002 const nodeFieldCount = this._nodeFieldCount;
1003 const edgeToNodeOffset = this._edgeToNodeOffset;
1004 const firstEdgeIndexes = this._firstEdgeIndexes;
1005 const nodeCount = this.nodeCount;
1006
1007 for (let toNodeFieldIndex = edgeToNodeOffset, l = containmentEdges.length; toNodeFieldIndex < l;
1008 toNodeFieldIndex += edgeFieldsCount) {
1009 const toNodeIndex = containmentEdges[toNodeFieldIndex];
Tim van der Lippe1d6e57a2019-09-30 11:55:341010 if (toNodeIndex % nodeFieldCount) {
Blink Reformat4c46d092018-04-07 15:32:371011 throw new Error('Invalid toNodeIndex ' + toNodeIndex);
Tim van der Lippe1d6e57a2019-09-30 11:55:341012 }
Blink Reformat4c46d092018-04-07 15:32:371013 ++firstRetainerIndex[toNodeIndex / nodeFieldCount];
1014 }
1015 for (let i = 0, firstUnusedRetainerSlot = 0; i < nodeCount; i++) {
1016 const retainersCount = firstRetainerIndex[i];
1017 firstRetainerIndex[i] = firstUnusedRetainerSlot;
1018 retainingNodes[firstUnusedRetainerSlot] = retainersCount;
1019 firstUnusedRetainerSlot += retainersCount;
1020 }
1021 firstRetainerIndex[nodeCount] = retainingNodes.length;
1022
1023 let nextNodeFirstEdgeIndex = firstEdgeIndexes[0];
1024 for (let srcNodeOrdinal = 0; srcNodeOrdinal < nodeCount; ++srcNodeOrdinal) {
1025 const firstEdgeIndex = nextNodeFirstEdgeIndex;
1026 nextNodeFirstEdgeIndex = firstEdgeIndexes[srcNodeOrdinal + 1];
1027 const srcNodeIndex = srcNodeOrdinal * nodeFieldCount;
1028 for (let edgeIndex = firstEdgeIndex; edgeIndex < nextNodeFirstEdgeIndex; edgeIndex += edgeFieldsCount) {
1029 const toNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:341030 if (toNodeIndex % nodeFieldCount) {
Blink Reformat4c46d092018-04-07 15:32:371031 throw new Error('Invalid toNodeIndex ' + toNodeIndex);
Tim van der Lippe1d6e57a2019-09-30 11:55:341032 }
Blink Reformat4c46d092018-04-07 15:32:371033 const firstRetainerSlotIndex = firstRetainerIndex[toNodeIndex / nodeFieldCount];
1034 const nextUnusedRetainerSlotIndex = firstRetainerSlotIndex + (--retainingNodes[firstRetainerSlotIndex]);
1035 retainingNodes[nextUnusedRetainerSlotIndex] = srcNodeIndex;
1036 retainingEdges[nextUnusedRetainerSlotIndex] = edgeIndex;
1037 }
1038 }
1039 }
1040
1041 /**
1042 * @param {number=} nodeIndex
1043 */
1044 createNode(nodeIndex) {
1045 throw new Error('Not implemented');
1046 }
1047
1048 /**
1049 * @param {number} edgeIndex
Tim van der Lippefd903612019-11-07 11:29:061050 * @return {!JSHeapSnapshotEdge}
Blink Reformat4c46d092018-04-07 15:32:371051 */
1052 createEdge(edgeIndex) {
1053 throw new Error('Not implemented');
1054 }
1055
1056 /**
1057 * @param {number} retainerIndex
Tim van der Lippefd903612019-11-07 11:29:061058 * @return {!JSHeapSnapshotRetainerEdge}
Blink Reformat4c46d092018-04-07 15:32:371059 */
1060 createRetainingEdge(retainerIndex) {
1061 throw new Error('Not implemented');
1062 }
1063
1064 /**
Tim van der Lippefd903612019-11-07 11:29:061065 * @return {!HeapSnapshotNodeIterator}
Blink Reformat4c46d092018-04-07 15:32:371066 */
1067 _allNodes() {
Tim van der Lippefd903612019-11-07 11:29:061068 return new HeapSnapshotNodeIterator(this.rootNode());
Blink Reformat4c46d092018-04-07 15:32:371069 }
1070
1071 /**
Tim van der Lippefd903612019-11-07 11:29:061072 * @return {!HeapSnapshotNode}
Blink Reformat4c46d092018-04-07 15:32:371073 */
1074 rootNode() {
1075 return this.createNode(this._rootNodeIndex);
1076 }
1077
1078 /**
1079 * @return {number}
1080 */
1081 get rootNodeIndex() {
1082 return this._rootNodeIndex;
1083 }
1084
1085 /**
1086 * @return {number}
1087 */
1088 get totalSize() {
1089 return this.rootNode().retainedSize();
1090 }
1091
1092 /**
1093 * @param {number} nodeIndex
1094 * @return {number}
1095 */
1096 _getDominatedIndex(nodeIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341097 if (nodeIndex % this._nodeFieldCount) {
Blink Reformat4c46d092018-04-07 15:32:371098 throw new Error('Invalid nodeIndex: ' + nodeIndex);
Tim van der Lippe1d6e57a2019-09-30 11:55:341099 }
Blink Reformat4c46d092018-04-07 15:32:371100 return this._firstDominatedNodeIndex[nodeIndex / this._nodeFieldCount];
1101 }
1102
1103 /**
Tim van der Lippee2a36ca2020-01-24 13:41:251104 * @param {!HeapSnapshotModel.HeapSnapshotModel.NodeFilter} nodeFilter
Tim van der Lippefd903612019-11-07 11:29:061105 * @return {undefined|function(!HeapSnapshotNode):boolean}
Blink Reformat4c46d092018-04-07 15:32:371106 */
1107 _createFilter(nodeFilter) {
1108 const minNodeId = nodeFilter.minNodeId;
1109 const maxNodeId = nodeFilter.maxNodeId;
1110 const allocationNodeId = nodeFilter.allocationNodeId;
1111 let filter;
1112 if (typeof allocationNodeId === 'number') {
1113 filter = this._createAllocationStackFilter(allocationNodeId);
1114 filter.key = 'AllocationNodeId: ' + allocationNodeId;
1115 } else if (typeof minNodeId === 'number' && typeof maxNodeId === 'number') {
1116 filter = this._createNodeIdFilter(minNodeId, maxNodeId);
1117 filter.key = 'NodeIdRange: ' + minNodeId + '..' + maxNodeId;
1118 }
1119 return filter;
1120 }
1121
1122 /**
Tim van der Lippee2a36ca2020-01-24 13:41:251123 * @param {!HeapSnapshotModel.HeapSnapshotModel.SearchConfig} searchConfig
1124 * @param {!HeapSnapshotModel.HeapSnapshotModel.NodeFilter} nodeFilter
Blink Reformat4c46d092018-04-07 15:32:371125 * @return {!Array.<number>}
1126 */
1127 search(searchConfig, nodeFilter) {
1128 const query = searchConfig.query;
1129
1130 function filterString(matchedStringIndexes, string, index) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341131 if (string.indexOf(query) !== -1) {
Blink Reformat4c46d092018-04-07 15:32:371132 matchedStringIndexes.add(index);
Tim van der Lippe1d6e57a2019-09-30 11:55:341133 }
Blink Reformat4c46d092018-04-07 15:32:371134 return matchedStringIndexes;
1135 }
1136
1137 const regexp = searchConfig.isRegex ? new RegExp(query) : createPlainTextSearchRegex(query, 'i');
1138 function filterRegexp(matchedStringIndexes, string, index) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341139 if (regexp.test(string)) {
Blink Reformat4c46d092018-04-07 15:32:371140 matchedStringIndexes.add(index);
Tim van der Lippe1d6e57a2019-09-30 11:55:341141 }
Blink Reformat4c46d092018-04-07 15:32:371142 return matchedStringIndexes;
1143 }
1144
1145 const stringFilter = (searchConfig.isRegex || !searchConfig.caseSensitive) ? filterRegexp : filterString;
1146 const stringIndexes = this.strings.reduce(stringFilter, new Set());
1147
Tim van der Lippe1d6e57a2019-09-30 11:55:341148 if (!stringIndexes.size) {
Blink Reformat4c46d092018-04-07 15:32:371149 return [];
Tim van der Lippe1d6e57a2019-09-30 11:55:341150 }
Blink Reformat4c46d092018-04-07 15:32:371151
1152 const filter = this._createFilter(nodeFilter);
1153 const nodeIds = [];
1154 const nodesLength = this.nodes.length;
1155 const nodes = this.nodes;
1156 const nodeNameOffset = this._nodeNameOffset;
1157 const nodeIdOffset = this._nodeIdOffset;
1158 const nodeFieldCount = this._nodeFieldCount;
1159 const node = this.rootNode();
1160
1161 for (let nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
1162 node.nodeIndex = nodeIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:341163 if (filter && !filter(node)) {
Blink Reformat4c46d092018-04-07 15:32:371164 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341165 }
1166 if (stringIndexes.has(nodes[nodeIndex + nodeNameOffset])) {
Blink Reformat4c46d092018-04-07 15:32:371167 nodeIds.push(nodes[nodeIndex + nodeIdOffset]);
Tim van der Lippe1d6e57a2019-09-30 11:55:341168 }
Blink Reformat4c46d092018-04-07 15:32:371169 }
1170 return nodeIds;
1171 }
1172
1173 /**
Tim van der Lippee2a36ca2020-01-24 13:41:251174 * @param {!HeapSnapshotModel.HeapSnapshotModel.NodeFilter} nodeFilter
1175 * @return {!Object.<string, !HeapSnapshotModel.HeapSnapshotModel.Aggregate>}
Blink Reformat4c46d092018-04-07 15:32:371176 */
1177 aggregatesWithFilter(nodeFilter) {
1178 const filter = this._createFilter(nodeFilter);
1179 const key = filter ? filter.key : 'allObjects';
1180 return this.aggregates(false, key, filter);
1181 }
1182
1183 /**
1184 * @param {number} minNodeId
1185 * @param {number} maxNodeId
Tim van der Lippefd903612019-11-07 11:29:061186 * @return {function(!HeapSnapshotNode):boolean}
Blink Reformat4c46d092018-04-07 15:32:371187 */
1188 _createNodeIdFilter(minNodeId, maxNodeId) {
1189 /**
Tim van der Lippefd903612019-11-07 11:29:061190 * @param {!HeapSnapshotNode} node
Blink Reformat4c46d092018-04-07 15:32:371191 * @return {boolean}
1192 */
1193 function nodeIdFilter(node) {
1194 const id = node.id();
1195 return id > minNodeId && id <= maxNodeId;
1196 }
1197 return nodeIdFilter;
1198 }
1199
1200 /**
1201 * @param {number} bottomUpAllocationNodeId
Tim van der Lippefd903612019-11-07 11:29:061202 * @return {function(!HeapSnapshotNode):boolean|undefined}
Blink Reformat4c46d092018-04-07 15:32:371203 */
1204 _createAllocationStackFilter(bottomUpAllocationNodeId) {
1205 const traceIds = this._allocationProfile.traceIds(bottomUpAllocationNodeId);
Tim van der Lippe1d6e57a2019-09-30 11:55:341206 if (!traceIds.length) {
Blink Reformat4c46d092018-04-07 15:32:371207 return undefined;
Tim van der Lippe1d6e57a2019-09-30 11:55:341208 }
Blink Reformat4c46d092018-04-07 15:32:371209 const set = {};
Tim van der Lippe1d6e57a2019-09-30 11:55:341210 for (let i = 0; i < traceIds.length; i++) {
Blink Reformat4c46d092018-04-07 15:32:371211 set[traceIds[i]] = true;
Tim van der Lippe1d6e57a2019-09-30 11:55:341212 }
Blink Reformat4c46d092018-04-07 15:32:371213 /**
Tim van der Lippefd903612019-11-07 11:29:061214 * @param {!HeapSnapshotNode} node
Blink Reformat4c46d092018-04-07 15:32:371215 * @return {boolean}
1216 */
1217 function traceIdFilter(node) {
1218 return !!set[node.traceNodeId()];
1219 }
1220 return traceIdFilter;
1221 }
1222
1223 /**
1224 * @param {boolean} sortedIndexes
1225 * @param {string=} key
Tim van der Lippefd903612019-11-07 11:29:061226 * @param {function(!HeapSnapshotNode):boolean=} filter
Tim van der Lippee2a36ca2020-01-24 13:41:251227 * @return {!Object.<string, !HeapSnapshotModel.HeapSnapshotModel.Aggregate>}
Blink Reformat4c46d092018-04-07 15:32:371228 */
1229 aggregates(sortedIndexes, key, filter) {
1230 let aggregatesByClassName = key && this._aggregates[key];
1231 if (!aggregatesByClassName) {
1232 const aggregates = this._buildAggregates(filter);
1233 this._calculateClassesRetainedSize(aggregates.aggregatesByClassIndex, filter);
1234 aggregatesByClassName = aggregates.aggregatesByClassName;
Tim van der Lippe1d6e57a2019-09-30 11:55:341235 if (key) {
Blink Reformat4c46d092018-04-07 15:32:371236 this._aggregates[key] = aggregatesByClassName;
Tim van der Lippe1d6e57a2019-09-30 11:55:341237 }
Blink Reformat4c46d092018-04-07 15:32:371238 }
1239
1240 if (sortedIndexes && (!key || !this._aggregatesSortedFlags[key])) {
1241 this._sortAggregateIndexes(aggregatesByClassName);
Tim van der Lippe1d6e57a2019-09-30 11:55:341242 if (key) {
Blink Reformat4c46d092018-04-07 15:32:371243 this._aggregatesSortedFlags[key] = sortedIndexes;
Tim van der Lippe1d6e57a2019-09-30 11:55:341244 }
Blink Reformat4c46d092018-04-07 15:32:371245 }
1246 return aggregatesByClassName;
1247 }
1248
1249 /**
Tim van der Lippee2a36ca2020-01-24 13:41:251250 * @return {!Array.<!HeapSnapshotModel.HeapSnapshotModel.SerializedAllocationNode>}
Blink Reformat4c46d092018-04-07 15:32:371251 */
1252 allocationTracesTops() {
1253 return this._allocationProfile.serializeTraceTops();
1254 }
1255
1256 /**
1257 * @param {number} nodeId
Tim van der Lippee2a36ca2020-01-24 13:41:251258 * @return {!HeapSnapshotModel.HeapSnapshotModel.AllocationNodeCallers}
Blink Reformat4c46d092018-04-07 15:32:371259 */
1260 allocationNodeCallers(nodeId) {
1261 return this._allocationProfile.serializeCallers(nodeId);
1262 }
1263
1264 /**
1265 * @param {number} nodeIndex
Tim van der Lippee2a36ca2020-01-24 13:41:251266 * @return {?Array.<!HeapSnapshotModel.HeapSnapshotModel.AllocationStackFrame>}
Blink Reformat4c46d092018-04-07 15:32:371267 */
1268 allocationStack(nodeIndex) {
1269 const node = this.createNode(nodeIndex);
1270 const allocationNodeId = node.traceNodeId();
Tim van der Lippe1d6e57a2019-09-30 11:55:341271 if (!allocationNodeId) {
Blink Reformat4c46d092018-04-07 15:32:371272 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:341273 }
Blink Reformat4c46d092018-04-07 15:32:371274 return this._allocationProfile.serializeAllocationStack(allocationNodeId);
1275 }
1276
1277 /**
Tim van der Lippee2a36ca2020-01-24 13:41:251278 * @return {!Object.<string, !HeapSnapshotModel.HeapSnapshotModel.AggregateForDiff>}
Blink Reformat4c46d092018-04-07 15:32:371279 */
1280 aggregatesForDiff() {
Tim van der Lippe1d6e57a2019-09-30 11:55:341281 if (this._aggregatesForDiff) {
Blink Reformat4c46d092018-04-07 15:32:371282 return this._aggregatesForDiff;
Tim van der Lippe1d6e57a2019-09-30 11:55:341283 }
Blink Reformat4c46d092018-04-07 15:32:371284
1285 const aggregatesByClassName = this.aggregates(true, 'allObjects');
1286 this._aggregatesForDiff = {};
1287
1288 const node = this.createNode();
1289 for (const className in aggregatesByClassName) {
1290 const aggregate = aggregatesByClassName[className];
1291 const indexes = aggregate.idxs;
1292 const ids = new Array(indexes.length);
1293 const selfSizes = new Array(indexes.length);
1294 for (let i = 0; i < indexes.length; i++) {
1295 node.nodeIndex = indexes[i];
1296 ids[i] = node.id();
1297 selfSizes[i] = node.selfSize();
1298 }
1299
1300 this._aggregatesForDiff[className] = {indexes: indexes, ids: ids, selfSizes: selfSizes};
1301 }
1302 return this._aggregatesForDiff;
1303 }
1304
1305 /**
1306 * @protected
Tim van der Lippefd903612019-11-07 11:29:061307 * @param {!HeapSnapshotNode} node
Blink Reformat4c46d092018-04-07 15:32:371308 * @return {boolean}
1309 */
1310 isUserRoot(node) {
1311 return true;
1312 }
1313
1314 /**
Tim van der Lippefd903612019-11-07 11:29:061315 * @param {function(!HeapSnapshotNode,!HeapSnapshotEdge):boolean=} filter
Blink Reformat4c46d092018-04-07 15:32:371316 */
1317 calculateDistances(filter) {
1318 const nodeCount = this.nodeCount;
1319 const distances = this._nodeDistances;
1320 const noDistance = this._noDistance;
Tim van der Lippe1d6e57a2019-09-30 11:55:341321 for (let i = 0; i < nodeCount; ++i) {
Blink Reformat4c46d092018-04-07 15:32:371322 distances[i] = noDistance;
Tim van der Lippe1d6e57a2019-09-30 11:55:341323 }
Blink Reformat4c46d092018-04-07 15:32:371324
1325 const nodesToVisit = new Uint32Array(this.nodeCount);
1326 let nodesToVisitLength = 0;
1327
Alexei Filippovde6b75a2018-11-29 23:44:141328 // BFS for user root objects.
1329 for (let iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
1330 const node = iter.edge.node();
1331 if (this.isUserRoot(node)) {
1332 distances[node.ordinal()] = 1;
1333 nodesToVisit[nodesToVisitLength++] = node.nodeIndex;
1334 }
Blink Reformat4c46d092018-04-07 15:32:371335 }
Blink Reformat4c46d092018-04-07 15:32:371336 this._bfs(nodesToVisit, nodesToVisitLength, distances, filter);
1337
Alexei Filippovde6b75a2018-11-29 23:44:141338 // BFS for objects not reached from user roots.
Tim van der Lippee2a36ca2020-01-24 13:41:251339 distances[this.rootNode().ordinal()] =
1340 nodesToVisitLength > 0 ? HeapSnapshotModel.HeapSnapshotModel.baseSystemDistance : 0;
Alexei Filippovde6b75a2018-11-29 23:44:141341 nodesToVisit[0] = this.rootNode().nodeIndex;
1342 nodesToVisitLength = 1;
Blink Reformat4c46d092018-04-07 15:32:371343 this._bfs(nodesToVisit, nodesToVisitLength, distances, filter);
1344 }
1345
1346 /**
1347 * @param {!Uint32Array} nodesToVisit
1348 * @param {number} nodesToVisitLength
1349 * @param {!Int32Array} distances
Tim van der Lippefd903612019-11-07 11:29:061350 * @param {function(!HeapSnapshotNode,!HeapSnapshotEdge):boolean=} filter
Blink Reformat4c46d092018-04-07 15:32:371351 */
1352 _bfs(nodesToVisit, nodesToVisitLength, distances, filter) {
1353 // Preload fields into local variables for better performance.
1354 const edgeFieldsCount = this._edgeFieldsCount;
1355 const nodeFieldCount = this._nodeFieldCount;
1356 const containmentEdges = this.containmentEdges;
1357 const firstEdgeIndexes = this._firstEdgeIndexes;
1358 const edgeToNodeOffset = this._edgeToNodeOffset;
1359 const edgeTypeOffset = this._edgeTypeOffset;
1360 const nodeCount = this.nodeCount;
1361 const edgeWeakType = this._edgeWeakType;
1362 const noDistance = this._noDistance;
1363
1364 let index = 0;
1365 const edge = this.createEdge(0);
1366 const node = this.createNode(0);
1367 while (index < nodesToVisitLength) {
1368 const nodeIndex = nodesToVisit[index++]; // shift generates too much garbage.
1369 const nodeOrdinal = nodeIndex / nodeFieldCount;
1370 const distance = distances[nodeOrdinal] + 1;
1371 const firstEdgeIndex = firstEdgeIndexes[nodeOrdinal];
1372 const edgesEnd = firstEdgeIndexes[nodeOrdinal + 1];
1373 node.nodeIndex = nodeIndex;
1374 for (let edgeIndex = firstEdgeIndex; edgeIndex < edgesEnd; edgeIndex += edgeFieldsCount) {
1375 const edgeType = containmentEdges[edgeIndex + edgeTypeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:341376 if (edgeType === edgeWeakType) {
Blink Reformat4c46d092018-04-07 15:32:371377 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341378 }
Blink Reformat4c46d092018-04-07 15:32:371379 const childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
1380 const childNodeOrdinal = childNodeIndex / nodeFieldCount;
Tim van der Lippe1d6e57a2019-09-30 11:55:341381 if (distances[childNodeOrdinal] !== noDistance) {
Blink Reformat4c46d092018-04-07 15:32:371382 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341383 }
Blink Reformat4c46d092018-04-07 15:32:371384 edge.edgeIndex = edgeIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:341385 if (filter && !filter(node, edge)) {
Blink Reformat4c46d092018-04-07 15:32:371386 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341387 }
Blink Reformat4c46d092018-04-07 15:32:371388 distances[childNodeOrdinal] = distance;
1389 nodesToVisit[nodesToVisitLength++] = childNodeIndex;
1390 }
1391 }
1392 if (nodesToVisitLength > nodeCount) {
1393 throw new Error(
1394 'BFS failed. Nodes to visit (' + nodesToVisitLength + ') is more than nodes count (' + nodeCount + ')');
1395 }
1396 }
1397
1398 /**
Tim van der Lippefd903612019-11-07 11:29:061399 * @param {function(!HeapSnapshotNode):boolean=} filter
Blink Reformat4c46d092018-04-07 15:32:371400 * @return {!{aggregatesByClassName: !Object<string, !HeapSnapshotWorker.HeapSnapshot.AggregatedInfo>,
1401 * aggregatesByClassIndex: !Object<number, !HeapSnapshotWorker.HeapSnapshot.AggregatedInfo>}}
1402 */
1403 _buildAggregates(filter) {
1404 const aggregates = {};
1405 const aggregatesByClassName = {};
1406 const classIndexes = [];
1407 const nodes = this.nodes;
1408 const nodesLength = nodes.length;
1409 const nodeNativeType = this._nodeNativeType;
1410 const nodeFieldCount = this._nodeFieldCount;
1411 const selfSizeOffset = this._nodeSelfSizeOffset;
1412 const nodeTypeOffset = this._nodeTypeOffset;
1413 const node = this.rootNode();
1414 const nodeDistances = this._nodeDistances;
1415
1416 for (let nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
1417 node.nodeIndex = nodeIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:341418 if (filter && !filter(node)) {
Blink Reformat4c46d092018-04-07 15:32:371419 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341420 }
Blink Reformat4c46d092018-04-07 15:32:371421 const selfSize = nodes[nodeIndex + selfSizeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:341422 if (!selfSize && nodes[nodeIndex + nodeTypeOffset] !== nodeNativeType) {
Blink Reformat4c46d092018-04-07 15:32:371423 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341424 }
Blink Reformat4c46d092018-04-07 15:32:371425 const classIndex = node.classIndex();
1426 const nodeOrdinal = nodeIndex / nodeFieldCount;
1427 const distance = nodeDistances[nodeOrdinal];
1428 if (!(classIndex in aggregates)) {
1429 const nodeType = node.type();
1430 const nameMatters = nodeType === 'object' || nodeType === 'native';
1431 const value = {
1432 count: 1,
1433 distance: distance,
1434 self: selfSize,
1435 maxRet: 0,
1436 type: nodeType,
1437 name: nameMatters ? node.name() : null,
1438 idxs: [nodeIndex]
1439 };
1440 aggregates[classIndex] = value;
1441 classIndexes.push(classIndex);
1442 aggregatesByClassName[node.className()] = value;
1443 } else {
1444 const clss = aggregates[classIndex];
1445 clss.distance = Math.min(clss.distance, distance);
1446 ++clss.count;
1447 clss.self += selfSize;
1448 clss.idxs.push(nodeIndex);
1449 }
1450 }
1451
1452 // Shave off provisionally allocated space.
1453 for (let i = 0, l = classIndexes.length; i < l; ++i) {
1454 const classIndex = classIndexes[i];
1455 aggregates[classIndex].idxs = aggregates[classIndex].idxs.slice();
1456 }
1457 return {aggregatesByClassName: aggregatesByClassName, aggregatesByClassIndex: aggregates};
1458 }
1459
1460 /**
1461 * @param {!Object<number, !HeapSnapshotWorker.HeapSnapshot.AggregatedInfo>} aggregates
Tim van der Lippefd903612019-11-07 11:29:061462 * @param {function(!HeapSnapshotNode):boolean=} filter
Blink Reformat4c46d092018-04-07 15:32:371463 */
1464 _calculateClassesRetainedSize(aggregates, filter) {
1465 const rootNodeIndex = this._rootNodeIndex;
1466 const node = this.createNode(rootNodeIndex);
1467 const list = [rootNodeIndex];
1468 const sizes = [-1];
1469 const classes = [];
1470 const seenClassNameIndexes = {};
1471 const nodeFieldCount = this._nodeFieldCount;
1472 const nodeTypeOffset = this._nodeTypeOffset;
1473 const nodeNativeType = this._nodeNativeType;
1474 const dominatedNodes = this._dominatedNodes;
1475 const nodes = this.nodes;
1476 const firstDominatedNodeIndex = this._firstDominatedNodeIndex;
1477
1478 while (list.length) {
1479 const nodeIndex = list.pop();
1480 node.nodeIndex = nodeIndex;
1481 let classIndex = node.classIndex();
1482 const seen = !!seenClassNameIndexes[classIndex];
1483 const nodeOrdinal = nodeIndex / nodeFieldCount;
1484 const dominatedIndexFrom = firstDominatedNodeIndex[nodeOrdinal];
1485 const dominatedIndexTo = firstDominatedNodeIndex[nodeOrdinal + 1];
1486
1487 if (!seen && (!filter || filter(node)) &&
1488 (node.selfSize() || nodes[nodeIndex + nodeTypeOffset] === nodeNativeType)) {
1489 aggregates[classIndex].maxRet += node.retainedSize();
1490 if (dominatedIndexFrom !== dominatedIndexTo) {
1491 seenClassNameIndexes[classIndex] = true;
1492 sizes.push(list.length);
1493 classes.push(classIndex);
1494 }
1495 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341496 for (let i = dominatedIndexFrom; i < dominatedIndexTo; i++) {
Blink Reformat4c46d092018-04-07 15:32:371497 list.push(dominatedNodes[i]);
Tim van der Lippe1d6e57a2019-09-30 11:55:341498 }
Blink Reformat4c46d092018-04-07 15:32:371499
1500 const l = list.length;
1501 while (sizes[sizes.length - 1] === l) {
1502 sizes.pop();
1503 classIndex = classes.pop();
1504 seenClassNameIndexes[classIndex] = false;
1505 }
1506 }
1507 }
1508
1509 /**
1510 * @param {!{aggregatesByClassName: !Object<string, !HeapSnapshotWorker.HeapSnapshot.AggregatedInfo>, aggregatesByClassIndex: !Object<number, !HeapSnapshotWorker.HeapSnapshot.AggregatedInfo>}} aggregates
1511 */
1512 _sortAggregateIndexes(aggregates) {
1513 const nodeA = this.createNode();
1514 const nodeB = this.createNode();
1515 for (const clss in aggregates) {
1516 aggregates[clss].idxs.sort((idxA, idxB) => {
1517 nodeA.nodeIndex = idxA;
1518 nodeB.nodeIndex = idxB;
1519 return nodeA.id() < nodeB.id() ? -1 : 1;
1520 });
1521 }
1522 }
1523
1524 /**
1525 * The function checks is the edge should be considered during building
1526 * postorder iterator and dominator tree.
1527 *
1528 * @param {number} nodeIndex
1529 * @param {number} edgeType
1530 * @return {boolean}
1531 */
1532 _isEssentialEdge(nodeIndex, edgeType) {
1533 // Shortcuts at the root node have special meaning of marking user global objects.
1534 return edgeType !== this._edgeWeakType &&
1535 (edgeType !== this._edgeShortcutType || nodeIndex === this._rootNodeIndex);
1536 }
1537
1538 _buildPostOrderIndex() {
1539 const nodeFieldCount = this._nodeFieldCount;
1540 const nodeCount = this.nodeCount;
1541 const rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
1542
1543 const edgeFieldsCount = this._edgeFieldsCount;
1544 const edgeTypeOffset = this._edgeTypeOffset;
1545 const edgeToNodeOffset = this._edgeToNodeOffset;
1546 const firstEdgeIndexes = this._firstEdgeIndexes;
1547 const containmentEdges = this.containmentEdges;
1548
1549 const mapAndFlag = this.userObjectsMapAndFlag();
1550 const flags = mapAndFlag ? mapAndFlag.map : null;
1551 const flag = mapAndFlag ? mapAndFlag.flag : 0;
1552
1553 const stackNodes = new Uint32Array(nodeCount);
1554 const stackCurrentEdge = new Uint32Array(nodeCount);
1555 const postOrderIndex2NodeOrdinal = new Uint32Array(nodeCount);
1556 const nodeOrdinal2PostOrderIndex = new Uint32Array(nodeCount);
1557 const visited = new Uint8Array(nodeCount);
1558 let postOrderIndex = 0;
1559
1560 let stackTop = 0;
1561 stackNodes[0] = rootNodeOrdinal;
1562 stackCurrentEdge[0] = firstEdgeIndexes[rootNodeOrdinal];
1563 visited[rootNodeOrdinal] = 1;
1564
1565 let iteration = 0;
1566 while (true) {
1567 ++iteration;
1568 while (stackTop >= 0) {
1569 const nodeOrdinal = stackNodes[stackTop];
1570 const edgeIndex = stackCurrentEdge[stackTop];
1571 const edgesEnd = firstEdgeIndexes[nodeOrdinal + 1];
1572
1573 if (edgeIndex < edgesEnd) {
1574 stackCurrentEdge[stackTop] += edgeFieldsCount;
1575 const edgeType = containmentEdges[edgeIndex + edgeTypeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:341576 if (!this._isEssentialEdge(nodeOrdinal * nodeFieldCount, edgeType)) {
Blink Reformat4c46d092018-04-07 15:32:371577 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341578 }
Blink Reformat4c46d092018-04-07 15:32:371579 const childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
1580 const childNodeOrdinal = childNodeIndex / nodeFieldCount;
Tim van der Lippe1d6e57a2019-09-30 11:55:341581 if (visited[childNodeOrdinal]) {
Blink Reformat4c46d092018-04-07 15:32:371582 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341583 }
Blink Reformat4c46d092018-04-07 15:32:371584 const nodeFlag = !flags || (flags[nodeOrdinal] & flag);
1585 const childNodeFlag = !flags || (flags[childNodeOrdinal] & flag);
1586 // We are skipping the edges from non-page-owned nodes to page-owned nodes.
1587 // Otherwise the dominators for the objects that also were retained by debugger would be affected.
Tim van der Lippe1d6e57a2019-09-30 11:55:341588 if (nodeOrdinal !== rootNodeOrdinal && childNodeFlag && !nodeFlag) {
Blink Reformat4c46d092018-04-07 15:32:371589 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341590 }
Blink Reformat4c46d092018-04-07 15:32:371591 ++stackTop;
1592 stackNodes[stackTop] = childNodeOrdinal;
1593 stackCurrentEdge[stackTop] = firstEdgeIndexes[childNodeOrdinal];
1594 visited[childNodeOrdinal] = 1;
1595 } else {
1596 // Done with all the node children
1597 nodeOrdinal2PostOrderIndex[nodeOrdinal] = postOrderIndex;
1598 postOrderIndex2NodeOrdinal[postOrderIndex++] = nodeOrdinal;
1599 --stackTop;
1600 }
1601 }
1602
Tim van der Lippe1d6e57a2019-09-30 11:55:341603 if (postOrderIndex === nodeCount || iteration > 1) {
Blink Reformat4c46d092018-04-07 15:32:371604 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:341605 }
Tim van der Lippefd903612019-11-07 11:29:061606 const errors = new HeapSnapshotProblemReport(`Heap snapshot: ${
1607 nodeCount - postOrderIndex} nodes are unreachable from the root. Following nodes have only weak retainers:`);
Blink Reformat4c46d092018-04-07 15:32:371608 const dumpNode = this.rootNode();
1609 // Remove root from the result (last node in the array) and put it at the bottom of the stack so that it is
1610 // visited after all orphan nodes and their subgraphs.
1611 --postOrderIndex;
1612 stackTop = 0;
1613 stackNodes[0] = rootNodeOrdinal;
1614 stackCurrentEdge[0] = firstEdgeIndexes[rootNodeOrdinal + 1]; // no need to reiterate its edges
1615 for (let i = 0; i < nodeCount; ++i) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341616 if (visited[i] || !this._hasOnlyWeakRetainers(i)) {
Blink Reformat4c46d092018-04-07 15:32:371617 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341618 }
Blink Reformat4c46d092018-04-07 15:32:371619
1620 // Add all nodes that have only weak retainers to traverse their subgraphs.
1621 stackNodes[++stackTop] = i;
1622 stackCurrentEdge[stackTop] = firstEdgeIndexes[i];
1623 visited[i] = 1;
1624
1625 dumpNode.nodeIndex = i * nodeFieldCount;
1626 const retainers = [];
Tim van der Lippe1d6e57a2019-09-30 11:55:341627 for (let it = dumpNode.retainers(); it.hasNext(); it.next()) {
Blink Reformat4c46d092018-04-07 15:32:371628 retainers.push(`${it.item().node().name()}@${it.item().node().id()}.${it.item().name()}`);
Tim van der Lippe1d6e57a2019-09-30 11:55:341629 }
Blink Reformat4c46d092018-04-07 15:32:371630 errors.addError(`${dumpNode.name()} @${dumpNode.id()} weak retainers: ${retainers.join(', ')}`);
1631 }
1632 console.warn(errors.toString());
1633 }
1634
1635 // If we already processed all orphan nodes that have only weak retainers and still have some orphans...
1636 if (postOrderIndex !== nodeCount) {
Tim van der Lippefd903612019-11-07 11:29:061637 const errors = new HeapSnapshotProblemReport(
Blink Reformat4c46d092018-04-07 15:32:371638 'Still found ' + (nodeCount - postOrderIndex) + ' unreachable nodes in heap snapshot:');
1639 const dumpNode = this.rootNode();
1640 // Remove root from the result (last node in the array) and put it at the bottom of the stack so that it is
1641 // visited after all orphan nodes and their subgraphs.
1642 --postOrderIndex;
1643 for (let i = 0; i < nodeCount; ++i) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341644 if (visited[i]) {
Blink Reformat4c46d092018-04-07 15:32:371645 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341646 }
Blink Reformat4c46d092018-04-07 15:32:371647 dumpNode.nodeIndex = i * nodeFieldCount;
1648 errors.addError(dumpNode.name() + ' @' + dumpNode.id());
1649 // Fix it by giving the node a postorder index anyway.
1650 nodeOrdinal2PostOrderIndex[i] = postOrderIndex;
1651 postOrderIndex2NodeOrdinal[postOrderIndex++] = i;
1652 }
1653 nodeOrdinal2PostOrderIndex[rootNodeOrdinal] = postOrderIndex;
1654 postOrderIndex2NodeOrdinal[postOrderIndex++] = rootNodeOrdinal;
1655 console.warn(errors.toString());
1656 }
1657
1658 return {
1659 postOrderIndex2NodeOrdinal: postOrderIndex2NodeOrdinal,
1660 nodeOrdinal2PostOrderIndex: nodeOrdinal2PostOrderIndex
1661 };
1662 }
1663
1664 /**
1665 * @param {number} nodeOrdinal
1666 * @return {boolean}
1667 */
1668 _hasOnlyWeakRetainers(nodeOrdinal) {
1669 const edgeTypeOffset = this._edgeTypeOffset;
1670 const edgeWeakType = this._edgeWeakType;
1671 const edgeShortcutType = this._edgeShortcutType;
1672 const containmentEdges = this.containmentEdges;
1673 const retainingEdges = this._retainingEdges;
1674 const beginRetainerIndex = this._firstRetainerIndex[nodeOrdinal];
1675 const endRetainerIndex = this._firstRetainerIndex[nodeOrdinal + 1];
1676 for (let retainerIndex = beginRetainerIndex; retainerIndex < endRetainerIndex; ++retainerIndex) {
1677 const retainerEdgeIndex = retainingEdges[retainerIndex];
1678 const retainerEdgeType = containmentEdges[retainerEdgeIndex + edgeTypeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:341679 if (retainerEdgeType !== edgeWeakType && retainerEdgeType !== edgeShortcutType) {
Blink Reformat4c46d092018-04-07 15:32:371680 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341681 }
Blink Reformat4c46d092018-04-07 15:32:371682 }
1683 return true;
1684 }
1685
1686 // The algorithm is based on the article:
1687 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm"
1688 // Softw. Pract. Exper. 4 (2001), pp. 1-10.
1689 /**
1690 * @param {!Array.<number>} postOrderIndex2NodeOrdinal
1691 * @param {!Array.<number>} nodeOrdinal2PostOrderIndex
1692 */
1693 _buildDominatorTree(postOrderIndex2NodeOrdinal, nodeOrdinal2PostOrderIndex) {
1694 const nodeFieldCount = this._nodeFieldCount;
1695 const firstRetainerIndex = this._firstRetainerIndex;
1696 const retainingNodes = this._retainingNodes;
1697 const retainingEdges = this._retainingEdges;
1698 const edgeFieldsCount = this._edgeFieldsCount;
1699 const edgeTypeOffset = this._edgeTypeOffset;
1700 const edgeToNodeOffset = this._edgeToNodeOffset;
1701 const firstEdgeIndexes = this._firstEdgeIndexes;
1702 const containmentEdges = this.containmentEdges;
1703 const rootNodeIndex = this._rootNodeIndex;
1704
1705 const mapAndFlag = this.userObjectsMapAndFlag();
1706 const flags = mapAndFlag ? mapAndFlag.map : null;
1707 const flag = mapAndFlag ? mapAndFlag.flag : 0;
1708
1709 const nodesCount = postOrderIndex2NodeOrdinal.length;
1710 const rootPostOrderedIndex = nodesCount - 1;
1711 const noEntry = nodesCount;
1712 const dominators = new Uint32Array(nodesCount);
Tim van der Lippe1d6e57a2019-09-30 11:55:341713 for (let i = 0; i < rootPostOrderedIndex; ++i) {
Blink Reformat4c46d092018-04-07 15:32:371714 dominators[i] = noEntry;
Tim van der Lippe1d6e57a2019-09-30 11:55:341715 }
Blink Reformat4c46d092018-04-07 15:32:371716 dominators[rootPostOrderedIndex] = rootPostOrderedIndex;
1717
1718 // The affected array is used to mark entries which dominators
1719 // have to be racalculated because of changes in their retainers.
1720 const affected = new Uint8Array(nodesCount);
1721 let nodeOrdinal;
1722
1723 { // Mark the root direct children as affected.
1724 nodeOrdinal = this._rootNodeIndex / nodeFieldCount;
1725 const endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
1726 for (let edgeIndex = firstEdgeIndexes[nodeOrdinal]; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
1727 const edgeType = containmentEdges[edgeIndex + edgeTypeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:341728 if (!this._isEssentialEdge(this._rootNodeIndex, edgeType)) {
Blink Reformat4c46d092018-04-07 15:32:371729 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341730 }
Blink Reformat4c46d092018-04-07 15:32:371731 const childNodeOrdinal = containmentEdges[edgeIndex + edgeToNodeOffset] / nodeFieldCount;
1732 affected[nodeOrdinal2PostOrderIndex[childNodeOrdinal]] = 1;
1733 }
1734 }
1735
1736 let changed = true;
1737 while (changed) {
1738 changed = false;
1739 for (let postOrderIndex = rootPostOrderedIndex - 1; postOrderIndex >= 0; --postOrderIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341740 if (affected[postOrderIndex] === 0) {
Blink Reformat4c46d092018-04-07 15:32:371741 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341742 }
Blink Reformat4c46d092018-04-07 15:32:371743 affected[postOrderIndex] = 0;
1744 // If dominator of the entry has already been set to root,
1745 // then it can't propagate any further.
Tim van der Lippe1d6e57a2019-09-30 11:55:341746 if (dominators[postOrderIndex] === rootPostOrderedIndex) {
Blink Reformat4c46d092018-04-07 15:32:371747 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341748 }
Blink Reformat4c46d092018-04-07 15:32:371749 nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
1750 const nodeFlag = !flags || (flags[nodeOrdinal] & flag);
1751 let newDominatorIndex = noEntry;
1752 const beginRetainerIndex = firstRetainerIndex[nodeOrdinal];
1753 const endRetainerIndex = firstRetainerIndex[nodeOrdinal + 1];
1754 let orphanNode = true;
1755 for (let retainerIndex = beginRetainerIndex; retainerIndex < endRetainerIndex; ++retainerIndex) {
1756 const retainerEdgeIndex = retainingEdges[retainerIndex];
1757 const retainerEdgeType = containmentEdges[retainerEdgeIndex + edgeTypeOffset];
1758 const retainerNodeIndex = retainingNodes[retainerIndex];
Tim van der Lippe1d6e57a2019-09-30 11:55:341759 if (!this._isEssentialEdge(retainerNodeIndex, retainerEdgeType)) {
Blink Reformat4c46d092018-04-07 15:32:371760 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341761 }
Blink Reformat4c46d092018-04-07 15:32:371762 orphanNode = false;
1763 const retainerNodeOrdinal = retainerNodeIndex / nodeFieldCount;
1764 const retainerNodeFlag = !flags || (flags[retainerNodeOrdinal] & flag);
1765 // We are skipping the edges from non-page-owned nodes to page-owned nodes.
1766 // Otherwise the dominators for the objects that also were retained by debugger would be affected.
Tim van der Lippe1d6e57a2019-09-30 11:55:341767 if (retainerNodeIndex !== rootNodeIndex && nodeFlag && !retainerNodeFlag) {
Blink Reformat4c46d092018-04-07 15:32:371768 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341769 }
Blink Reformat4c46d092018-04-07 15:32:371770 let retanerPostOrderIndex = nodeOrdinal2PostOrderIndex[retainerNodeOrdinal];
1771 if (dominators[retanerPostOrderIndex] !== noEntry) {
1772 if (newDominatorIndex === noEntry) {
1773 newDominatorIndex = retanerPostOrderIndex;
1774 } else {
1775 while (retanerPostOrderIndex !== newDominatorIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341776 while (retanerPostOrderIndex < newDominatorIndex) {
Blink Reformat4c46d092018-04-07 15:32:371777 retanerPostOrderIndex = dominators[retanerPostOrderIndex];
Tim van der Lippe1d6e57a2019-09-30 11:55:341778 }
1779 while (newDominatorIndex < retanerPostOrderIndex) {
Blink Reformat4c46d092018-04-07 15:32:371780 newDominatorIndex = dominators[newDominatorIndex];
Tim van der Lippe1d6e57a2019-09-30 11:55:341781 }
Blink Reformat4c46d092018-04-07 15:32:371782 }
1783 }
1784 // If idom has already reached the root, it doesn't make sense
1785 // to check other retainers.
Tim van der Lippe1d6e57a2019-09-30 11:55:341786 if (newDominatorIndex === rootPostOrderedIndex) {
Blink Reformat4c46d092018-04-07 15:32:371787 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:341788 }
Blink Reformat4c46d092018-04-07 15:32:371789 }
1790 }
1791 // Make root dominator of orphans.
Tim van der Lippe1d6e57a2019-09-30 11:55:341792 if (orphanNode) {
Blink Reformat4c46d092018-04-07 15:32:371793 newDominatorIndex = rootPostOrderedIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:341794 }
Blink Reformat4c46d092018-04-07 15:32:371795 if (newDominatorIndex !== noEntry && dominators[postOrderIndex] !== newDominatorIndex) {
1796 dominators[postOrderIndex] = newDominatorIndex;
1797 changed = true;
1798 nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
1799 const beginEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal] + edgeToNodeOffset;
1800 const endEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal + 1];
1801 for (let toNodeFieldIndex = beginEdgeToNodeFieldIndex; toNodeFieldIndex < endEdgeToNodeFieldIndex;
1802 toNodeFieldIndex += edgeFieldsCount) {
1803 const childNodeOrdinal = containmentEdges[toNodeFieldIndex] / nodeFieldCount;
1804 affected[nodeOrdinal2PostOrderIndex[childNodeOrdinal]] = 1;
1805 }
1806 }
1807 }
1808 }
1809
1810 const dominatorsTree = new Uint32Array(nodesCount);
1811 for (let postOrderIndex = 0, l = dominators.length; postOrderIndex < l; ++postOrderIndex) {
1812 nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
1813 dominatorsTree[nodeOrdinal] = postOrderIndex2NodeOrdinal[dominators[postOrderIndex]];
1814 }
1815 return dominatorsTree;
1816 }
1817
1818 /**
1819 * @param {!Array<number>} postOrderIndex2NodeOrdinal
1820 */
1821 _calculateRetainedSizes(postOrderIndex2NodeOrdinal) {
1822 const nodeCount = this.nodeCount;
1823 const nodes = this.nodes;
1824 const nodeSelfSizeOffset = this._nodeSelfSizeOffset;
1825 const nodeFieldCount = this._nodeFieldCount;
1826 const dominatorsTree = this._dominatorsTree;
1827 const retainedSizes = this._retainedSizes;
1828
Tim van der Lippe1d6e57a2019-09-30 11:55:341829 for (let nodeOrdinal = 0; nodeOrdinal < nodeCount; ++nodeOrdinal) {
Blink Reformat4c46d092018-04-07 15:32:371830 retainedSizes[nodeOrdinal] = nodes[nodeOrdinal * nodeFieldCount + nodeSelfSizeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:341831 }
Blink Reformat4c46d092018-04-07 15:32:371832
1833 // Propagate retained sizes for each node excluding root.
1834 for (let postOrderIndex = 0; postOrderIndex < nodeCount - 1; ++postOrderIndex) {
1835 const nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
1836 const dominatorOrdinal = dominatorsTree[nodeOrdinal];
1837 retainedSizes[dominatorOrdinal] += retainedSizes[nodeOrdinal];
1838 }
1839 }
1840
1841 _buildDominatedNodes() {
1842 // Builds up two arrays:
1843 // - "dominatedNodes" is a continuous array, where each node owns an
1844 // interval (can be empty) with corresponding dominated nodes.
1845 // - "indexArray" is an array of indexes in the "dominatedNodes"
1846 // with the same positions as in the _nodeIndex.
1847 const indexArray = this._firstDominatedNodeIndex;
1848 // All nodes except the root have dominators.
1849 const dominatedNodes = this._dominatedNodes;
1850
1851 // Count the number of dominated nodes for each node. Skip the root (node at
1852 // index 0) as it is the only node that dominates itself.
1853 const nodeFieldCount = this._nodeFieldCount;
1854 const dominatorsTree = this._dominatorsTree;
1855
1856 let fromNodeOrdinal = 0;
1857 let toNodeOrdinal = this.nodeCount;
1858 const rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
Tim van der Lippe1d6e57a2019-09-30 11:55:341859 if (rootNodeOrdinal === fromNodeOrdinal) {
Blink Reformat4c46d092018-04-07 15:32:371860 fromNodeOrdinal = 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341861 } else if (rootNodeOrdinal === toNodeOrdinal - 1) {
Blink Reformat4c46d092018-04-07 15:32:371862 toNodeOrdinal = toNodeOrdinal - 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341863 } else {
Blink Reformat4c46d092018-04-07 15:32:371864 throw new Error('Root node is expected to be either first or last');
Tim van der Lippe1d6e57a2019-09-30 11:55:341865 }
1866 for (let nodeOrdinal = fromNodeOrdinal; nodeOrdinal < toNodeOrdinal; ++nodeOrdinal) {
Blink Reformat4c46d092018-04-07 15:32:371867 ++indexArray[dominatorsTree[nodeOrdinal]];
Tim van der Lippe1d6e57a2019-09-30 11:55:341868 }
Blink Reformat4c46d092018-04-07 15:32:371869 // Put in the first slot of each dominatedNodes slice the count of entries
1870 // that will be filled.
1871 let firstDominatedNodeIndex = 0;
1872 for (let i = 0, l = this.nodeCount; i < l; ++i) {
1873 const dominatedCount = dominatedNodes[firstDominatedNodeIndex] = indexArray[i];
1874 indexArray[i] = firstDominatedNodeIndex;
1875 firstDominatedNodeIndex += dominatedCount;
1876 }
1877 indexArray[this.nodeCount] = dominatedNodes.length;
1878 // Fill up the dominatedNodes array with indexes of dominated nodes. Skip the root (node at
1879 // index 0) as it is the only node that dominates itself.
1880 for (let nodeOrdinal = fromNodeOrdinal; nodeOrdinal < toNodeOrdinal; ++nodeOrdinal) {
1881 const dominatorOrdinal = dominatorsTree[nodeOrdinal];
1882 let dominatedRefIndex = indexArray[dominatorOrdinal];
1883 dominatedRefIndex += (--dominatedNodes[dominatedRefIndex]);
1884 dominatedNodes[dominatedRefIndex] = nodeOrdinal * nodeFieldCount;
1885 }
1886 }
1887
1888 _buildSamples() {
1889 const samples = this._rawSamples;
Tim van der Lippe1d6e57a2019-09-30 11:55:341890 if (!samples || !samples.length) {
Blink Reformat4c46d092018-04-07 15:32:371891 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341892 }
Blink Reformat4c46d092018-04-07 15:32:371893 const sampleCount = samples.length / 2;
1894 const sizeForRange = new Array(sampleCount);
1895 const timestamps = new Array(sampleCount);
1896 const lastAssignedIds = new Array(sampleCount);
1897
1898 const timestampOffset = this._metaNode.sample_fields.indexOf('timestamp_us');
1899 const lastAssignedIdOffset = this._metaNode.sample_fields.indexOf('last_assigned_id');
1900 for (let i = 0; i < sampleCount; i++) {
1901 sizeForRange[i] = 0;
1902 timestamps[i] = (samples[2 * i + timestampOffset]) / 1000;
1903 lastAssignedIds[i] = samples[2 * i + lastAssignedIdOffset];
1904 }
1905
1906 const nodes = this.nodes;
1907 const nodesLength = nodes.length;
1908 const nodeFieldCount = this._nodeFieldCount;
1909 const node = this.rootNode();
1910 for (let nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
1911 node.nodeIndex = nodeIndex;
1912
1913 const nodeId = node.id();
1914 // JS objects have odd ids, skip native objects.
Tim van der Lippe1d6e57a2019-09-30 11:55:341915 if (nodeId % 2 === 0) {
Blink Reformat4c46d092018-04-07 15:32:371916 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341917 }
Blink Reformat4c46d092018-04-07 15:32:371918 const rangeIndex = lastAssignedIds.lowerBound(nodeId);
1919 if (rangeIndex === sampleCount) {
1920 // TODO: make heap profiler not allocate while taking snapshot
1921 continue;
1922 }
1923 sizeForRange[rangeIndex] += node.selfSize();
1924 }
Tim van der Lippee2a36ca2020-01-24 13:41:251925 this._samples = new HeapSnapshotModel.HeapSnapshotModel.Samples(timestamps, lastAssignedIds, sizeForRange);
Blink Reformat4c46d092018-04-07 15:32:371926 }
1927
Dominik Inführ1a302102018-08-27 16:24:001928 _buildLocationMap() {
Tim van der Lippee2a36ca2020-01-24 13:41:251929 /** @type {!Map<number, !HeapSnapshotModel.HeapSnapshotModel.Location>} */
Dominik Inführ1a302102018-08-27 16:24:001930 const map = new Map();
1931 const locations = this._locations;
1932
1933 for (let i = 0; i < locations.length; i += this._locationFieldCount) {
1934 const nodeIndex = locations[i + this._locationIndexOffset];
1935 const scriptId = locations[i + this._locationScriptIdOffset];
1936 const line = locations[i + this._locationLineOffset];
1937 const col = locations[i + this._locationColumnOffset];
Tim van der Lippee2a36ca2020-01-24 13:41:251938 map.set(nodeIndex, new HeapSnapshotModel.HeapSnapshotModel.Location(scriptId, line, col));
Dominik Inführ1a302102018-08-27 16:24:001939 }
1940
1941 this._locationMap = map;
1942 }
1943
1944 /**
1945 * @param {number} nodeIndex
Tim van der Lippee2a36ca2020-01-24 13:41:251946 * @return {?HeapSnapshotModel.HeapSnapshotModel.Location}
Dominik Inführ1a302102018-08-27 16:24:001947 */
1948 getLocation(nodeIndex) {
1949 return this._locationMap.get(nodeIndex) || null;
1950 }
1951
Blink Reformat4c46d092018-04-07 15:32:371952 /**
Tim van der Lippee2a36ca2020-01-24 13:41:251953 * @return {?HeapSnapshotModel.HeapSnapshotModel.Samples}
Blink Reformat4c46d092018-04-07 15:32:371954 */
1955 getSamples() {
1956 return this._samples;
1957 }
1958
1959 /**
1960 * @protected
1961 */
1962 calculateFlags() {
1963 throw new Error('Not implemented');
1964 }
1965
1966 /**
1967 * @protected
1968 */
1969 calculateStatistics() {
1970 throw new Error('Not implemented');
1971 }
1972
1973 userObjectsMapAndFlag() {
1974 throw new Error('Not implemented');
1975 }
1976
1977 /**
1978 * @param {string} baseSnapshotId
Tim van der Lippee2a36ca2020-01-24 13:41:251979 * @param {!Object.<string, !HeapSnapshotModel.HeapSnapshotModel.AggregateForDiff>} baseSnapshotAggregates
1980 * @return {!Object.<string, !HeapSnapshotModel.HeapSnapshotModel.Diff>}
Blink Reformat4c46d092018-04-07 15:32:371981 */
1982 calculateSnapshotDiff(baseSnapshotId, baseSnapshotAggregates) {
1983 let snapshotDiff = this._snapshotDiffs[baseSnapshotId];
Tim van der Lippe1d6e57a2019-09-30 11:55:341984 if (snapshotDiff) {
Blink Reformat4c46d092018-04-07 15:32:371985 return snapshotDiff;
Tim van der Lippe1d6e57a2019-09-30 11:55:341986 }
Blink Reformat4c46d092018-04-07 15:32:371987 snapshotDiff = {};
1988
1989 const aggregates = this.aggregates(true, 'allObjects');
1990 for (const className in baseSnapshotAggregates) {
1991 const baseAggregate = baseSnapshotAggregates[className];
1992 const diff = this._calculateDiffForClass(baseAggregate, aggregates[className]);
Tim van der Lippe1d6e57a2019-09-30 11:55:341993 if (diff) {
Blink Reformat4c46d092018-04-07 15:32:371994 snapshotDiff[className] = diff;
Tim van der Lippe1d6e57a2019-09-30 11:55:341995 }
Blink Reformat4c46d092018-04-07 15:32:371996 }
Tim van der Lippee2a36ca2020-01-24 13:41:251997 const emptyBaseAggregate = new HeapSnapshotModel.HeapSnapshotModel.AggregateForDiff();
Blink Reformat4c46d092018-04-07 15:32:371998 for (const className in aggregates) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341999 if (className in baseSnapshotAggregates) {
Blink Reformat4c46d092018-04-07 15:32:372000 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342001 }
Blink Reformat4c46d092018-04-07 15:32:372002 snapshotDiff[className] = this._calculateDiffForClass(emptyBaseAggregate, aggregates[className]);
2003 }
2004
2005 this._snapshotDiffs[baseSnapshotId] = snapshotDiff;
2006 return snapshotDiff;
2007 }
2008
2009 /**
Tim van der Lippee2a36ca2020-01-24 13:41:252010 * @param {!HeapSnapshotModel.HeapSnapshotModel.AggregateForDiff} baseAggregate
2011 * @param {!HeapSnapshotModel.HeapSnapshotModel.Aggregate} aggregate
2012 * @return {?HeapSnapshotModel.HeapSnapshotModel.Diff}
Blink Reformat4c46d092018-04-07 15:32:372013 */
2014 _calculateDiffForClass(baseAggregate, aggregate) {
2015 const baseIds = baseAggregate.ids;
2016 const baseIndexes = baseAggregate.indexes;
2017 const baseSelfSizes = baseAggregate.selfSizes;
2018
2019 const indexes = aggregate ? aggregate.idxs : [];
2020
2021 let i = 0;
2022 let j = 0;
2023 const l = baseIds.length;
2024 const m = indexes.length;
Tim van der Lippee2a36ca2020-01-24 13:41:252025 const diff = new HeapSnapshotModel.HeapSnapshotModel.Diff();
Blink Reformat4c46d092018-04-07 15:32:372026
2027 const nodeB = this.createNode(indexes[j]);
2028 while (i < l && j < m) {
2029 const nodeAId = baseIds[i];
2030 if (nodeAId < nodeB.id()) {
2031 diff.deletedIndexes.push(baseIndexes[i]);
2032 diff.removedCount++;
2033 diff.removedSize += baseSelfSizes[i];
2034 ++i;
2035 } else if (
2036 nodeAId >
2037 nodeB.id()) { // Native nodes(e.g. dom groups) may have ids less than max JS object id in the base snapshot
2038 diff.addedIndexes.push(indexes[j]);
2039 diff.addedCount++;
2040 diff.addedSize += nodeB.selfSize();
2041 nodeB.nodeIndex = indexes[++j];
2042 } else { // nodeAId === nodeB.id()
2043 ++i;
2044 nodeB.nodeIndex = indexes[++j];
2045 }
2046 }
2047 while (i < l) {
2048 diff.deletedIndexes.push(baseIndexes[i]);
2049 diff.removedCount++;
2050 diff.removedSize += baseSelfSizes[i];
2051 ++i;
2052 }
2053 while (j < m) {
2054 diff.addedIndexes.push(indexes[j]);
2055 diff.addedCount++;
2056 diff.addedSize += nodeB.selfSize();
2057 nodeB.nodeIndex = indexes[++j];
2058 }
2059 diff.countDelta = diff.addedCount - diff.removedCount;
2060 diff.sizeDelta = diff.addedSize - diff.removedSize;
Tim van der Lippe1d6e57a2019-09-30 11:55:342061 if (!diff.addedCount && !diff.removedCount) {
Blink Reformat4c46d092018-04-07 15:32:372062 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:342063 }
Blink Reformat4c46d092018-04-07 15:32:372064 return diff;
2065 }
2066
2067 _nodeForSnapshotObjectId(snapshotObjectId) {
2068 for (let it = this._allNodes(); it.hasNext(); it.next()) {
Tim van der Lippe1d6e57a2019-09-30 11:55:342069 if (it.node.id() === snapshotObjectId) {
Blink Reformat4c46d092018-04-07 15:32:372070 return it.node;
Tim van der Lippe1d6e57a2019-09-30 11:55:342071 }
Blink Reformat4c46d092018-04-07 15:32:372072 }
2073 return null;
2074 }
2075
2076 /**
2077 * @param {string} snapshotObjectId
2078 * @return {?string}
2079 */
2080 nodeClassName(snapshotObjectId) {
2081 const node = this._nodeForSnapshotObjectId(snapshotObjectId);
Tim van der Lippe1d6e57a2019-09-30 11:55:342082 if (node) {
Blink Reformat4c46d092018-04-07 15:32:372083 return node.className();
Tim van der Lippe1d6e57a2019-09-30 11:55:342084 }
Blink Reformat4c46d092018-04-07 15:32:372085 return null;
2086 }
2087
2088 /**
2089 * @param {string} name
2090 * @return {!Array.<number>}
2091 */
2092 idsOfObjectsWithName(name) {
2093 const ids = [];
2094 for (let it = this._allNodes(); it.hasNext(); it.next()) {
Tim van der Lippe1d6e57a2019-09-30 11:55:342095 if (it.item().name() === name) {
Blink Reformat4c46d092018-04-07 15:32:372096 ids.push(it.item().id());
Tim van der Lippe1d6e57a2019-09-30 11:55:342097 }
Blink Reformat4c46d092018-04-07 15:32:372098 }
2099 return ids;
2100 }
2101
2102 /**
2103 * @param {number} nodeIndex
Tim van der Lippefd903612019-11-07 11:29:062104 * @return {!HeapSnapshotEdgesProvider}
Blink Reformat4c46d092018-04-07 15:32:372105 */
2106 createEdgesProvider(nodeIndex) {
2107 const node = this.createNode(nodeIndex);
2108 const filter = this.containmentEdgesFilter();
Tim van der Lippefd903612019-11-07 11:29:062109 const indexProvider = new HeapSnapshotEdgeIndexProvider(this);
2110 return new HeapSnapshotEdgesProvider(this, filter, node.edges(), indexProvider);
Blink Reformat4c46d092018-04-07 15:32:372111 }
2112
2113 /**
2114 * @param {number} nodeIndex
Tim van der Lippefd903612019-11-07 11:29:062115 * @param {?function(!HeapSnapshotEdge):boolean} filter
2116 * @return {!HeapSnapshotEdgesProvider}
Blink Reformat4c46d092018-04-07 15:32:372117 */
2118 createEdgesProviderForTest(nodeIndex, filter) {
2119 const node = this.createNode(nodeIndex);
Tim van der Lippefd903612019-11-07 11:29:062120 const indexProvider = new HeapSnapshotEdgeIndexProvider(this);
2121 return new HeapSnapshotEdgesProvider(this, filter, node.edges(), indexProvider);
Blink Reformat4c46d092018-04-07 15:32:372122 }
2123
2124 /**
Tim van der Lippefd903612019-11-07 11:29:062125 * @return {?function(!HeapSnapshotEdge):boolean}
Blink Reformat4c46d092018-04-07 15:32:372126 */
2127 retainingEdgesFilter() {
2128 return null;
2129 }
2130
2131 /**
Tim van der Lippefd903612019-11-07 11:29:062132 * @return {?function(!HeapSnapshotEdge):boolean}
Blink Reformat4c46d092018-04-07 15:32:372133 */
2134 containmentEdgesFilter() {
2135 return null;
2136 }
2137
2138 /**
2139 * @param {number} nodeIndex
Tim van der Lippefd903612019-11-07 11:29:062140 * @return {!HeapSnapshotEdgesProvider}
Blink Reformat4c46d092018-04-07 15:32:372141 */
2142 createRetainingEdgesProvider(nodeIndex) {
2143 const node = this.createNode(nodeIndex);
2144 const filter = this.retainingEdgesFilter();
Tim van der Lippefd903612019-11-07 11:29:062145 const indexProvider = new HeapSnapshotRetainerEdgeIndexProvider(this);
2146 return new HeapSnapshotEdgesProvider(this, filter, node.retainers(), indexProvider);
Blink Reformat4c46d092018-04-07 15:32:372147 }
2148
2149 /**
2150 * @param {string} baseSnapshotId
2151 * @param {string} className
Tim van der Lippefd903612019-11-07 11:29:062152 * @return {!HeapSnapshotNodesProvider}
Blink Reformat4c46d092018-04-07 15:32:372153 */
2154 createAddedNodesProvider(baseSnapshotId, className) {
2155 const snapshotDiff = this._snapshotDiffs[baseSnapshotId];
2156 const diffForClass = snapshotDiff[className];
Tim van der Lippefd903612019-11-07 11:29:062157 return new HeapSnapshotNodesProvider(this, diffForClass.addedIndexes);
Blink Reformat4c46d092018-04-07 15:32:372158 }
2159
2160 /**
2161 * @param {!Array.<number>} nodeIndexes
Tim van der Lippefd903612019-11-07 11:29:062162 * @return {!HeapSnapshotNodesProvider}
Blink Reformat4c46d092018-04-07 15:32:372163 */
2164 createDeletedNodesProvider(nodeIndexes) {
Tim van der Lippefd903612019-11-07 11:29:062165 return new HeapSnapshotNodesProvider(this, nodeIndexes);
Blink Reformat4c46d092018-04-07 15:32:372166 }
2167
2168 /**
2169 * @param {string} className
Tim van der Lippee2a36ca2020-01-24 13:41:252170 * @param {!HeapSnapshotModel.HeapSnapshotModel.NodeFilter} nodeFilter
Tim van der Lippefd903612019-11-07 11:29:062171 * @return {!HeapSnapshotNodesProvider}
Blink Reformat4c46d092018-04-07 15:32:372172 */
2173 createNodesProviderForClass(className, nodeFilter) {
Tim van der Lippefd903612019-11-07 11:29:062174 return new HeapSnapshotNodesProvider(this, this.aggregatesWithFilter(nodeFilter)[className].idxs);
Blink Reformat4c46d092018-04-07 15:32:372175 }
2176
2177 /**
2178 * @return {number}
2179 */
2180 _maxJsNodeId() {
2181 const nodeFieldCount = this._nodeFieldCount;
2182 const nodes = this.nodes;
2183 const nodesLength = nodes.length;
2184 let id = 0;
2185 for (let nodeIndex = this._nodeIdOffset; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
2186 const nextId = nodes[nodeIndex];
2187 // JS objects have odd ids, skip native objects.
Tim van der Lippe1d6e57a2019-09-30 11:55:342188 if (nextId % 2 === 0) {
Blink Reformat4c46d092018-04-07 15:32:372189 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342190 }
2191 if (id < nextId) {
Blink Reformat4c46d092018-04-07 15:32:372192 id = nextId;
Tim van der Lippe1d6e57a2019-09-30 11:55:342193 }
Blink Reformat4c46d092018-04-07 15:32:372194 }
2195 return id;
2196 }
2197
2198 /**
Tim van der Lippee2a36ca2020-01-24 13:41:252199 * @return {!HeapSnapshotModel.HeapSnapshotModel.StaticData}
Blink Reformat4c46d092018-04-07 15:32:372200 */
2201 updateStaticData() {
Tim van der Lippee2a36ca2020-01-24 13:41:252202 return new HeapSnapshotModel.HeapSnapshotModel.StaticData(
2203 this.nodeCount, this._rootNodeIndex, this.totalSize, this._maxJsNodeId());
Blink Reformat4c46d092018-04-07 15:32:372204 }
Tim van der Lippefd903612019-11-07 11:29:062205}
Blink Reformat4c46d092018-04-07 15:32:372206
2207/**
2208 * @unrestricted
2209 */
2210const HeapSnapshotMetainfo = class {
2211 constructor() {
2212 // New format.
2213 this.node_fields = [];
2214 this.node_types = [];
2215 this.edge_fields = [];
2216 this.edge_types = [];
2217 this.trace_function_info_fields = [];
2218 this.trace_node_fields = [];
2219 this.sample_fields = [];
2220 this.type_strings = {};
2221 }
2222};
2223
2224/**
2225 * @unrestricted
2226 */
Tim van der Lippefd903612019-11-07 11:29:062227export class HeapSnapshotHeader {
Blink Reformat4c46d092018-04-07 15:32:372228 constructor() {
2229 // New format.
2230 this.title = '';
2231 this.meta = new HeapSnapshotMetainfo();
2232 this.node_count = 0;
2233 this.edge_count = 0;
2234 this.trace_function_count = 0;
2235 }
Tim van der Lippefd903612019-11-07 11:29:062236}
Blink Reformat4c46d092018-04-07 15:32:372237
2238/**
2239 * @unrestricted
2240 */
Tim van der Lippefd903612019-11-07 11:29:062241export class HeapSnapshotItemProvider {
Blink Reformat4c46d092018-04-07 15:32:372242 /**
Tim van der Lippefd903612019-11-07 11:29:062243 * @param {!HeapSnapshotItemIterator} iterator
2244 * @param {!HeapSnapshotItemIndexProvider} indexProvider
Blink Reformat4c46d092018-04-07 15:32:372245 */
2246 constructor(iterator, indexProvider) {
2247 this._iterator = iterator;
2248 this._indexProvider = indexProvider;
2249 this._isEmpty = !iterator.hasNext();
2250 /** @type {?Array.<number>} */
2251 this._iterationOrder = null;
2252 this._currentComparator = null;
2253 this._sortedPrefixLength = 0;
2254 this._sortedSuffixLength = 0;
2255 }
2256
2257 _createIterationOrder() {
Tim van der Lippe1d6e57a2019-09-30 11:55:342258 if (this._iterationOrder) {
Blink Reformat4c46d092018-04-07 15:32:372259 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:342260 }
Blink Reformat4c46d092018-04-07 15:32:372261 this._iterationOrder = [];
Tim van der Lippe1d6e57a2019-09-30 11:55:342262 for (let iterator = this._iterator; iterator.hasNext(); iterator.next()) {
Blink Reformat4c46d092018-04-07 15:32:372263 this._iterationOrder.push(iterator.item().itemIndex());
Tim van der Lippe1d6e57a2019-09-30 11:55:342264 }
Blink Reformat4c46d092018-04-07 15:32:372265 }
2266
2267 /**
2268 * @return {boolean}
2269 */
2270 isEmpty() {
2271 return this._isEmpty;
2272 }
2273
2274 /**
2275 * @param {number} begin
2276 * @param {number} end
Tim van der Lippee2a36ca2020-01-24 13:41:252277 * @return {!HeapSnapshotModel.HeapSnapshotModel.ItemsRange}
Blink Reformat4c46d092018-04-07 15:32:372278 */
2279 serializeItemsRange(begin, end) {
2280 this._createIterationOrder();
Tim van der Lippe1d6e57a2019-09-30 11:55:342281 if (begin > end) {
Blink Reformat4c46d092018-04-07 15:32:372282 throw new Error('Start position > end position: ' + begin + ' > ' + end);
Tim van der Lippe1d6e57a2019-09-30 11:55:342283 }
2284 if (end > this._iterationOrder.length) {
Blink Reformat4c46d092018-04-07 15:32:372285 end = this._iterationOrder.length;
Tim van der Lippe1d6e57a2019-09-30 11:55:342286 }
Blink Reformat4c46d092018-04-07 15:32:372287 if (this._sortedPrefixLength < end && begin < this._iterationOrder.length - this._sortedSuffixLength) {
2288 this.sort(
2289 this._currentComparator, this._sortedPrefixLength, this._iterationOrder.length - 1 - this._sortedSuffixLength,
2290 begin, end - 1);
Tim van der Lippe1d6e57a2019-09-30 11:55:342291 if (begin <= this._sortedPrefixLength) {
Blink Reformat4c46d092018-04-07 15:32:372292 this._sortedPrefixLength = end;
Tim van der Lippe1d6e57a2019-09-30 11:55:342293 }
2294 if (end >= this._iterationOrder.length - this._sortedSuffixLength) {
Blink Reformat4c46d092018-04-07 15:32:372295 this._sortedSuffixLength = this._iterationOrder.length - begin;
Tim van der Lippe1d6e57a2019-09-30 11:55:342296 }
Blink Reformat4c46d092018-04-07 15:32:372297 }
2298 let position = begin;
2299 const count = end - begin;
2300 const result = new Array(count);
2301 for (let i = 0; i < count; ++i) {
2302 const itemIndex = this._iterationOrder[position++];
2303 const item = this._indexProvider.itemForIndex(itemIndex);
2304 result[i] = item.serialize();
2305 }
Tim van der Lippee2a36ca2020-01-24 13:41:252306 return new HeapSnapshotModel.HeapSnapshotModel.ItemsRange(begin, end, this._iterationOrder.length, result);
Blink Reformat4c46d092018-04-07 15:32:372307 }
2308
2309 sortAndRewind(comparator) {
2310 this._currentComparator = comparator;
2311 this._sortedPrefixLength = 0;
2312 this._sortedSuffixLength = 0;
2313 }
Tim van der Lippefd903612019-11-07 11:29:062314}
Blink Reformat4c46d092018-04-07 15:32:372315
2316/**
2317 * @unrestricted
2318 */
Tim van der Lippefd903612019-11-07 11:29:062319export class HeapSnapshotEdgesProvider extends HeapSnapshotItemProvider {
Blink Reformat4c46d092018-04-07 15:32:372320 /**
Tim van der Lippefd903612019-11-07 11:29:062321 * @param {!HeapSnapshot} snapshot
2322 * @param {?function(!HeapSnapshotEdge):boolean} filter
2323 * @param {!HeapSnapshotEdgeIterator} edgesIter
2324 * @param {!HeapSnapshotItemIndexProvider} indexProvider
Blink Reformat4c46d092018-04-07 15:32:372325 */
2326 constructor(snapshot, filter, edgesIter, indexProvider) {
2327 const iter = filter ?
Tim van der Lippefd903612019-11-07 11:29:062328 new HeapSnapshotFilteredIterator(edgesIter, /** @type {function(!HeapSnapshotItem):boolean} */ (filter)) :
Blink Reformat4c46d092018-04-07 15:32:372329 edgesIter;
2330 super(iter, indexProvider);
2331 this.snapshot = snapshot;
2332 }
2333
2334 /**
Tim van der Lippee2a36ca2020-01-24 13:41:252335 * @param {!HeapSnapshotModel.HeapSnapshotModel.ComparatorConfig} comparator
Blink Reformat4c46d092018-04-07 15:32:372336 * @param {number} leftBound
2337 * @param {number} rightBound
2338 * @param {number} windowLeft
2339 * @param {number} windowRight
2340 */
2341 sort(comparator, leftBound, rightBound, windowLeft, windowRight) {
2342 const fieldName1 = comparator.fieldName1;
2343 const fieldName2 = comparator.fieldName2;
2344 const ascending1 = comparator.ascending1;
2345 const ascending2 = comparator.ascending2;
2346
Tim van der Lippefd903612019-11-07 11:29:062347 const edgeA = /** @type {!HeapSnapshotEdge} */ (this._iterator.item()).clone();
Blink Reformat4c46d092018-04-07 15:32:372348 const edgeB = edgeA.clone();
2349 const nodeA = this.snapshot.createNode();
2350 const nodeB = this.snapshot.createNode();
2351
2352 function compareEdgeFieldName(ascending, indexA, indexB) {
2353 edgeA.edgeIndex = indexA;
2354 edgeB.edgeIndex = indexB;
Tim van der Lippe1d6e57a2019-09-30 11:55:342355 if (edgeB.name() === '__proto__') {
Blink Reformat4c46d092018-04-07 15:32:372356 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:342357 }
2358 if (edgeA.name() === '__proto__') {
Blink Reformat4c46d092018-04-07 15:32:372359 return 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:342360 }
Blink Reformat4c46d092018-04-07 15:32:372361 const result = edgeA.hasStringName() === edgeB.hasStringName() ?
2362 (edgeA.name() < edgeB.name() ? -1 : (edgeA.name() > edgeB.name() ? 1 : 0)) :
2363 (edgeA.hasStringName() ? -1 : 1);
2364 return ascending ? result : -result;
2365 }
2366
2367 function compareNodeField(fieldName, ascending, indexA, indexB) {
2368 edgeA.edgeIndex = indexA;
2369 nodeA.nodeIndex = edgeA.nodeIndex();
2370 const valueA = nodeA[fieldName]();
2371
2372 edgeB.edgeIndex = indexB;
2373 nodeB.nodeIndex = edgeB.nodeIndex();
2374 const valueB = nodeB[fieldName]();
2375
2376 const result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0);
2377 return ascending ? result : -result;
2378 }
2379
2380 function compareEdgeAndNode(indexA, indexB) {
2381 let result = compareEdgeFieldName(ascending1, indexA, indexB);
Tim van der Lippe1d6e57a2019-09-30 11:55:342382 if (result === 0) {
Blink Reformat4c46d092018-04-07 15:32:372383 result = compareNodeField(fieldName2, ascending2, indexA, indexB);
Tim van der Lippe1d6e57a2019-09-30 11:55:342384 }
2385 if (result === 0) {
Blink Reformat4c46d092018-04-07 15:32:372386 return indexA - indexB;
Tim van der Lippe1d6e57a2019-09-30 11:55:342387 }
Blink Reformat4c46d092018-04-07 15:32:372388 return result;
2389 }
2390
2391 function compareNodeAndEdge(indexA, indexB) {
2392 let result = compareNodeField(fieldName1, ascending1, indexA, indexB);
Tim van der Lippe1d6e57a2019-09-30 11:55:342393 if (result === 0) {
Blink Reformat4c46d092018-04-07 15:32:372394 result = compareEdgeFieldName(ascending2, indexA, indexB);
Tim van der Lippe1d6e57a2019-09-30 11:55:342395 }
2396 if (result === 0) {
Blink Reformat4c46d092018-04-07 15:32:372397 return indexA - indexB;
Tim van der Lippe1d6e57a2019-09-30 11:55:342398 }
Blink Reformat4c46d092018-04-07 15:32:372399 return result;
2400 }
2401
2402 function compareNodeAndNode(indexA, indexB) {
2403 let result = compareNodeField(fieldName1, ascending1, indexA, indexB);
Tim van der Lippe1d6e57a2019-09-30 11:55:342404 if (result === 0) {
Blink Reformat4c46d092018-04-07 15:32:372405 result = compareNodeField(fieldName2, ascending2, indexA, indexB);
Tim van der Lippe1d6e57a2019-09-30 11:55:342406 }
2407 if (result === 0) {
Blink Reformat4c46d092018-04-07 15:32:372408 return indexA - indexB;
Tim van der Lippe1d6e57a2019-09-30 11:55:342409 }
Blink Reformat4c46d092018-04-07 15:32:372410 return result;
2411 }
2412
Tim van der Lippe1d6e57a2019-09-30 11:55:342413 if (fieldName1 === '!edgeName') {
Blink Reformat4c46d092018-04-07 15:32:372414 this._iterationOrder.sortRange(compareEdgeAndNode, leftBound, rightBound, windowLeft, windowRight);
Tim van der Lippe1d6e57a2019-09-30 11:55:342415 } else if (fieldName2 === '!edgeName') {
Blink Reformat4c46d092018-04-07 15:32:372416 this._iterationOrder.sortRange(compareNodeAndEdge, leftBound, rightBound, windowLeft, windowRight);
Tim van der Lippe1d6e57a2019-09-30 11:55:342417 } else {
Blink Reformat4c46d092018-04-07 15:32:372418 this._iterationOrder.sortRange(compareNodeAndNode, leftBound, rightBound, windowLeft, windowRight);
Tim van der Lippe1d6e57a2019-09-30 11:55:342419 }
Blink Reformat4c46d092018-04-07 15:32:372420 }
Tim van der Lippefd903612019-11-07 11:29:062421}
Blink Reformat4c46d092018-04-07 15:32:372422
2423/**
2424 * @unrestricted
2425 */
Tim van der Lippefd903612019-11-07 11:29:062426export class HeapSnapshotNodesProvider extends HeapSnapshotItemProvider {
Blink Reformat4c46d092018-04-07 15:32:372427 /**
Tim van der Lippefd903612019-11-07 11:29:062428 * @param {!HeapSnapshot} snapshot
Blink Reformat4c46d092018-04-07 15:32:372429 * @param {!Array<number>|!Uint32Array} nodeIndexes
2430 */
2431 constructor(snapshot, nodeIndexes) {
Tim van der Lippefd903612019-11-07 11:29:062432 const indexProvider = new HeapSnapshotNodeIndexProvider(snapshot);
2433 const it = new HeapSnapshotIndexRangeIterator(indexProvider, nodeIndexes);
Blink Reformat4c46d092018-04-07 15:32:372434 super(it, indexProvider);
2435 this.snapshot = snapshot;
2436 }
2437
2438 /**
2439 * @param {string} snapshotObjectId
2440 * @return {number}
2441 */
2442 nodePosition(snapshotObjectId) {
2443 this._createIterationOrder();
2444 const node = this.snapshot.createNode();
2445 let i = 0;
2446 for (; i < this._iterationOrder.length; i++) {
2447 node.nodeIndex = this._iterationOrder[i];
Tim van der Lippe1d6e57a2019-09-30 11:55:342448 if (node.id() === snapshotObjectId) {
Blink Reformat4c46d092018-04-07 15:32:372449 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:342450 }
Blink Reformat4c46d092018-04-07 15:32:372451 }
Tim van der Lippe1d6e57a2019-09-30 11:55:342452 if (i === this._iterationOrder.length) {
Blink Reformat4c46d092018-04-07 15:32:372453 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:342454 }
Blink Reformat4c46d092018-04-07 15:32:372455 const targetNodeIndex = this._iterationOrder[i];
2456 let smallerCount = 0;
2457 const compare = this._buildCompareFunction(this._currentComparator);
2458 for (let i = 0; i < this._iterationOrder.length; i++) {
Tim van der Lippe1d6e57a2019-09-30 11:55:342459 if (compare(this._iterationOrder[i], targetNodeIndex) < 0) {
Blink Reformat4c46d092018-04-07 15:32:372460 ++smallerCount;
Tim van der Lippe1d6e57a2019-09-30 11:55:342461 }
Blink Reformat4c46d092018-04-07 15:32:372462 }
2463 return smallerCount;
2464 }
2465
2466 /**
2467 * @return {function(number,number):number}
2468 */
2469 _buildCompareFunction(comparator) {
2470 const nodeA = this.snapshot.createNode();
2471 const nodeB = this.snapshot.createNode();
2472 const fieldAccessor1 = nodeA[comparator.fieldName1];
2473 const fieldAccessor2 = nodeA[comparator.fieldName2];
2474 const ascending1 = comparator.ascending1 ? 1 : -1;
2475 const ascending2 = comparator.ascending2 ? 1 : -1;
2476
2477 /**
2478 * @param {function():*} fieldAccessor
2479 * @param {number} ascending
2480 * @return {number}
2481 */
2482 function sortByNodeField(fieldAccessor, ascending) {
2483 const valueA = fieldAccessor.call(nodeA);
2484 const valueB = fieldAccessor.call(nodeB);
2485 return valueA < valueB ? -ascending : (valueA > valueB ? ascending : 0);
2486 }
2487
2488 /**
2489 * @param {number} indexA
2490 * @param {number} indexB
2491 * @return {number}
2492 */
2493 function sortByComparator(indexA, indexB) {
2494 nodeA.nodeIndex = indexA;
2495 nodeB.nodeIndex = indexB;
2496 let result = sortByNodeField(fieldAccessor1, ascending1);
Tim van der Lippe1d6e57a2019-09-30 11:55:342497 if (result === 0) {
Blink Reformat4c46d092018-04-07 15:32:372498 result = sortByNodeField(fieldAccessor2, ascending2);
Tim van der Lippe1d6e57a2019-09-30 11:55:342499 }
Blink Reformat4c46d092018-04-07 15:32:372500 return result || indexA - indexB;
2501 }
2502
2503 return sortByComparator;
2504 }
2505
2506 /**
Tim van der Lippee2a36ca2020-01-24 13:41:252507 * @param {!HeapSnapshotModel.HeapSnapshotModel.ComparatorConfig} comparator
Blink Reformat4c46d092018-04-07 15:32:372508 * @param {number} leftBound
2509 * @param {number} rightBound
2510 * @param {number} windowLeft
2511 * @param {number} windowRight
2512 */
2513 sort(comparator, leftBound, rightBound, windowLeft, windowRight) {
2514 this._iterationOrder.sortRange(
2515 this._buildCompareFunction(comparator), leftBound, rightBound, windowLeft, windowRight);
2516 }
Tim van der Lippefd903612019-11-07 11:29:062517}
Blink Reformat4c46d092018-04-07 15:32:372518
2519/**
2520 * @unrestricted
2521 */
Tim van der Lippefd903612019-11-07 11:29:062522export class JSHeapSnapshot extends HeapSnapshot {
Blink Reformat4c46d092018-04-07 15:32:372523 /**
2524 * @param {!Object} profile
Tim van der Lippefd903612019-11-07 11:29:062525 * @param {!HeapSnapshotProgress} progress
Blink Reformat4c46d092018-04-07 15:32:372526 */
2527 constructor(profile, progress) {
2528 super(profile, progress);
2529 this._nodeFlags = {
2530 // bit flags
2531 canBeQueried: 1,
2532 detachedDOMTreeNode: 2,
2533 pageObject: 4 // The idea is to track separately the objects owned by the page and the objects owned by debugger.
2534 };
2535 this._lazyStringCache = {};
2536 this.initialize();
2537 }
2538
2539 /**
2540 * @override
2541 * @param {number=} nodeIndex
Tim van der Lippefd903612019-11-07 11:29:062542 * @return {!JSHeapSnapshotNode}
Blink Reformat4c46d092018-04-07 15:32:372543 */
2544 createNode(nodeIndex) {
Tim van der Lippefd903612019-11-07 11:29:062545 return new JSHeapSnapshotNode(this, nodeIndex === undefined ? -1 : nodeIndex);
Blink Reformat4c46d092018-04-07 15:32:372546 }
2547
2548 /**
2549 * @override
2550 * @param {number} edgeIndex
Tim van der Lippefd903612019-11-07 11:29:062551 * @return {!JSHeapSnapshotEdge}
Blink Reformat4c46d092018-04-07 15:32:372552 */
2553 createEdge(edgeIndex) {
Tim van der Lippefd903612019-11-07 11:29:062554 return new JSHeapSnapshotEdge(this, edgeIndex);
Blink Reformat4c46d092018-04-07 15:32:372555 }
2556
2557 /**
2558 * @override
2559 * @param {number} retainerIndex
Tim van der Lippefd903612019-11-07 11:29:062560 * @return {!JSHeapSnapshotRetainerEdge}
Blink Reformat4c46d092018-04-07 15:32:372561 */
2562 createRetainingEdge(retainerIndex) {
Tim van der Lippefd903612019-11-07 11:29:062563 return new JSHeapSnapshotRetainerEdge(this, retainerIndex);
Blink Reformat4c46d092018-04-07 15:32:372564 }
2565
2566 /**
2567 * @override
Tim van der Lippefd903612019-11-07 11:29:062568 * @return {function(!HeapSnapshotEdge):boolean}
Blink Reformat4c46d092018-04-07 15:32:372569 */
2570 containmentEdgesFilter() {
2571 return edge => !edge.isInvisible();
2572 }
2573
2574 /**
2575 * @override
Tim van der Lippefd903612019-11-07 11:29:062576 * @return {function(!HeapSnapshotEdge):boolean}
Blink Reformat4c46d092018-04-07 15:32:372577 */
2578 retainingEdgesFilter() {
2579 const containmentEdgesFilter = this.containmentEdgesFilter();
2580 function filter(edge) {
2581 return containmentEdgesFilter(edge) && !edge.node().isRoot() && !edge.isWeak();
2582 }
2583 return filter;
2584 }
2585
2586 /**
2587 * @override
2588 */
2589 calculateFlags() {
2590 this._flags = new Uint32Array(this.nodeCount);
2591 this._markDetachedDOMTreeNodes();
2592 this._markQueriableHeapObjects();
2593 this._markPageOwnedNodes();
2594 }
2595
2596 /**
2597 * @override
2598 */
2599 calculateDistances() {
2600 /**
Tim van der Lippefd903612019-11-07 11:29:062601 * @param {!HeapSnapshotNode} node
2602 * @param {!HeapSnapshotEdge} edge
Blink Reformat4c46d092018-04-07 15:32:372603 * @return {boolean}
2604 */
2605 function filter(node, edge) {
Tim van der Lippe1d6e57a2019-09-30 11:55:342606 if (node.isHidden()) {
Blink Reformat4c46d092018-04-07 15:32:372607 return edge.name() !== 'sloppy_function_map' || node.rawName() !== 'system / NativeContext';
Tim van der Lippe1d6e57a2019-09-30 11:55:342608 }
Blink Reformat4c46d092018-04-07 15:32:372609 if (node.isArray()) {
2610 // DescriptorArrays are fixed arrays used to hold instance descriptors.
2611 // The format of the these objects is:
2612 // [0]: Number of descriptors
2613 // [1]: Either Smi(0) if uninitialized, or a pointer to small fixed array:
2614 // [0]: pointer to fixed array with enum cache
2615 // [1]: either Smi(0) or pointer to fixed array with indices
2616 // [i*3+2]: i-th key
2617 // [i*3+3]: i-th type
2618 // [i*3+4]: i-th descriptor
2619 // As long as maps may share descriptor arrays some of the descriptor
2620 // links may not be valid for all the maps. We just skip
2621 // all the descriptor links when calculating distances.
2622 // For more details see http://crbug.com/413608
Tim van der Lippe1d6e57a2019-09-30 11:55:342623 if (node.rawName() !== '(map descriptors)') {
Blink Reformat4c46d092018-04-07 15:32:372624 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:342625 }
Blink Reformat4c46d092018-04-07 15:32:372626 const index = edge.name();
2627 return index < 2 || (index % 3) !== 1;
2628 }
2629 return true;
2630 }
2631 super.calculateDistances(filter);
2632 }
2633
2634 /**
2635 * @override
2636 * @protected
Tim van der Lippefd903612019-11-07 11:29:062637 * @param {!HeapSnapshotNode} node
Blink Reformat4c46d092018-04-07 15:32:372638 * @return {boolean}
2639 */
2640 isUserRoot(node) {
2641 return node.isUserRoot() || node.isDocumentDOMTreesRoot();
2642 }
2643
2644 /**
2645 * @override
Blink Reformat4c46d092018-04-07 15:32:372646 * @return {?{map: !Uint32Array, flag: number}}
2647 */
2648 userObjectsMapAndFlag() {
2649 return {map: this._flags, flag: this._nodeFlags.pageObject};
2650 }
2651
2652 /**
Tim van der Lippefd903612019-11-07 11:29:062653 * @param {!HeapSnapshotNode} node
Blink Reformat4c46d092018-04-07 15:32:372654 * @return {number}
2655 */
2656 _flagsOfNode(node) {
2657 return this._flags[node.nodeIndex / this._nodeFieldCount];
2658 }
2659
2660 _markDetachedDOMTreeNodes() {
2661 const nodes = this.nodes;
2662 const nodesLength = nodes.length;
2663 const nodeFieldCount = this._nodeFieldCount;
2664 const nodeNativeType = this._nodeNativeType;
2665 const nodeTypeOffset = this._nodeTypeOffset;
2666 const flag = this._nodeFlags.detachedDOMTreeNode;
2667 const node = this.rootNode();
2668 for (let nodeIndex = 0, ordinal = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount, ordinal++) {
2669 const nodeType = nodes[nodeIndex + nodeTypeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:342670 if (nodeType !== nodeNativeType) {
Blink Reformat4c46d092018-04-07 15:32:372671 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342672 }
Blink Reformat4c46d092018-04-07 15:32:372673 node.nodeIndex = nodeIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:342674 if (node.name().startsWith('Detached ')) {
Blink Reformat4c46d092018-04-07 15:32:372675 this._flags[ordinal] |= flag;
Tim van der Lippe1d6e57a2019-09-30 11:55:342676 }
Blink Reformat4c46d092018-04-07 15:32:372677 }
2678 }
2679
2680 _markQueriableHeapObjects() {
2681 // Allow runtime properties query for objects accessible from Window objects
2682 // via regular properties, and for DOM wrappers. Trying to access random objects
2683 // can cause a crash due to insonsistent state of internal properties of wrappers.
2684 const flag = this._nodeFlags.canBeQueried;
2685 const hiddenEdgeType = this._edgeHiddenType;
2686 const internalEdgeType = this._edgeInternalType;
2687 const invisibleEdgeType = this._edgeInvisibleType;
2688 const weakEdgeType = this._edgeWeakType;
2689 const edgeToNodeOffset = this._edgeToNodeOffset;
2690 const edgeTypeOffset = this._edgeTypeOffset;
2691 const edgeFieldsCount = this._edgeFieldsCount;
2692 const containmentEdges = this.containmentEdges;
2693 const nodeFieldCount = this._nodeFieldCount;
2694 const firstEdgeIndexes = this._firstEdgeIndexes;
2695
2696 const flags = this._flags;
2697 const list = [];
2698
2699 for (let iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
Tim van der Lippe1d6e57a2019-09-30 11:55:342700 if (iter.edge.node().isUserRoot()) {
Blink Reformat4c46d092018-04-07 15:32:372701 list.push(iter.edge.node().nodeIndex / nodeFieldCount);
Tim van der Lippe1d6e57a2019-09-30 11:55:342702 }
Blink Reformat4c46d092018-04-07 15:32:372703 }
2704
2705 while (list.length) {
2706 const nodeOrdinal = list.pop();
Tim van der Lippe1d6e57a2019-09-30 11:55:342707 if (flags[nodeOrdinal] & flag) {
Blink Reformat4c46d092018-04-07 15:32:372708 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342709 }
Blink Reformat4c46d092018-04-07 15:32:372710 flags[nodeOrdinal] |= flag;
2711 const beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
2712 const endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
2713 for (let edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
2714 const childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
2715 const childNodeOrdinal = childNodeIndex / nodeFieldCount;
Tim van der Lippe1d6e57a2019-09-30 11:55:342716 if (flags[childNodeOrdinal] & flag) {
Blink Reformat4c46d092018-04-07 15:32:372717 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342718 }
Blink Reformat4c46d092018-04-07 15:32:372719 const type = containmentEdges[edgeIndex + edgeTypeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:342720 if (type === hiddenEdgeType || type === invisibleEdgeType || type === internalEdgeType ||
2721 type === weakEdgeType) {
Blink Reformat4c46d092018-04-07 15:32:372722 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342723 }
Blink Reformat4c46d092018-04-07 15:32:372724 list.push(childNodeOrdinal);
2725 }
2726 }
2727 }
2728
2729 _markPageOwnedNodes() {
2730 const edgeShortcutType = this._edgeShortcutType;
2731 const edgeElementType = this._edgeElementType;
2732 const edgeToNodeOffset = this._edgeToNodeOffset;
2733 const edgeTypeOffset = this._edgeTypeOffset;
2734 const edgeFieldsCount = this._edgeFieldsCount;
2735 const edgeWeakType = this._edgeWeakType;
2736 const firstEdgeIndexes = this._firstEdgeIndexes;
2737 const containmentEdges = this.containmentEdges;
2738 const nodeFieldCount = this._nodeFieldCount;
2739 const nodesCount = this.nodeCount;
2740
2741 const flags = this._flags;
2742 const pageObjectFlag = this._nodeFlags.pageObject;
2743
2744 const nodesToVisit = new Uint32Array(nodesCount);
2745 let nodesToVisitLength = 0;
2746
2747 const rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
2748 const node = this.rootNode();
2749
2750 // Populate the entry points. They are Window objects and DOM Tree Roots.
2751 for (let edgeIndex = firstEdgeIndexes[rootNodeOrdinal], endEdgeIndex = firstEdgeIndexes[rootNodeOrdinal + 1];
2752 edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
2753 const edgeType = containmentEdges[edgeIndex + edgeTypeOffset];
2754 const nodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
2755 if (edgeType === edgeElementType) {
2756 node.nodeIndex = nodeIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:342757 if (!node.isDocumentDOMTreesRoot()) {
Blink Reformat4c46d092018-04-07 15:32:372758 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342759 }
Blink Reformat4c46d092018-04-07 15:32:372760 } else if (edgeType !== edgeShortcutType) {
2761 continue;
2762 }
2763 const nodeOrdinal = nodeIndex / nodeFieldCount;
2764 nodesToVisit[nodesToVisitLength++] = nodeOrdinal;
2765 flags[nodeOrdinal] |= pageObjectFlag;
2766 }
2767
2768 // Mark everything reachable with the pageObject flag.
2769 while (nodesToVisitLength) {
2770 const nodeOrdinal = nodesToVisit[--nodesToVisitLength];
2771 const beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
2772 const endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
2773 for (let edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
2774 const childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
2775 const childNodeOrdinal = childNodeIndex / nodeFieldCount;
Tim van der Lippe1d6e57a2019-09-30 11:55:342776 if (flags[childNodeOrdinal] & pageObjectFlag) {
Blink Reformat4c46d092018-04-07 15:32:372777 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342778 }
Blink Reformat4c46d092018-04-07 15:32:372779 const type = containmentEdges[edgeIndex + edgeTypeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:342780 if (type === edgeWeakType) {
Blink Reformat4c46d092018-04-07 15:32:372781 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342782 }
Blink Reformat4c46d092018-04-07 15:32:372783 nodesToVisit[nodesToVisitLength++] = childNodeOrdinal;
2784 flags[childNodeOrdinal] |= pageObjectFlag;
2785 }
2786 }
2787 }
2788
2789 /**
2790 * @override
2791 */
2792 calculateStatistics() {
2793 const nodeFieldCount = this._nodeFieldCount;
2794 const nodes = this.nodes;
2795 const nodesLength = nodes.length;
2796 const nodeTypeOffset = this._nodeTypeOffset;
2797 const nodeSizeOffset = this._nodeSelfSizeOffset;
2798 const nodeNativeType = this._nodeNativeType;
2799 const nodeCodeType = this._nodeCodeType;
2800 const nodeConsStringType = this._nodeConsStringType;
2801 const nodeSlicedStringType = this._nodeSlicedStringType;
2802 const distances = this._nodeDistances;
2803 let sizeNative = 0;
2804 let sizeCode = 0;
2805 let sizeStrings = 0;
2806 let sizeJSArrays = 0;
2807 let sizeSystem = 0;
2808 const node = this.rootNode();
2809 for (let nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
2810 const nodeSize = nodes[nodeIndex + nodeSizeOffset];
2811 const ordinal = nodeIndex / nodeFieldCount;
Tim van der Lippee2a36ca2020-01-24 13:41:252812 if (distances[ordinal] >= HeapSnapshotModel.HeapSnapshotModel.baseSystemDistance) {
Blink Reformat4c46d092018-04-07 15:32:372813 sizeSystem += nodeSize;
2814 continue;
2815 }
2816 const nodeType = nodes[nodeIndex + nodeTypeOffset];
2817 node.nodeIndex = nodeIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:342818 if (nodeType === nodeNativeType) {
Blink Reformat4c46d092018-04-07 15:32:372819 sizeNative += nodeSize;
Tim van der Lippe1d6e57a2019-09-30 11:55:342820 } else if (nodeType === nodeCodeType) {
Blink Reformat4c46d092018-04-07 15:32:372821 sizeCode += nodeSize;
Tim van der Lippe1d6e57a2019-09-30 11:55:342822 } else if (nodeType === nodeConsStringType || nodeType === nodeSlicedStringType || node.type() === 'string') {
Blink Reformat4c46d092018-04-07 15:32:372823 sizeStrings += nodeSize;
Tim van der Lippe1d6e57a2019-09-30 11:55:342824 } else if (node.name() === 'Array') {
Blink Reformat4c46d092018-04-07 15:32:372825 sizeJSArrays += this._calculateArraySize(node);
Tim van der Lippe1d6e57a2019-09-30 11:55:342826 }
Blink Reformat4c46d092018-04-07 15:32:372827 }
Tim van der Lippee2a36ca2020-01-24 13:41:252828 this._statistics = new HeapSnapshotModel.HeapSnapshotModel.Statistics();
Blink Reformat4c46d092018-04-07 15:32:372829 this._statistics.total = this.totalSize;
2830 this._statistics.v8heap = this.totalSize - sizeNative;
2831 this._statistics.native = sizeNative;
2832 this._statistics.code = sizeCode;
2833 this._statistics.jsArrays = sizeJSArrays;
2834 this._statistics.strings = sizeStrings;
2835 this._statistics.system = sizeSystem;
2836 }
2837
2838 /**
Tim van der Lippefd903612019-11-07 11:29:062839 * @param {!HeapSnapshotNode} node
Blink Reformat4c46d092018-04-07 15:32:372840 * @return {number}
2841 */
2842 _calculateArraySize(node) {
2843 let size = node.selfSize();
2844 const beginEdgeIndex = node.edgeIndexesStart();
2845 const endEdgeIndex = node.edgeIndexesEnd();
2846 const containmentEdges = this.containmentEdges;
2847 const strings = this.strings;
2848 const edgeToNodeOffset = this._edgeToNodeOffset;
2849 const edgeTypeOffset = this._edgeTypeOffset;
2850 const edgeNameOffset = this._edgeNameOffset;
2851 const edgeFieldsCount = this._edgeFieldsCount;
2852 const edgeInternalType = this._edgeInternalType;
2853 for (let edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
2854 const edgeType = containmentEdges[edgeIndex + edgeTypeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:342855 if (edgeType !== edgeInternalType) {
Blink Reformat4c46d092018-04-07 15:32:372856 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342857 }
Blink Reformat4c46d092018-04-07 15:32:372858 const edgeName = strings[containmentEdges[edgeIndex + edgeNameOffset]];
Tim van der Lippe1d6e57a2019-09-30 11:55:342859 if (edgeName !== 'elements') {
Blink Reformat4c46d092018-04-07 15:32:372860 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342861 }
Blink Reformat4c46d092018-04-07 15:32:372862 const elementsNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
2863 node.nodeIndex = elementsNodeIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:342864 if (node.retainersCount() === 1) {
Blink Reformat4c46d092018-04-07 15:32:372865 size += node.selfSize();
Tim van der Lippe1d6e57a2019-09-30 11:55:342866 }
Blink Reformat4c46d092018-04-07 15:32:372867 break;
2868 }
2869 return size;
2870 }
2871
2872 /**
Tim van der Lippee2a36ca2020-01-24 13:41:252873 * @return {!HeapSnapshotModel.HeapSnapshotModel.Statistics}
Blink Reformat4c46d092018-04-07 15:32:372874 */
2875 getStatistics() {
2876 return this._statistics;
2877 }
Tim van der Lippefd903612019-11-07 11:29:062878}
Blink Reformat4c46d092018-04-07 15:32:372879
2880/**
2881 * @unrestricted
2882 */
Tim van der Lippefd903612019-11-07 11:29:062883export class JSHeapSnapshotNode extends HeapSnapshotNode {
Blink Reformat4c46d092018-04-07 15:32:372884 /**
Tim van der Lippefd903612019-11-07 11:29:062885 * @param {!JSHeapSnapshot} snapshot
Blink Reformat4c46d092018-04-07 15:32:372886 * @param {number=} nodeIndex
2887 */
2888 constructor(snapshot, nodeIndex) {
2889 super(snapshot, nodeIndex);
2890 }
2891
2892 /**
2893 * @return {boolean}
2894 */
2895 canBeQueried() {
2896 const flags = this._snapshot._flagsOfNode(this);
2897 return !!(flags & this._snapshot._nodeFlags.canBeQueried);
2898 }
2899
2900 /**
2901 * @return {string}
2902 */
2903 rawName() {
2904 return super.name();
2905 }
2906
2907 /**
2908 * @override
2909 * @return {string}
2910 */
2911 name() {
2912 const snapshot = this._snapshot;
2913 if (this.rawType() === snapshot._nodeConsStringType) {
2914 let string = snapshot._lazyStringCache[this.nodeIndex];
2915 if (typeof string === 'undefined') {
2916 string = this._consStringName();
2917 snapshot._lazyStringCache[this.nodeIndex] = string;
2918 }
2919 return string;
2920 }
2921 return this.rawName();
2922 }
2923
2924 /**
2925 * @return {string}
2926 */
2927 _consStringName() {
2928 const snapshot = this._snapshot;
2929 const consStringType = snapshot._nodeConsStringType;
2930 const edgeInternalType = snapshot._edgeInternalType;
2931 const edgeFieldsCount = snapshot._edgeFieldsCount;
2932 const edgeToNodeOffset = snapshot._edgeToNodeOffset;
2933 const edgeTypeOffset = snapshot._edgeTypeOffset;
2934 const edgeNameOffset = snapshot._edgeNameOffset;
2935 const strings = snapshot.strings;
2936 const edges = snapshot.containmentEdges;
2937 const firstEdgeIndexes = snapshot._firstEdgeIndexes;
2938 const nodeFieldCount = snapshot._nodeFieldCount;
2939 const nodeTypeOffset = snapshot._nodeTypeOffset;
2940 const nodeNameOffset = snapshot._nodeNameOffset;
2941 const nodes = snapshot.nodes;
2942 const nodesStack = [];
2943 nodesStack.push(this.nodeIndex);
2944 let name = '';
2945
2946 while (nodesStack.length && name.length < 1024) {
2947 const nodeIndex = nodesStack.pop();
2948 if (nodes[nodeIndex + nodeTypeOffset] !== consStringType) {
2949 name += strings[nodes[nodeIndex + nodeNameOffset]];
2950 continue;
2951 }
2952 const nodeOrdinal = nodeIndex / nodeFieldCount;
2953 const beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
2954 const endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
2955 let firstNodeIndex = 0;
2956 let secondNodeIndex = 0;
2957 for (let edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex && (!firstNodeIndex || !secondNodeIndex);
2958 edgeIndex += edgeFieldsCount) {
2959 const edgeType = edges[edgeIndex + edgeTypeOffset];
2960 if (edgeType === edgeInternalType) {
2961 const edgeName = strings[edges[edgeIndex + edgeNameOffset]];
Tim van der Lippe1d6e57a2019-09-30 11:55:342962 if (edgeName === 'first') {
Blink Reformat4c46d092018-04-07 15:32:372963 firstNodeIndex = edges[edgeIndex + edgeToNodeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:342964 } else if (edgeName === 'second') {
Blink Reformat4c46d092018-04-07 15:32:372965 secondNodeIndex = edges[edgeIndex + edgeToNodeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:342966 }
Blink Reformat4c46d092018-04-07 15:32:372967 }
2968 }
2969 nodesStack.push(secondNodeIndex);
2970 nodesStack.push(firstNodeIndex);
2971 }
2972 return name;
2973 }
2974
2975 /**
2976 * @override
2977 * @return {string}
2978 */
2979 className() {
2980 const type = this.type();
2981 switch (type) {
2982 case 'hidden':
2983 return '(system)';
2984 case 'object':
2985 case 'native':
2986 return this.name();
2987 case 'code':
2988 return '(compiled code)';
2989 default:
2990 return '(' + type + ')';
2991 }
2992 }
2993
2994 /**
2995 * @override
2996 * @return {number}
2997 */
2998 classIndex() {
2999 const snapshot = this._snapshot;
3000 const nodes = snapshot.nodes;
3001 const type = nodes[this.nodeIndex + snapshot._nodeTypeOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:343002 if (type === snapshot._nodeObjectType || type === snapshot._nodeNativeType) {
Blink Reformat4c46d092018-04-07 15:32:373003 return nodes[this.nodeIndex + snapshot._nodeNameOffset];
Tim van der Lippe1d6e57a2019-09-30 11:55:343004 }
Blink Reformat4c46d092018-04-07 15:32:373005 return -1 - type;
3006 }
3007
3008 /**
3009 * @override
3010 * @return {number}
3011 */
3012 id() {
3013 const snapshot = this._snapshot;
3014 return snapshot.nodes[this.nodeIndex + snapshot._nodeIdOffset];
3015 }
3016
3017 /**
3018 * @return {boolean}
3019 */
3020 isHidden() {
3021 return this.rawType() === this._snapshot._nodeHiddenType;
3022 }
3023
3024 /**
3025 * @return {boolean}
3026 */
3027 isArray() {
3028 return this.rawType() === this._snapshot._nodeArrayType;
3029 }
3030
3031 /**
3032 * @return {boolean}
3033 */
3034 isSynthetic() {
3035 return this.rawType() === this._snapshot._nodeSyntheticType;
3036 }
3037
3038 /**
3039 * @return {boolean}
3040 */
3041 isUserRoot() {
3042 return !this.isSynthetic();
3043 }
3044
3045 /**
3046 * @return {boolean}
3047 */
3048 isDocumentDOMTreesRoot() {
3049 return this.isSynthetic() && this.name() === '(Document DOM trees)';
3050 }
3051
3052 /**
3053 * @override
Tim van der Lippee2a36ca2020-01-24 13:41:253054 * @return {!HeapSnapshotModel.HeapSnapshotModel.Node}
Blink Reformat4c46d092018-04-07 15:32:373055 */
3056 serialize() {
3057 const result = super.serialize();
3058 const flags = this._snapshot._flagsOfNode(this);
Tim van der Lippe1d6e57a2019-09-30 11:55:343059 if (flags & this._snapshot._nodeFlags.canBeQueried) {
Blink Reformat4c46d092018-04-07 15:32:373060 result.canBeQueried = true;
Tim van der Lippe1d6e57a2019-09-30 11:55:343061 }
3062 if (flags & this._snapshot._nodeFlags.detachedDOMTreeNode) {
Blink Reformat4c46d092018-04-07 15:32:373063 result.detachedDOMTreeNode = true;
Tim van der Lippe1d6e57a2019-09-30 11:55:343064 }
Blink Reformat4c46d092018-04-07 15:32:373065 return result;
3066 }
Tim van der Lippefd903612019-11-07 11:29:063067}
Blink Reformat4c46d092018-04-07 15:32:373068
3069/**
3070 * @unrestricted
3071 */
Tim van der Lippefd903612019-11-07 11:29:063072export class JSHeapSnapshotEdge extends HeapSnapshotEdge {
Blink Reformat4c46d092018-04-07 15:32:373073 /**
Tim van der Lippefd903612019-11-07 11:29:063074 * @param {!JSHeapSnapshot} snapshot
Blink Reformat4c46d092018-04-07 15:32:373075 * @param {number=} edgeIndex
3076 */
3077 constructor(snapshot, edgeIndex) {
3078 super(snapshot, edgeIndex);
3079 }
3080
3081 /**
3082 * @override
Tim van der Lippefd903612019-11-07 11:29:063083 * @return {!JSHeapSnapshotEdge}
Blink Reformat4c46d092018-04-07 15:32:373084 */
3085 clone() {
Tim van der Lippefd903612019-11-07 11:29:063086 const snapshot = /** @type {!JSHeapSnapshot} */ (this._snapshot);
3087 return new JSHeapSnapshotEdge(snapshot, this.edgeIndex);
Blink Reformat4c46d092018-04-07 15:32:373088 }
3089
3090 /**
3091 * @override
3092 * @return {boolean}
3093 */
3094 hasStringName() {
Tim van der Lippe1d6e57a2019-09-30 11:55:343095 if (!this.isShortcut()) {
Blink Reformat4c46d092018-04-07 15:32:373096 return this._hasStringName();
Tim van der Lippe1d6e57a2019-09-30 11:55:343097 }
Blink Reformat4c46d092018-04-07 15:32:373098 return isNaN(parseInt(this._name(), 10));
3099 }
3100
3101 /**
3102 * @return {boolean}
3103 */
3104 isElement() {
3105 return this.rawType() === this._snapshot._edgeElementType;
3106 }
3107
3108 /**
3109 * @return {boolean}
3110 */
3111 isHidden() {
3112 return this.rawType() === this._snapshot._edgeHiddenType;
3113 }
3114
3115 /**
3116 * @return {boolean}
3117 */
3118 isWeak() {
3119 return this.rawType() === this._snapshot._edgeWeakType;
3120 }
3121
3122 /**
3123 * @return {boolean}
3124 */
3125 isInternal() {
3126 return this.rawType() === this._snapshot._edgeInternalType;
3127 }
3128
3129 /**
3130 * @return {boolean}
3131 */
3132 isInvisible() {
3133 return this.rawType() === this._snapshot._edgeInvisibleType;
3134 }
3135
3136 /**
3137 * @return {boolean}
3138 */
3139 isShortcut() {
3140 return this.rawType() === this._snapshot._edgeShortcutType;
3141 }
3142
3143 /**
3144 * @override
3145 * @return {string}
3146 */
3147 name() {
3148 const name = this._name();
Tim van der Lippe1d6e57a2019-09-30 11:55:343149 if (!this.isShortcut()) {
Blink Reformat4c46d092018-04-07 15:32:373150 return String(name);
Tim van der Lippe1d6e57a2019-09-30 11:55:343151 }
Blink Reformat4c46d092018-04-07 15:32:373152 const numName = parseInt(name, 10);
3153 return String(isNaN(numName) ? name : numName);
3154 }
3155
3156 /**
3157 * @override
3158 * @return {string}
3159 */
3160 toString() {
3161 const name = this.name();
3162 switch (this.type()) {
3163 case 'context':
3164 return '->' + name;
3165 case 'element':
3166 return '[' + name + ']';
3167 case 'weak':
3168 return '[[' + name + ']]';
3169 case 'property':
3170 return name.indexOf(' ') === -1 ? '.' + name : '["' + name + '"]';
3171 case 'shortcut':
Tim van der Lippe1d6e57a2019-09-30 11:55:343172 if (typeof name === 'string') {
Blink Reformat4c46d092018-04-07 15:32:373173 return name.indexOf(' ') === -1 ? '.' + name : '["' + name + '"]';
Tim van der Lippe1d6e57a2019-09-30 11:55:343174 }
Mathias Bynensf06e8c02020-02-28 13:58:283175 return '[' + name + ']';
Blink Reformat4c46d092018-04-07 15:32:373176 case 'internal':
3177 case 'hidden':
3178 case 'invisible':
3179 return '{' + name + '}';
3180 }
3181 return '?' + name + '?';
3182 }
3183
3184 /**
3185 * @return {boolean}
3186 */
3187 _hasStringName() {
3188 const type = this.rawType();
3189 const snapshot = this._snapshot;
3190 return type !== snapshot._edgeElementType && type !== snapshot._edgeHiddenType;
3191 }
3192
3193 /**
3194 * @return {string|number}
3195 */
3196 _name() {
3197 return this._hasStringName() ? this._snapshot.strings[this._nameOrIndex()] : this._nameOrIndex();
3198 }
3199
3200 /**
3201 * @return {number}
3202 */
3203 _nameOrIndex() {
3204 return this._edges[this.edgeIndex + this._snapshot._edgeNameOffset];
3205 }
3206
3207 /**
3208 * @override
3209 * @return {number}
3210 */
3211 rawType() {
3212 return this._edges[this.edgeIndex + this._snapshot._edgeTypeOffset];
3213 }
Tim van der Lippefd903612019-11-07 11:29:063214}
Blink Reformat4c46d092018-04-07 15:32:373215
3216/**
3217 * @unrestricted
3218 */
Tim van der Lippefd903612019-11-07 11:29:063219export class JSHeapSnapshotRetainerEdge extends HeapSnapshotRetainerEdge {
Blink Reformat4c46d092018-04-07 15:32:373220 /**
Tim van der Lippefd903612019-11-07 11:29:063221 * @param {!JSHeapSnapshot} snapshot
Blink Reformat4c46d092018-04-07 15:32:373222 * @param {number} retainerIndex
3223 */
3224 constructor(snapshot, retainerIndex) {
3225 super(snapshot, retainerIndex);
3226 }
3227
3228 /**
3229 * @override
Tim van der Lippefd903612019-11-07 11:29:063230 * @return {!JSHeapSnapshotRetainerEdge}
Blink Reformat4c46d092018-04-07 15:32:373231 */
3232 clone() {
Tim van der Lippefd903612019-11-07 11:29:063233 const snapshot = /** @type {!JSHeapSnapshot} */ (this._snapshot);
3234 return new JSHeapSnapshotRetainerEdge(snapshot, this.retainerIndex());
Blink Reformat4c46d092018-04-07 15:32:373235 }
3236
3237 /**
3238 * @return {boolean}
3239 */
3240 isHidden() {
3241 return this._edge().isHidden();
3242 }
3243
3244 /**
3245 * @return {boolean}
3246 */
3247 isInternal() {
3248 return this._edge().isInternal();
3249 }
3250
3251 /**
3252 * @return {boolean}
3253 */
3254 isInvisible() {
3255 return this._edge().isInvisible();
3256 }
3257
3258 /**
3259 * @return {boolean}
3260 */
3261 isShortcut() {
3262 return this._edge().isShortcut();
3263 }
3264
3265 /**
3266 * @return {boolean}
3267 */
3268 isWeak() {
3269 return this._edge().isWeak();
3270 }
Tim van der Lippefd903612019-11-07 11:29:063271}
Blink Reformat4c46d092018-04-07 15:32:373272
3273(function disableLoggingForTest() {
3274 // Runtime doesn't exist because this file is loaded as a one-off
3275 // file in some inspector-protocol tests.
Tim van der Lippe99e59b82019-09-30 20:00:593276 if (self.Root && self.Root.Runtime && Root.Runtime.queryParam('test')) {
Blink Reformat4c46d092018-04-07 15:32:373277 console.warn = () => undefined;
Tim van der Lippe1d6e57a2019-09-30 11:55:343278 }
Blink Reformat4c46d092018-04-07 15:32:373279})();