2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 * @extends {WebInspector.DataGridNode}
34 * @param {!WebInspector.HeapSnapshotSortableDataGrid} tree
35 * @param {boolean} hasChildren
37 WebInspector
.HeapSnapshotGridNode = function(tree
, hasChildren
)
39 WebInspector
.DataGridNode
.call(this, null, hasChildren
);
40 this._dataGrid
= tree
;
41 this._instanceCount
= 0;
43 this._savedChildren
= null;
45 * List of position ranges for all visible nodes: [startPos1, endPos1),...,[startPosN, endPosN)
46 * Position is an item position in the provider.
48 this._retrievedChildrenRanges
= [];
51 * @type {?WebInspector.HeapSnapshotGridNode.ChildrenProvider}
53 this._providerObject
= null;
56 WebInspector
.HeapSnapshotGridNode
.Events
= {
57 PopulateComplete
: "PopulateComplete"
61 * @param {!Array.<string>} fieldNames
62 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
64 WebInspector
.HeapSnapshotGridNode
.createComparator = function(fieldNames
)
66 return /** @type {!WebInspector.HeapSnapshotCommon.ComparatorConfig} */ ({fieldName1
: fieldNames
[0], ascending1
: fieldNames
[1], fieldName2
: fieldNames
[2], ascending2
: fieldNames
[3]});
73 WebInspector
.HeapSnapshotGridNode
.ChildrenProvider = function() { }
75 WebInspector
.HeapSnapshotGridNode
.ChildrenProvider
.prototype = {
76 dispose: function() { },
79 * @param {number} snapshotObjectId
80 * @return {!Promise<number>}
82 nodePosition: function(snapshotObjectId
) { },
85 * @param {function(boolean)} callback
87 isEmpty: function(callback
) { },
90 * @param {number} startPosition
91 * @param {number} endPosition
92 * @param {function(!WebInspector.HeapSnapshotCommon.ItemsRange)} callback
94 serializeItemsRange: function(startPosition
, endPosition
, callback
) { },
97 * @param {!WebInspector.HeapSnapshotCommon.ComparatorConfig} comparator
98 * @return {!Promise<?>}
100 sortAndRewind: function(comparator
) { }
104 WebInspector
.HeapSnapshotGridNode
.prototype = {
106 * @return {!WebInspector.HeapSnapshotSortableDataGrid}
108 heapSnapshotDataGrid: function()
110 return this._dataGrid
;
114 * @return {!WebInspector.HeapSnapshotGridNode.ChildrenProvider}
116 createProvider: function()
118 throw new Error("Not implemented.");
122 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
124 retainersDataSource: function()
130 * @return {!WebInspector.HeapSnapshotGridNode.ChildrenProvider}
132 _provider: function()
134 if (!this._providerObject
)
135 this._providerObject
= this.createProvider();
136 return this._providerObject
;
141 * @param {string} columnIdentifier
144 createCell: function(columnIdentifier
)
146 var cell
= WebInspector
.DataGridNode
.prototype.createCell
.call(this, columnIdentifier
);
147 if (this._searchMatched
)
148 cell
.classList
.add("highlight");
157 WebInspector
.DataGridNode
.prototype.collapse
.call(this);
158 this._dataGrid
.updateVisibleNodes(true);
166 WebInspector
.DataGridNode
.prototype.expand
.call(this);
167 this._dataGrid
.updateVisibleNodes(true);
172 if (this._providerObject
)
173 this._providerObject
.dispose();
174 for (var node
= this.children
[0]; node
; node
= node
.traverseNextNode(true, this, true))
179 _reachableFromWindow
: false,
181 queryObjectContent: function(callback
)
188 wasDetached: function()
190 this._dataGrid
.nodeWasDetached(this);
194 * @param {number} num
197 _toPercentString: function(num
)
199 return num
.toFixed(0) + "\u2009%"; // \u2009 is a thin space.
203 * @param {number} distance
206 _toUIDistance: function(distance
)
208 var baseSystemDistance
= WebInspector
.HeapSnapshotCommon
.baseSystemDistance
;
209 return distance
>= 0 && distance
< baseSystemDistance
? WebInspector
.UIString("%d", distance
) : WebInspector
.UIString("\u2212");
213 * @return {!Array.<!WebInspector.DataGridNode>}
215 allChildren: function()
217 return this._dataGrid
.allChildren(this);
221 * @param {number} index
223 removeChildByIndex: function(index
)
225 this._dataGrid
.removeChildByIndex(this, index
);
229 * @param {number} nodePosition
230 * @return {?WebInspector.DataGridNode}
232 childForPosition: function(nodePosition
)
234 var indexOfFirstChildInRange
= 0;
235 for (var i
= 0; i
< this._retrievedChildrenRanges
.length
; i
++) {
236 var range
= this._retrievedChildrenRanges
[i
];
237 if (range
.from <= nodePosition
&& nodePosition
< range
.to
) {
238 var childIndex
= indexOfFirstChildInRange
+ nodePosition
- range
.from;
239 return this.allChildren()[childIndex
];
241 indexOfFirstChildInRange
+= range
.to
- range
.from + 1;
247 * @param {string} columnIdentifier
250 _createValueCell: function(columnIdentifier
)
252 var cell
= createElement("td");
253 cell
.className
= "numeric-column";
254 if (this.dataGrid
.snapshot
.totalSize
!== 0) {
255 var div
= createElement("div");
256 var valueSpan
= createElement("span");
257 valueSpan
.textContent
= this.data
[columnIdentifier
];
258 div
.appendChild(valueSpan
);
259 var percentColumn
= columnIdentifier
+ "-percent";
260 if (percentColumn
in this.data
) {
261 var percentSpan
= createElement("span");
262 percentSpan
.className
= "percent-column";
263 percentSpan
.textContent
= this.data
[percentColumn
];
264 div
.appendChild(percentSpan
);
265 div
.classList
.add("profile-multiple-values");
267 cell
.appendChild(div
);
272 populate: function(event
)
276 this._populated
= true;
277 this._provider().sortAndRewind(this.comparator()).then(this._populateChildren
.bind(this));
281 * @return {!Promise<?>}
283 expandWithoutPopulate: function()
285 // Make sure default populate won't take action.
286 this._populated
= true;
288 return this._provider().sortAndRewind(this.comparator());
292 * @param {?number=} fromPosition
293 * @param {?number=} toPosition
294 * @param {function()=} afterPopulate
296 _populateChildren: function(fromPosition
, toPosition
, afterPopulate
)
298 fromPosition
= fromPosition
|| 0;
299 toPosition
= toPosition
|| fromPosition
+ this._dataGrid
.defaultPopulateCount();
300 var firstNotSerializedPosition
= fromPosition
;
303 * @this {WebInspector.HeapSnapshotGridNode}
305 function serializeNextChunk()
307 if (firstNotSerializedPosition
>= toPosition
)
309 var end
= Math
.min(firstNotSerializedPosition
+ this._dataGrid
.defaultPopulateCount(), toPosition
);
310 this._provider().serializeItemsRange(firstNotSerializedPosition
, end
, childrenRetrieved
.bind(this));
311 firstNotSerializedPosition
= end
;
315 * @this {WebInspector.HeapSnapshotGridNode}
317 function insertRetrievedChild(item
, insertionIndex
)
319 if (this._savedChildren
) {
320 var hash
= this._childHashForEntity(item
);
321 if (hash
in this._savedChildren
) {
322 this._dataGrid
.insertChild(this, this._savedChildren
[hash
], insertionIndex
);
326 this._dataGrid
.insertChild(this, this._createChildNode(item
), insertionIndex
);
330 * @this {WebInspector.HeapSnapshotGridNode}
332 function insertShowMoreButton(from, to
, insertionIndex
)
334 var button
= new WebInspector
.ShowMoreDataGridNode(this._populateChildren
.bind(this), from, to
, this._dataGrid
.defaultPopulateCount());
335 this._dataGrid
.insertChild(this, button
, insertionIndex
);
339 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
340 * @this {WebInspector.HeapSnapshotGridNode}
342 function childrenRetrieved(itemsRange
)
345 var itemPosition
= itemsRange
.startPosition
;
346 var items
= itemsRange
.items
;
347 var insertionIndex
= 0;
349 if (!this._retrievedChildrenRanges
.length
) {
350 if (itemsRange
.startPosition
> 0) {
351 this._retrievedChildrenRanges
.push({from: 0, to
: 0});
352 insertShowMoreButton
.call(this, 0, itemsRange
.startPosition
, insertionIndex
++);
354 this._retrievedChildrenRanges
.push({from: itemsRange
.startPosition
, to
: itemsRange
.endPosition
});
355 for (var i
= 0, l
= items
.length
; i
< l
; ++i
)
356 insertRetrievedChild
.call(this, items
[i
], insertionIndex
++);
357 if (itemsRange
.endPosition
< itemsRange
.totalLength
)
358 insertShowMoreButton
.call(this, itemsRange
.endPosition
, itemsRange
.totalLength
, insertionIndex
++);
363 while (rangeIndex
< this._retrievedChildrenRanges
.length
) {
364 range
= this._retrievedChildrenRanges
[rangeIndex
];
365 if (range
.to
>= itemPosition
) {
369 insertionIndex
+= range
.to
- range
.from;
370 // Skip the button if there is one.
371 if (range
.to
< itemsRange
.totalLength
)
376 if (!found
|| itemsRange
.startPosition
< range
.from) {
377 // Update previous button.
378 this.allChildren()[insertionIndex
- 1].setEndPosition(itemsRange
.startPosition
);
379 insertShowMoreButton
.call(this, itemsRange
.startPosition
, found
? range
.from : itemsRange
.totalLength
, insertionIndex
);
380 range
= {from: itemsRange
.startPosition
, to
: itemsRange
.startPosition
};
382 rangeIndex
= this._retrievedChildrenRanges
.length
;
383 this._retrievedChildrenRanges
.splice(rangeIndex
, 0, range
);
385 insertionIndex
+= itemPosition
- range
.from;
387 // At this point insertionIndex is always an index before button or between nodes.
388 // Also it is always true here that range.from <= itemPosition <= range.to
390 // Stretch the range right bound to include all new items.
391 while (range
.to
< itemsRange
.endPosition
) {
392 // Skip already added nodes.
393 var skipCount
= range
.to
- itemPosition
;
394 insertionIndex
+= skipCount
;
395 itemIndex
+= skipCount
;
396 itemPosition
= range
.to
;
398 // We're at the position before button: ...<?node>x<button>
399 var nextRange
= this._retrievedChildrenRanges
[rangeIndex
+ 1];
400 var newEndOfRange
= nextRange
? nextRange
.from : itemsRange
.totalLength
;
401 if (newEndOfRange
> itemsRange
.endPosition
)
402 newEndOfRange
= itemsRange
.endPosition
;
403 while (itemPosition
< newEndOfRange
) {
404 insertRetrievedChild
.call(this, items
[itemIndex
++], insertionIndex
++);
408 // Merge with the next range.
409 if (nextRange
&& newEndOfRange
=== nextRange
.from) {
410 range
.to
= nextRange
.to
;
411 // Remove "show next" button if there is one.
412 this.removeChildByIndex(insertionIndex
);
413 this._retrievedChildrenRanges
.splice(rangeIndex
+ 1, 1);
415 range
.to
= newEndOfRange
;
416 // Remove or update next button.
417 if (newEndOfRange
=== itemsRange
.totalLength
)
418 this.removeChildByIndex(insertionIndex
);
420 this.allChildren()[insertionIndex
].setStartPosition(itemsRange
.endPosition
);
426 this._instanceCount
+= items
.length
;
427 if (firstNotSerializedPosition
< toPosition
) {
428 serializeNextChunk
.call(this);
433 this._dataGrid
.updateVisibleNodes(true);
436 this.dispatchEventToListeners(WebInspector
.HeapSnapshotGridNode
.Events
.PopulateComplete
);
438 serializeNextChunk
.call(this);
441 _saveChildren: function()
443 this._savedChildren
= null;
444 var children
= this.allChildren();
445 for (var i
= 0, l
= children
.length
; i
< l
; ++i
) {
446 var child
= children
[i
];
449 if (!this._savedChildren
)
450 this._savedChildren
= {};
451 this._savedChildren
[this._childHashForNode(child
)] = child
;
457 this._dataGrid
.recursiveSortingEnter();
460 * @this {WebInspector.HeapSnapshotGridNode}
464 this._saveChildren();
465 this._dataGrid
.removeAllChildren(this);
466 this._retrievedChildrenRanges
= [];
469 * @this {WebInspector.HeapSnapshotGridNode}
471 function afterPopulate()
473 var children
= this.allChildren();
474 for (var i
= 0, l
= children
.length
; i
< l
; ++i
) {
475 var child
= children
[i
];
479 this._dataGrid
.recursiveSortingLeave();
481 var instanceCount
= this._instanceCount
;
482 this._instanceCount
= 0;
483 this._populateChildren(0, instanceCount
, afterPopulate
.bind(this));
486 this._provider().sortAndRewind(this.comparator()).then(afterSort
.bind(this));
489 __proto__
: WebInspector
.DataGridNode
.prototype
495 * @extends {WebInspector.HeapSnapshotGridNode}
496 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
497 * @param {!WebInspector.HeapSnapshotCommon.Node} node
499 WebInspector
.HeapSnapshotGenericObjectNode = function(dataGrid
, node
)
501 WebInspector
.HeapSnapshotGridNode
.call(this, dataGrid
, false);
502 // node is null for DataGrid root nodes.
505 this._name
= node
.name
;
506 this._type
= node
.type
;
507 this._distance
= node
.distance
;
508 this._shallowSize
= node
.selfSize
;
509 this._retainedSize
= node
.retainedSize
;
510 this.snapshotNodeId
= node
.id
;
511 this.snapshotNodeIndex
= node
.nodeIndex
;
512 if (this._type
=== "string")
513 this._reachableFromWindow
= true;
514 else if (this._type
=== "object" && this._name
.startsWith("Window")) {
515 this._name
= this.shortenWindowURL(this._name
, false);
516 this._reachableFromWindow
= true;
517 } else if (node
.canBeQueried
)
518 this._reachableFromWindow
= true;
519 if (node
.detachedDOMTreeNode
)
520 this.detachedDOMTreeNode
= true;
522 var snapshot
= dataGrid
.snapshot
;
523 var shallowSizePercent
= this._shallowSize
/ snapshot
.totalSize
* 100.0;
524 var retainedSizePercent
= this._retainedSize
/ snapshot
.totalSize
* 100.0;
526 "distance": this._toUIDistance(this._distance
),
527 "shallowSize": Number
.withThousandsSeparator(this._shallowSize
),
528 "retainedSize": Number
.withThousandsSeparator(this._retainedSize
),
529 "shallowSize-percent": this._toPercentString(shallowSizePercent
),
530 "retainedSize-percent": this._toPercentString(retainedSizePercent
)
534 WebInspector
.HeapSnapshotGenericObjectNode
.prototype = {
537 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
539 retainersDataSource: function()
541 return {snapshot
: this._dataGrid
.snapshot
, snapshotNodeIndex
: this.snapshotNodeIndex
};
546 * @param {string} columnIdentifier
549 createCell: function(columnIdentifier
)
551 var cell
= columnIdentifier
!== "object" ? this._createValueCell(columnIdentifier
) : this._createObjectCell();
552 if (this._searchMatched
)
553 cell
.classList
.add("highlight");
560 _createObjectCell: function()
562 var value
= this._name
;
563 var valueStyle
= "object";
564 switch (this._type
) {
565 case "concatenated string":
567 value
= "\"" + value
+ "\"";
568 valueStyle
= "string";
571 value
= "/" + value
+ "/";
572 valueStyle
= "string";
575 value
= value
+ "()";
576 valueStyle
= "function";
579 valueStyle
= "number";
585 value
= (value
|| "") + "[]";
588 if (this._reachableFromWindow
)
589 valueStyle
+= " highlight";
590 if (value
=== "Object")
592 if (this.detachedDOMTreeNode
)
593 valueStyle
+= " detached-dom-tree-node";
594 return this._createObjectCellWithValue(valueStyle
, value
);
597 _createObjectCellWithValue: function(valueStyle
, value
)
599 var cell
= createElement("td");
600 cell
.className
= "object-column";
601 var div
= createElement("div");
602 div
.className
= "source-code event-properties";
603 div
.style
.overflow
= "visible";
605 this._prefixObjectCell(div
);
607 var valueSpan
= createElement("span");
608 valueSpan
.className
= "value object-value-" + valueStyle
;
609 valueSpan
.textContent
= value
;
610 div
.appendChild(valueSpan
);
612 var idSpan
= createElement("span");
613 idSpan
.className
= "object-value-id";
614 idSpan
.textContent
= " @" + this.snapshotNodeId
;
615 div
.appendChild(idSpan
);
617 cell
.appendChild(div
);
618 cell
.classList
.add("disclosure");
620 cell
.style
.setProperty("padding-left", (this.depth
* this.dataGrid
.indentWidth
) + "px");
621 cell
.heapSnapshotNode
= this;
625 _prefixObjectCell: function(div
)
630 * @param {!WebInspector.Target} target
631 * @param {function(!WebInspector.RemoteObject)} callback
632 * @param {string} objectGroupName
634 queryObjectContent: function(target
, callback
, objectGroupName
)
637 * @param {?Protocol.Error} error
638 * @param {!RuntimeAgent.RemoteObject} object
640 function formatResult(error
, object
)
642 if (!error
&& object
.type
)
643 callback(target
.runtimeModel
.createRemoteObject(object
));
645 callback(target
.runtimeModel
.createRemoteObjectFromPrimitiveValue(WebInspector
.UIString("Preview is not available")));
648 if (this._type
=== "string")
649 callback(target
.runtimeModel
.createRemoteObjectFromPrimitiveValue(this._name
));
651 target
.heapProfilerAgent().getObjectByHeapObjectId(String(this.snapshotNodeId
), objectGroupName
, formatResult
);
654 updateHasChildren: function()
657 * @this {WebInspector.HeapSnapshotGenericObjectNode}
659 function isEmptyCallback(isEmpty
)
661 this.hasChildren
= !isEmpty
;
663 this._provider().isEmpty(isEmptyCallback
.bind(this));
667 * @param {string} fullName
668 * @param {boolean} hasObjectId
671 shortenWindowURL: function(fullName
, hasObjectId
)
673 var startPos
= fullName
.indexOf("/");
674 var endPos
= hasObjectId
? fullName
.indexOf("@") : fullName
.length
;
675 if (startPos
!== -1 && endPos
!== -1) {
676 var fullURL
= fullName
.substring(startPos
+ 1, endPos
).trimLeft();
677 var url
= fullURL
.trimURL();
679 url
= url
.trimMiddle(40);
680 return fullName
.substr(0, startPos
+ 2) + url
+ fullName
.substr(endPos
);
685 __proto__
: WebInspector
.HeapSnapshotGridNode
.prototype
690 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
691 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
692 * @param {!WebInspector.HeapSnapshotProxy} snapshot
693 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
694 * @param {?WebInspector.HeapSnapshotObjectNode} parentObjectNode
696 WebInspector
.HeapSnapshotObjectNode = function(dataGrid
, snapshot
, edge
, parentObjectNode
)
698 WebInspector
.HeapSnapshotGenericObjectNode
.call(this, dataGrid
, edge
.node
);
699 this._referenceName
= edge
.name
;
700 this._referenceType
= edge
.type
;
701 this._edgeIndex
= edge
.edgeIndex
;
702 this._snapshot
= snapshot
;
704 this._parentObjectNode
= parentObjectNode
;
705 this._cycledWithAncestorGridNode
= this._findAncestorWithSameSnapshotNodeId();
706 if (!this._cycledWithAncestorGridNode
)
707 this.updateHasChildren();
709 var data
= this.data
;
711 data
["addedCount"] = "";
712 data
["removedCount"] = "";
713 data
["countDelta"] = "";
714 data
["addedSize"] = "";
715 data
["removedSize"] = "";
716 data
["sizeDelta"] = "";
719 WebInspector
.HeapSnapshotObjectNode
.prototype = {
722 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
724 retainersDataSource: function()
726 return {snapshot
: this._snapshot
, snapshotNodeIndex
: this.snapshotNodeIndex
};
731 * @return {!WebInspector.HeapSnapshotProviderProxy}
733 createProvider: function()
735 return this._snapshot
.createEdgesProvider(this.snapshotNodeIndex
);
738 _findAncestorWithSameSnapshotNodeId: function()
740 var ancestor
= this._parentObjectNode
;
742 if (ancestor
.snapshotNodeId
=== this.snapshotNodeId
)
744 ancestor
= ancestor
._parentObjectNode
;
750 * @param {!WebInspector.HeapSnapshotCommon.Edge} item
751 * @return {!WebInspector.HeapSnapshotObjectNode}
753 _createChildNode: function(item
)
755 return new WebInspector
.HeapSnapshotObjectNode(this._dataGrid
, this._snapshot
, item
, this);
759 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
762 _childHashForEntity: function(edge
)
764 return edge
.edgeIndex
;
768 * @param {!WebInspector.HeapSnapshotObjectNode} childNode
771 _childHashForNode: function(childNode
)
773 return childNode
._edgeIndex
;
777 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
779 comparator: function()
781 var sortAscending
= this._dataGrid
.isSortOrderAscending();
782 var sortColumnIdentifier
= this._dataGrid
.sortColumnIdentifier();
784 object
: ["!edgeName", sortAscending
, "retainedSize", false],
785 count
: ["!edgeName", true, "retainedSize", false],
786 shallowSize
: ["selfSize", sortAscending
, "!edgeName", true],
787 retainedSize
: ["retainedSize", sortAscending
, "!edgeName", true],
788 distance
: ["distance", sortAscending
, "_name", true]
789 }[sortColumnIdentifier
] || ["!edgeName", true, "retainedSize", false];
790 return WebInspector
.HeapSnapshotGridNode
.createComparator(sortFields
);
793 _prefixObjectCell: function(div
)
795 var name
= this._referenceName
|| "(empty)";
796 var nameClass
= "name";
797 switch (this._referenceType
) {
799 nameClass
= "object-value-number";
804 nameClass
= "object-value-null";
807 name
= "[" + name
+ "]";
811 if (this._cycledWithAncestorGridNode
)
812 div
.className
+= " cycled-ancessor-node";
814 var nameSpan
= createElement("span");
815 nameSpan
.className
= nameClass
;
816 nameSpan
.textContent
= name
;
817 div
.appendChild(nameSpan
);
819 var separatorSpan
= createElement("span");
820 separatorSpan
.className
= "grayed";
821 separatorSpan
.textContent
= this._edgeNodeSeparator();
822 div
.appendChild(separatorSpan
);
828 _edgeNodeSeparator: function()
833 __proto__
: WebInspector
.HeapSnapshotGenericObjectNode
.prototype
838 * @extends {WebInspector.HeapSnapshotObjectNode}
839 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
840 * @param {!WebInspector.HeapSnapshotProxy} snapshot
841 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
842 * @param {?WebInspector.HeapSnapshotRetainingObjectNode} parentRetainingObjectNode
844 WebInspector
.HeapSnapshotRetainingObjectNode = function(dataGrid
, snapshot
, edge
, parentRetainingObjectNode
)
846 WebInspector
.HeapSnapshotObjectNode
.call(this, dataGrid
, snapshot
, edge
, parentRetainingObjectNode
);
849 WebInspector
.HeapSnapshotRetainingObjectNode
.prototype = {
852 * @return {!WebInspector.HeapSnapshotProviderProxy}
854 createProvider: function()
856 return this._snapshot
.createRetainingEdgesProvider(this.snapshotNodeIndex
);
861 * @param {!WebInspector.HeapSnapshotCommon.Edge} item
862 * @return {!WebInspector.HeapSnapshotRetainingObjectNode}
864 _createChildNode: function(item
)
866 return new WebInspector
.HeapSnapshotRetainingObjectNode(this._dataGrid
, this._snapshot
, item
, this);
873 _edgeNodeSeparator: function()
880 this._expandRetainersChain(20);
884 * @param {number} maxExpandLevels
886 _expandRetainersChain: function(maxExpandLevels
)
889 * @this {!WebInspector.HeapSnapshotRetainingObjectNode}
891 function populateComplete()
893 this.removeEventListener(WebInspector
.HeapSnapshotGridNode
.Events
.PopulateComplete
, populateComplete
, this);
894 this._expandRetainersChain(maxExpandLevels
);
897 if (!this._populated
) {
898 this.addEventListener(WebInspector
.HeapSnapshotGridNode
.Events
.PopulateComplete
, populateComplete
, this);
902 WebInspector
.HeapSnapshotGenericObjectNode
.prototype.expand
.call(this);
903 if (--maxExpandLevels
> 0 && this.children
.length
> 0) {
904 var retainer
= this.children
[0];
905 if (retainer
._distance
> 1) {
906 retainer
._expandRetainersChain(maxExpandLevels
);
910 this._dataGrid
.dispatchEventToListeners(WebInspector
.HeapSnapshotRetainmentDataGrid
.Events
.ExpandRetainersComplete
);
913 __proto__
: WebInspector
.HeapSnapshotObjectNode
.prototype
918 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
919 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
920 * @param {!WebInspector.HeapSnapshotProxy} snapshot
921 * @param {!WebInspector.HeapSnapshotCommon.Node} node
922 * @param {boolean} isDeletedNode
924 WebInspector
.HeapSnapshotInstanceNode = function(dataGrid
, snapshot
, node
, isDeletedNode
)
926 WebInspector
.HeapSnapshotGenericObjectNode
.call(this, dataGrid
, node
);
927 this._baseSnapshotOrSnapshot
= snapshot
;
928 this._isDeletedNode
= isDeletedNode
;
929 this.updateHasChildren();
931 var data
= this.data
;
933 data
["countDelta"] = "";
934 data
["sizeDelta"] = "";
935 if (this._isDeletedNode
) {
936 data
["addedCount"] = "";
937 data
["addedSize"] = "";
938 data
["removedCount"] = "\u2022";
939 data
["removedSize"] = Number
.withThousandsSeparator(this._shallowSize
);
941 data
["addedCount"] = "\u2022";
942 data
["addedSize"] = Number
.withThousandsSeparator(this._shallowSize
);
943 data
["removedCount"] = "";
944 data
["removedSize"] = "";
948 WebInspector
.HeapSnapshotInstanceNode
.prototype = {
951 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
953 retainersDataSource: function()
955 return {snapshot
: this._baseSnapshotOrSnapshot
, snapshotNodeIndex
: this.snapshotNodeIndex
};
960 * @return {!WebInspector.HeapSnapshotProviderProxy}
962 createProvider: function()
964 return this._baseSnapshotOrSnapshot
.createEdgesProvider(this.snapshotNodeIndex
);
968 * @param {!WebInspector.HeapSnapshotCommon.Edge} item
969 * @return {!WebInspector.HeapSnapshotObjectNode}
971 _createChildNode: function(item
)
973 return new WebInspector
.HeapSnapshotObjectNode(this._dataGrid
, this._baseSnapshotOrSnapshot
, item
, null);
977 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
980 _childHashForEntity: function(edge
)
982 return edge
.edgeIndex
;
986 * @param {!WebInspector.HeapSnapshotObjectNode} childNode
989 _childHashForNode: function(childNode
)
991 return childNode
._edgeIndex
;
995 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
997 comparator: function()
999 var sortAscending
= this._dataGrid
.isSortOrderAscending();
1000 var sortColumnIdentifier
= this._dataGrid
.sortColumnIdentifier();
1002 object
: ["!edgeName", sortAscending
, "retainedSize", false],
1003 distance
: ["distance", sortAscending
, "retainedSize", false],
1004 count
: ["!edgeName", true, "retainedSize", false],
1005 addedSize
: ["selfSize", sortAscending
, "!edgeName", true],
1006 removedSize
: ["selfSize", sortAscending
, "!edgeName", true],
1007 shallowSize
: ["selfSize", sortAscending
, "!edgeName", true],
1008 retainedSize
: ["retainedSize", sortAscending
, "!edgeName", true]
1009 }[sortColumnIdentifier
] || ["!edgeName", true, "retainedSize", false];
1010 return WebInspector
.HeapSnapshotGridNode
.createComparator(sortFields
);
1013 __proto__
: WebInspector
.HeapSnapshotGenericObjectNode
.prototype
1018 * @param {!WebInspector.HeapSnapshotConstructorsDataGrid} dataGrid
1019 * @param {string} className
1020 * @param {!WebInspector.HeapSnapshotCommon.Aggregate} aggregate
1021 * @param {!WebInspector.HeapSnapshotCommon.NodeFilter} nodeFilter
1022 * @extends {WebInspector.HeapSnapshotGridNode}
1024 WebInspector
.HeapSnapshotConstructorNode = function(dataGrid
, className
, aggregate
, nodeFilter
)
1026 WebInspector
.HeapSnapshotGridNode
.call(this, dataGrid
, aggregate
.count
> 0);
1027 this._name
= className
;
1028 this._nodeFilter
= nodeFilter
;
1029 this._distance
= aggregate
.distance
;
1030 this._count
= aggregate
.count
;
1031 this._shallowSize
= aggregate
.self
;
1032 this._retainedSize
= aggregate
.maxRet
;
1034 var snapshot
= dataGrid
.snapshot
;
1035 var countPercent
= this._count
/ snapshot
.nodeCount
* 100.0;
1036 var retainedSizePercent
= this._retainedSize
/ snapshot
.totalSize
* 100.0;
1037 var shallowSizePercent
= this._shallowSize
/ snapshot
.totalSize
* 100.0;
1040 "object": className
,
1041 "count": Number
.withThousandsSeparator(this._count
),
1042 "distance": this._toUIDistance(this._distance
),
1043 "shallowSize": Number
.withThousandsSeparator(this._shallowSize
),
1044 "retainedSize": Number
.withThousandsSeparator(this._retainedSize
),
1045 "count-percent": this._toPercentString(countPercent
),
1046 "shallowSize-percent": this._toPercentString(shallowSizePercent
),
1047 "retainedSize-percent": this._toPercentString(retainedSizePercent
)
1051 WebInspector
.HeapSnapshotConstructorNode
.prototype = {
1054 * @return {!WebInspector.HeapSnapshotProviderProxy}
1056 createProvider: function()
1058 return this._dataGrid
.snapshot
.createNodesProviderForClass(this._name
, this._nodeFilter
)
1062 * @param {number} snapshotObjectId
1063 * @return {!Promise<!Array<!WebInspector.HeapSnapshotGridNode>>}
1065 populateNodeBySnapshotObjectId: function(snapshotObjectId
)
1068 * @this {WebInspector.HeapSnapshotConstructorNode}
1070 function didExpand()
1072 return this._provider().nodePosition(snapshotObjectId
).then(didGetNodePosition
.bind(this));
1076 * @this {WebInspector.HeapSnapshotConstructorNode}
1077 * @param {number} nodePosition
1078 * @return {!Promise<!Array<!WebInspector.HeapSnapshotGridNode>>}
1080 function didGetNodePosition(nodePosition
)
1082 if (nodePosition
=== -1) {
1084 return Promise
.resolve([]);
1087 * @param {function(!Array<!WebInspector.HeapSnapshotGridNode>)} fulfill
1088 * @this {WebInspector.HeapSnapshotConstructorNode}
1090 function action(fulfill
)
1092 this._populateChildren(nodePosition
, null, didPopulateChildren
.bind(this, nodePosition
, fulfill
));
1094 return new Promise(action
.bind(this));
1099 * @this {WebInspector.HeapSnapshotConstructorNode}
1100 * @param {number} nodePosition
1101 * @param {function(!Array<!WebInspector.HeapSnapshotGridNode>)} callback
1103 function didPopulateChildren(nodePosition
, callback
)
1105 var node
= /** @type {?WebInspector.HeapSnapshotGridNode} */ (this.childForPosition(nodePosition
));
1106 callback(node
? [this, node
] : []);
1109 this._dataGrid
.resetNameFilter();
1110 return this.expandWithoutPopulate().then(didExpand
.bind(this));
1114 * @param {string} filterValue
1117 filteredOut: function(filterValue
)
1119 return this._name
.toLowerCase().indexOf(filterValue
) === -1;
1124 * @param {string} columnIdentifier
1125 * @return {!Element}
1127 createCell: function(columnIdentifier
)
1129 var cell
= columnIdentifier
!== "object" ? this._createValueCell(columnIdentifier
) : WebInspector
.HeapSnapshotGridNode
.prototype.createCell
.call(this, columnIdentifier
);
1130 if (this._searchMatched
)
1131 cell
.classList
.add("highlight");
1136 * @param {!WebInspector.HeapSnapshotCommon.Node} item
1137 * @return {!WebInspector.HeapSnapshotInstanceNode}
1139 _createChildNode: function(item
)
1141 return new WebInspector
.HeapSnapshotInstanceNode(this._dataGrid
, this._dataGrid
.snapshot
, item
, false);
1145 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1147 comparator: function()
1149 var sortAscending
= this._dataGrid
.isSortOrderAscending();
1150 var sortColumnIdentifier
= this._dataGrid
.sortColumnIdentifier();
1152 object
: ["name", sortAscending
, "id", true],
1153 distance
: ["distance", sortAscending
, "retainedSize", false],
1154 count
: ["name", true, "id", true],
1155 shallowSize
: ["selfSize", sortAscending
, "id", true],
1156 retainedSize
: ["retainedSize", sortAscending
, "id", true]
1157 }[sortColumnIdentifier
];
1158 return WebInspector
.HeapSnapshotGridNode
.createComparator(sortFields
);
1162 * @param {!WebInspector.HeapSnapshotCommon.Node} node
1165 _childHashForEntity: function(node
)
1171 * @param {!WebInspector.HeapSnapshotInstanceNode} childNode
1174 _childHashForNode: function(childNode
)
1176 return childNode
.snapshotNodeId
;
1179 __proto__
: WebInspector
.HeapSnapshotGridNode
.prototype
1185 * @implements {WebInspector.HeapSnapshotGridNode.ChildrenProvider}
1186 * @param {!WebInspector.HeapSnapshotProviderProxy} addedNodesProvider
1187 * @param {!WebInspector.HeapSnapshotProviderProxy} deletedNodesProvider
1188 * @param {number} addedCount
1189 * @param {number} removedCount
1191 WebInspector
.HeapSnapshotDiffNodesProvider = function(addedNodesProvider
, deletedNodesProvider
, addedCount
, removedCount
)
1193 this._addedNodesProvider
= addedNodesProvider
;
1194 this._deletedNodesProvider
= deletedNodesProvider
;
1195 this._addedCount
= addedCount
;
1196 this._removedCount
= removedCount
;
1199 WebInspector
.HeapSnapshotDiffNodesProvider
.prototype = {
1205 this._addedNodesProvider
.dispose();
1206 this._deletedNodesProvider
.dispose();
1211 * @param {number} snapshotObjectId
1212 * @return {!Promise<number>}
1214 nodePosition: function(snapshotObjectId
)
1216 throw new Error("Unreachable");
1221 * @param {function(boolean)} callback
1223 isEmpty: function(callback
)
1230 * @param {number} beginPosition
1231 * @param {number} endPosition
1232 * @param {function(!WebInspector.HeapSnapshotCommon.ItemsRange)} callback
1234 serializeItemsRange: function(beginPosition
, endPosition
, callback
)
1237 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} items
1238 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1240 function didReceiveAllItems(items
)
1242 items
.totalLength
= this._addedCount
+ this._removedCount
;
1247 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} addedItems
1248 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
1249 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1251 function didReceiveDeletedItems(addedItems
, itemsRange
)
1253 var items
= itemsRange
.items
;
1254 if (!addedItems
.items
.length
)
1255 addedItems
.startPosition
= this._addedCount
+ itemsRange
.startPosition
;
1256 for (var i
= 0; i
< items
.length
; i
++) {
1257 items
[i
].isAddedNotRemoved
= false;
1258 addedItems
.items
.push(items
[i
]);
1260 addedItems
.endPosition
= this._addedCount
+ itemsRange
.endPosition
;
1261 didReceiveAllItems
.call(this, addedItems
);
1265 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
1266 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1268 function didReceiveAddedItems(itemsRange
)
1270 var items
= itemsRange
.items
;
1271 for (var i
= 0; i
< items
.length
; i
++)
1272 items
[i
].isAddedNotRemoved
= true;
1273 if (itemsRange
.endPosition
< endPosition
)
1274 return this._deletedNodesProvider
.serializeItemsRange(0, endPosition
- itemsRange
.endPosition
, didReceiveDeletedItems
.bind(this, itemsRange
));
1276 itemsRange
.totalLength
= this._addedCount
+ this._removedCount
;
1277 didReceiveAllItems
.call(this, itemsRange
);
1280 if (beginPosition
< this._addedCount
) {
1281 this._addedNodesProvider
.serializeItemsRange(beginPosition
, endPosition
, didReceiveAddedItems
.bind(this));
1283 var emptyRange
= new WebInspector
.HeapSnapshotCommon
.ItemsRange(0, 0, 0, []);
1284 this._deletedNodesProvider
.serializeItemsRange(beginPosition
- this._addedCount
, endPosition
- this._addedCount
, didReceiveDeletedItems
.bind(this, emptyRange
));
1290 * @param {!WebInspector.HeapSnapshotCommon.ComparatorConfig} comparator
1291 * @return {!Promise<?>}
1293 sortAndRewind: function(comparator
)
1296 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1297 * @return {!Promise<?>}
1299 function afterSort()
1301 return this._deletedNodesProvider
.sortAndRewind(comparator
);
1303 return this._addedNodesProvider
.sortAndRewind(comparator
).then(afterSort
.bind(this));
1309 * @param {!WebInspector.HeapSnapshotDiffDataGrid} dataGrid
1310 * @param {string} className
1311 * @param {!WebInspector.HeapSnapshotCommon.DiffForClass} diffForClass
1312 * @extends {WebInspector.HeapSnapshotGridNode}
1314 WebInspector
.HeapSnapshotDiffNode = function(dataGrid
, className
, diffForClass
)
1316 WebInspector
.HeapSnapshotGridNode
.call(this, dataGrid
, true);
1317 this._name
= className
;
1318 this._addedCount
= diffForClass
.addedCount
;
1319 this._removedCount
= diffForClass
.removedCount
;
1320 this._countDelta
= diffForClass
.countDelta
;
1321 this._addedSize
= diffForClass
.addedSize
;
1322 this._removedSize
= diffForClass
.removedSize
;
1323 this._sizeDelta
= diffForClass
.sizeDelta
;
1324 this._deletedIndexes
= diffForClass
.deletedIndexes
;
1326 "object": className
,
1327 "addedCount": Number
.withThousandsSeparator(this._addedCount
),
1328 "removedCount": Number
.withThousandsSeparator(this._removedCount
),
1329 "countDelta": this._signForDelta(this._countDelta
) + Number
.withThousandsSeparator(Math
.abs(this._countDelta
)),
1330 "addedSize": Number
.withThousandsSeparator(this._addedSize
),
1331 "removedSize": Number
.withThousandsSeparator(this._removedSize
),
1332 "sizeDelta": this._signForDelta(this._sizeDelta
) + Number
.withThousandsSeparator(Math
.abs(this._sizeDelta
))
1336 WebInspector
.HeapSnapshotDiffNode
.prototype = {
1339 * @return {!WebInspector.HeapSnapshotDiffNodesProvider}
1341 createProvider: function()
1343 var tree
= this._dataGrid
;
1344 return new WebInspector
.HeapSnapshotDiffNodesProvider(
1345 tree
.snapshot
.createAddedNodesProvider(tree
.baseSnapshot
.uid
, this._name
),
1346 tree
.baseSnapshot
.createDeletedNodesProvider(this._deletedIndexes
),
1348 this._removedCount
);
1353 * @param {string} columnIdentifier
1354 * @return {!Element}
1356 createCell: function(columnIdentifier
)
1358 var cell
= WebInspector
.HeapSnapshotGridNode
.prototype.createCell
.call(this, columnIdentifier
);
1359 if (columnIdentifier
!== "object")
1360 cell
.classList
.add("numeric-column");
1365 * @param {!WebInspector.HeapSnapshotCommon.Node} item
1366 * @return {!WebInspector.HeapSnapshotInstanceNode}
1368 _createChildNode: function(item
)
1370 if (item
.isAddedNotRemoved
)
1371 return new WebInspector
.HeapSnapshotInstanceNode(this._dataGrid
, this._dataGrid
.snapshot
, item
, false);
1373 return new WebInspector
.HeapSnapshotInstanceNode(this._dataGrid
, this._dataGrid
.baseSnapshot
, item
, true);
1377 * @param {!WebInspector.HeapSnapshotCommon.Node} node
1380 _childHashForEntity: function(node
)
1386 * @param {!WebInspector.HeapSnapshotInstanceNode} childNode
1389 _childHashForNode: function(childNode
)
1391 return childNode
.snapshotNodeId
;
1395 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1397 comparator: function()
1399 var sortAscending
= this._dataGrid
.isSortOrderAscending();
1400 var sortColumnIdentifier
= this._dataGrid
.sortColumnIdentifier();
1402 object
: ["name", sortAscending
, "id", true],
1403 addedCount
: ["name", true, "id", true],
1404 removedCount
: ["name", true, "id", true],
1405 countDelta
: ["name", true, "id", true],
1406 addedSize
: ["selfSize", sortAscending
, "id", true],
1407 removedSize
: ["selfSize", sortAscending
, "id", true],
1408 sizeDelta
: ["selfSize", sortAscending
, "id", true]
1409 }[sortColumnIdentifier
];
1410 return WebInspector
.HeapSnapshotGridNode
.createComparator(sortFields
);
1414 * @param {string} filterValue
1417 filteredOut: function(filterValue
)
1419 return this._name
.toLowerCase().indexOf(filterValue
) === -1;
1422 _signForDelta: function(delta
)
1429 return "\u2212"; // Math minus sign, same width as plus.
1432 __proto__
: WebInspector
.HeapSnapshotGridNode
.prototype
1438 * @extends {WebInspector.HeapSnapshotGridNode}
1439 * @param {!WebInspector.AllocationDataGrid} dataGrid
1440 * @param {!WebInspector.HeapSnapshotCommon.SerializedAllocationNode} data
1442 WebInspector
.AllocationGridNode = function(dataGrid
, data
)
1444 WebInspector
.HeapSnapshotGridNode
.call(this, dataGrid
, data
.hasChildren
);
1445 this._populated
= false;
1446 this._allocationNode
= data
;
1448 "liveCount": Number
.withThousandsSeparator(data
.liveCount
),
1449 "count": Number
.withThousandsSeparator(data
.count
),
1450 "liveSize": Number
.withThousandsSeparator(data
.liveSize
),
1451 "size": Number
.withThousandsSeparator(data
.size
),
1456 WebInspector
.AllocationGridNode
.prototype = {
1457 populate: function()
1459 if (this._populated
)
1461 this._populated
= true;
1462 this._dataGrid
.snapshot
.allocationNodeCallers(this._allocationNode
.id
, didReceiveCallers
.bind(this));
1465 * @param {!WebInspector.HeapSnapshotCommon.AllocationNodeCallers} callers
1466 * @this {WebInspector.AllocationGridNode}
1468 function didReceiveCallers(callers
)
1470 var callersChain
= callers
.nodesWithSingleCaller
;
1471 var parentNode
= this;
1472 var dataGrid
= /** @type {!WebInspector.AllocationDataGrid} */ (this._dataGrid
);
1473 for (var i
= 0; i
< callersChain
.length
; i
++) {
1474 var child
= new WebInspector
.AllocationGridNode(dataGrid
, callersChain
[i
]);
1475 dataGrid
.appendNode(parentNode
, child
);
1477 parentNode
._populated
= true;
1479 parentNode
.expand();
1482 var callersBranch
= callers
.branchingCallers
;
1483 callersBranch
.sort(this._dataGrid
._createComparator());
1484 for (var i
= 0; i
< callersBranch
.length
; i
++)
1485 dataGrid
.appendNode(parentNode
, new WebInspector
.AllocationGridNode(dataGrid
, callersBranch
[i
]));
1486 dataGrid
.updateVisibleNodes(true);
1495 WebInspector
.HeapSnapshotGridNode
.prototype.expand
.call(this);
1496 if (this.children
.length
=== 1)
1497 this.children
[0].expand();
1502 * @param {string} columnIdentifier
1503 * @return {!Element}
1505 createCell: function(columnIdentifier
)
1507 if (columnIdentifier
!== "name")
1508 return this._createValueCell(columnIdentifier
);
1510 var cell
= WebInspector
.HeapSnapshotGridNode
.prototype.createCell
.call(this, columnIdentifier
);
1511 var allocationNode
= this._allocationNode
;
1512 var target
= this._dataGrid
.target();
1513 if (allocationNode
.scriptId
) {
1514 var linkifier
= this._dataGrid
._linkifier
;
1515 var urlElement
= linkifier
.linkifyScriptLocation(target
, String(allocationNode
.scriptId
), allocationNode
.scriptName
, allocationNode
.line
- 1, allocationNode
.column
- 1, "profile-node-file");
1516 urlElement
.style
.maxWidth
= "75%";
1517 cell
.insertBefore(urlElement
, cell
.firstChild
);
1525 allocationNodeId: function()
1527 return this._allocationNode
.id
;
1530 __proto__
: WebInspector
.HeapSnapshotGridNode
.prototype