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 * @param {function(number)} callback
82 nodePosition: function(snapshotObjectId, callback) { },
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 * @param {function()} callback
100 sortAndRewind: function(comparator, callback) { }
104 WebInspector.HeapSnapshotGridNode.prototype = {
106 * @return {!WebInspector.HeapSnapshotGridNode.ChildrenProvider}
108 createProvider: function()
110 throw new Error("Not implemented.");
114 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
116 retainersDataSource: function()
122 * @return {!WebInspector.HeapSnapshotGridNode.ChildrenProvider}
124 _provider: function()
126 if (!this._providerObject)
127 this._providerObject = this.createProvider();
128 return this._providerObject;
132 * @param {string} columnIdentifier
135 createCell: function(columnIdentifier)
137 var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
138 if (this._searchMatched)
139 cell.classList.add("highlight");
148 WebInspector.DataGridNode.prototype.collapse.call(this);
149 this._dataGrid.updateVisibleNodes(true);
157 WebInspector.DataGridNode.prototype.expand.call(this);
158 this._dataGrid.updateVisibleNodes(true);
166 if (this._providerObject)
167 this._providerObject.dispose();
168 for (var node = this.children[0]; node; node = node.traverseNextNode(true, this, true))
173 _reachableFromWindow: false,
175 queryObjectContent: function(callback)
182 wasDetached: function()
184 this._dataGrid.nodeWasDetached(this);
188 * @param {number} num
191 _toPercentString: function(num)
193 return num.toFixed(0) + "\u2009%"; // \u2009 is a thin space.
197 * @param {number} distance
200 _toUIDistance: function(distance)
202 var baseSystemDistance = WebInspector.HeapSnapshotCommon.baseSystemDistance;
203 return distance >= 0 && distance < baseSystemDistance ? WebInspector.UIString("%d", distance) : WebInspector.UIString("\u2212");
207 * @return {!Array.<!WebInspector.DataGridNode>}
209 allChildren: function()
211 return this._dataGrid.allChildren(this);
215 * @param {number} index
217 removeChildByIndex: function(index)
219 this._dataGrid.removeChildByIndex(this, index);
223 * @param {number} nodePosition
224 * @return {?WebInspector.DataGridNode}
226 childForPosition: function(nodePosition)
228 var indexOfFirstChildInRange = 0;
229 for (var i = 0; i < this._retrievedChildrenRanges.length; i++) {
230 var range = this._retrievedChildrenRanges[i];
231 if (range.from <= nodePosition && nodePosition < range.to) {
232 var childIndex = indexOfFirstChildInRange + nodePosition - range.from;
233 return this.allChildren()[childIndex];
235 indexOfFirstChildInRange += range.to - range.from + 1;
241 * @param {string} columnIdentifier
244 _createValueCell: function(columnIdentifier)
246 var cell = document.createElement("td");
247 cell.className = "numeric-column";
248 if (this.dataGrid.snapshot.totalSize !== 0) {
249 var div = document.createElement("div");
250 var valueSpan = document.createElement("span");
251 valueSpan.textContent = this.data[columnIdentifier];
252 div.appendChild(valueSpan);
253 var percentColumn = columnIdentifier + "-percent";
254 if (percentColumn in this.data) {
255 var percentSpan = document.createElement("span");
256 percentSpan.className = "percent-column";
257 percentSpan.textContent = this.data[percentColumn];
258 div.appendChild(percentSpan);
259 div.classList.add("profile-multiple-values");
261 cell.appendChild(div);
266 populate: function(event)
270 this._populated = true;
273 * @this {WebInspector.HeapSnapshotGridNode}
277 this._populateChildren();
279 this._provider().sortAndRewind(this.comparator(), sorted.bind(this));
282 expandWithoutPopulate: function(callback)
284 // Make sure default populate won't take action.
285 this._populated = true;
287 this._provider().sortAndRewind(this.comparator(), callback);
291 * @param {?number=} fromPosition
292 * @param {?number=} toPosition
293 * @param {function()=} afterPopulate
295 _populateChildren: function(fromPosition, toPosition, afterPopulate)
297 fromPosition = fromPosition || 0;
298 toPosition = toPosition || fromPosition + this._dataGrid.defaultPopulateCount();
299 var firstNotSerializedPosition = fromPosition;
302 * @this {WebInspector.HeapSnapshotGridNode}
304 function serializeNextChunk()
306 if (firstNotSerializedPosition >= toPosition)
308 var end = Math.min(firstNotSerializedPosition + this._dataGrid.defaultPopulateCount(), toPosition);
309 this._provider().serializeItemsRange(firstNotSerializedPosition, end, childrenRetrieved.bind(this));
310 firstNotSerializedPosition = end;
314 * @this {WebInspector.HeapSnapshotGridNode}
316 function insertRetrievedChild(item, insertionIndex)
318 if (this._savedChildren) {
319 var hash = this._childHashForEntity(item);
320 if (hash in this._savedChildren) {
321 this._dataGrid.insertChild(this, this._savedChildren[hash], insertionIndex);
325 this._dataGrid.insertChild(this, this._createChildNode(item), insertionIndex);
329 * @this {WebInspector.HeapSnapshotGridNode}
331 function insertShowMoreButton(from, to, insertionIndex)
333 var button = new WebInspector.ShowMoreDataGridNode(this._populateChildren.bind(this), from, to, this._dataGrid.defaultPopulateCount());
334 this._dataGrid.insertChild(this, button, insertionIndex);
338 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
339 * @this {WebInspector.HeapSnapshotGridNode}
341 function childrenRetrieved(itemsRange)
344 var itemPosition = itemsRange.startPosition;
345 var items = itemsRange.items;
346 var insertionIndex = 0;
348 if (!this._retrievedChildrenRanges.length) {
349 if (itemsRange.startPosition > 0) {
350 this._retrievedChildrenRanges.push({from: 0, to: 0});
351 insertShowMoreButton.call(this, 0, itemsRange.startPosition, insertionIndex++);
353 this._retrievedChildrenRanges.push({from: itemsRange.startPosition, to: itemsRange.endPosition});
354 for (var i = 0, l = items.length; i < l; ++i)
355 insertRetrievedChild.call(this, items[i], insertionIndex++);
356 if (itemsRange.endPosition < itemsRange.totalLength)
357 insertShowMoreButton.call(this, itemsRange.endPosition, itemsRange.totalLength, insertionIndex++);
362 while (rangeIndex < this._retrievedChildrenRanges.length) {
363 range = this._retrievedChildrenRanges[rangeIndex];
364 if (range.to >= itemPosition) {
368 insertionIndex += range.to - range.from;
369 // Skip the button if there is one.
370 if (range.to < itemsRange.totalLength)
375 if (!found || itemsRange.startPosition < range.from) {
376 // Update previous button.
377 this.allChildren()[insertionIndex - 1].setEndPosition(itemsRange.startPosition);
378 insertShowMoreButton.call(this, itemsRange.startPosition, found ? range.from : itemsRange.totalLength, insertionIndex);
379 range = {from: itemsRange.startPosition, to: itemsRange.startPosition};
381 rangeIndex = this._retrievedChildrenRanges.length;
382 this._retrievedChildrenRanges.splice(rangeIndex, 0, range);
384 insertionIndex += itemPosition - range.from;
386 // At this point insertionIndex is always an index before button or between nodes.
387 // Also it is always true here that range.from <= itemPosition <= range.to
389 // Stretch the range right bound to include all new items.
390 while (range.to < itemsRange.endPosition) {
391 // Skip already added nodes.
392 var skipCount = range.to - itemPosition;
393 insertionIndex += skipCount;
394 itemIndex += skipCount;
395 itemPosition = range.to;
397 // We're at the position before button: ...<?node>x<button>
398 var nextRange = this._retrievedChildrenRanges[rangeIndex + 1];
399 var newEndOfRange = nextRange ? nextRange.from : itemsRange.totalLength;
400 if (newEndOfRange > itemsRange.endPosition)
401 newEndOfRange = itemsRange.endPosition;
402 while (itemPosition < newEndOfRange) {
403 insertRetrievedChild.call(this, items[itemIndex++], insertionIndex++);
406 // Merge with the next range.
407 if (nextRange && newEndOfRange === nextRange.from) {
408 range.to = nextRange.to;
409 // Remove "show next" button if there is one.
410 this.removeChildByIndex(insertionIndex);
411 this._retrievedChildrenRanges.splice(rangeIndex + 1, 1);
413 range.to = newEndOfRange;
414 // Remove or update next button.
415 if (newEndOfRange === itemsRange.totalLength)
416 this.removeChildByIndex(insertionIndex);
418 this.allChildren()[insertionIndex].setStartPosition(itemsRange.endPosition);
424 this._instanceCount += items.length;
425 if (firstNotSerializedPosition < toPosition) {
426 serializeNextChunk.call(this);
431 this._dataGrid.updateVisibleNodes(true);
434 this.dispatchEventToListeners(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete);
436 serializeNextChunk.call(this);
439 _saveChildren: function()
441 this._savedChildren = null;
442 var children = this.allChildren();
443 for (var i = 0, l = children.length; i < l; ++i) {
444 var child = children[i];
447 if (!this._savedChildren)
448 this._savedChildren = {};
449 this._savedChildren[this._childHashForNode(child)] = child;
455 this._dataGrid.recursiveSortingEnter();
458 * @this {WebInspector.HeapSnapshotGridNode}
462 this._saveChildren();
463 this._dataGrid.removeAllChildren(this);
464 this._retrievedChildrenRanges = [];
467 * @this {WebInspector.HeapSnapshotGridNode}
469 function afterPopulate()
471 var children = this.allChildren();
472 for (var i = 0, l = children.length; i < l; ++i) {
473 var child = children[i];
477 this._dataGrid.recursiveSortingLeave();
479 var instanceCount = this._instanceCount;
480 this._instanceCount = 0;
481 this._populateChildren(0, instanceCount, afterPopulate.bind(this));
484 this._provider().sortAndRewind(this.comparator(), afterSort.bind(this));
487 __proto__: WebInspector.DataGridNode.prototype
493 * @extends {WebInspector.HeapSnapshotGridNode}
494 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
495 * @param {!WebInspector.HeapSnapshotCommon.Node} node
497 WebInspector.HeapSnapshotGenericObjectNode = function(dataGrid, node)
499 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, false);
500 // node is null for DataGrid root nodes.
503 this._name = node.name;
504 this._type = node.type;
505 this._distance = node.distance;
506 this._shallowSize = node.selfSize;
507 this._retainedSize = node.retainedSize;
508 this.snapshotNodeId = node.id;
509 this.snapshotNodeIndex = node.nodeIndex;
510 if (this._type === "string")
511 this._reachableFromWindow = true;
512 else if (this._type === "object" && this._name.startsWith("Window")) {
513 this._name = this.shortenWindowURL(this._name, false);
514 this._reachableFromWindow = true;
515 } else if (node.canBeQueried)
516 this._reachableFromWindow = true;
517 if (node.detachedDOMTreeNode)
518 this.detachedDOMTreeNode = true;
520 var snapshot = dataGrid.snapshot;
521 var shallowSizePercent = this._shallowSize / snapshot.totalSize * 100.0;
522 var retainedSizePercent = this._retainedSize / snapshot.totalSize * 100.0;
524 "distance": this._toUIDistance(this._distance),
525 "shallowSize": Number.withThousandsSeparator(this._shallowSize),
526 "retainedSize": Number.withThousandsSeparator(this._retainedSize),
527 "shallowSize-percent": this._toPercentString(shallowSizePercent),
528 "retainedSize-percent": this._toPercentString(retainedSizePercent)
532 WebInspector.HeapSnapshotGenericObjectNode.prototype = {
534 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
536 retainersDataSource: function()
538 return {snapshot: this._dataGrid.snapshot, snapshotNodeIndex: this.snapshotNodeIndex};
542 * @param {string} columnIdentifier
545 createCell: function(columnIdentifier)
547 var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : this._createObjectCell();
548 if (this._searchMatched)
549 cell.classList.add("highlight");
556 _createObjectCell: function()
558 var value = this._name;
559 var valueStyle = "object";
560 switch (this._type) {
561 case "concatenated string":
563 value = "\"" + value + "\"";
564 valueStyle = "string";
567 value = "/" + value + "/";
568 valueStyle = "string";
571 value = "function" + (value ? " " : "") + value + "()";
572 valueStyle = "function";
575 valueStyle = "number";
587 if (this._reachableFromWindow)
588 valueStyle += " highlight";
589 if (value === "Object")
591 if (this.detachedDOMTreeNode)
592 valueStyle += " detached-dom-tree-node";
593 return this._createObjectCellWithValue(valueStyle, value);
596 _createObjectCellWithValue: function(valueStyle, value)
598 var cell = document.createElement("td");
599 cell.className = "object-column";
600 var div = document.createElement("div");
601 div.className = "source-code event-properties";
602 div.style.overflow = "visible";
604 this._prefixObjectCell(div);
606 var valueSpan = document.createElement("span");
607 valueSpan.className = "value console-formatted-" + valueStyle;
608 valueSpan.textContent = value;
609 div.appendChild(valueSpan);
611 var idSpan = document.createElement("span");
612 idSpan.className = "console-formatted-id";
613 idSpan.textContent = " @" + this.snapshotNodeId;
614 div.appendChild(idSpan);
616 cell.appendChild(div);
617 cell.classList.add("disclosure");
619 cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px");
620 cell.heapSnapshotNode = this;
624 _prefixObjectCell: function(div)
629 * @param {!WebInspector.Target} target
630 * @param {!function(!WebInspector.RemoteObject)} callback
631 * @param {string} objectGroupName
633 queryObjectContent: function(target, callback, objectGroupName)
636 * @param {?Protocol.Error} error
637 * @param {!RuntimeAgent.RemoteObject} object
639 function formatResult(error, object)
641 if (!error && object.type)
642 callback(target.runtimeModel.createRemoteObject(object));
644 callback(target.runtimeModel.createRemoteObjectFromPrimitiveValue(WebInspector.UIString("Preview is not available")));
647 if (this._type === "string")
648 callback(target.runtimeModel.createRemoteObjectFromPrimitiveValue(this._name));
650 target.heapProfilerAgent().getObjectByHeapObjectId(String(this.snapshotNodeId), objectGroupName, formatResult);
653 updateHasChildren: function()
656 * @this {WebInspector.HeapSnapshotGenericObjectNode}
658 function isEmptyCallback(isEmpty)
660 this.hasChildren = !isEmpty;
662 this._provider().isEmpty(isEmptyCallback.bind(this));
666 * @param {string} fullName
667 * @param {boolean} hasObjectId
670 shortenWindowURL: function(fullName, hasObjectId)
672 var startPos = fullName.indexOf("/");
673 var endPos = hasObjectId ? fullName.indexOf("@") : fullName.length;
674 if (startPos !== -1 && endPos !== -1) {
675 var fullURL = fullName.substring(startPos + 1, endPos).trimLeft();
676 var url = fullURL.trimURL();
678 url = url.trimMiddle(40);
679 return fullName.substr(0, startPos + 2) + url + fullName.substr(endPos);
684 __proto__: WebInspector.HeapSnapshotGridNode.prototype
689 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
690 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
691 * @param {!WebInspector.HeapSnapshotProxy} snapshot
692 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
693 * @param {?WebInspector.HeapSnapshotObjectNode} parentObjectNode
695 WebInspector.HeapSnapshotObjectNode = function(dataGrid, snapshot, edge, parentObjectNode)
697 WebInspector.HeapSnapshotGenericObjectNode.call(this, dataGrid, edge.node);
698 this._referenceName = edge.name;
699 this._referenceType = edge.type;
700 this._edgeIndex = edge.edgeIndex;
701 this._snapshot = snapshot;
703 this._parentObjectNode = parentObjectNode;
704 this._cycledWithAncestorGridNode = this._findAncestorWithSameSnapshotNodeId();
705 if (!this._cycledWithAncestorGridNode)
706 this.updateHasChildren();
708 var data = this.data;
710 data["addedCount"] = "";
711 data["removedCount"] = "";
712 data["countDelta"] = "";
713 data["addedSize"] = "";
714 data["removedSize"] = "";
715 data["sizeDelta"] = "";
718 WebInspector.HeapSnapshotObjectNode.prototype = {
720 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
722 retainersDataSource: function()
724 return {snapshot: this._snapshot, snapshotNodeIndex: this.snapshotNodeIndex};
728 * @return {!WebInspector.HeapSnapshotProviderProxy}
730 createProvider: function()
732 return this._snapshot.createEdgesProvider(this.snapshotNodeIndex);
735 _findAncestorWithSameSnapshotNodeId: function()
737 var ancestor = this._parentObjectNode;
739 if (ancestor.snapshotNodeId === this.snapshotNodeId)
741 ancestor = ancestor._parentObjectNode;
747 * @param {!WebInspector.HeapSnapshotCommon.Edge} item
748 * @return {!WebInspector.HeapSnapshotObjectNode}
750 _createChildNode: function(item)
752 return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._snapshot, item, this);
756 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
759 _childHashForEntity: function(edge)
761 return edge.edgeIndex;
765 * @param {!WebInspector.HeapSnapshotObjectNode} childNode
768 _childHashForNode: function(childNode)
770 return childNode._edgeIndex;
774 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
776 comparator: function()
778 var sortAscending = this._dataGrid.isSortOrderAscending();
779 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
781 object: ["!edgeName", sortAscending, "retainedSize", false],
782 count: ["!edgeName", true, "retainedSize", false],
783 shallowSize: ["selfSize", sortAscending, "!edgeName", true],
784 retainedSize: ["retainedSize", sortAscending, "!edgeName", true],
785 distance: ["distance", sortAscending, "_name", true]
786 }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
787 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
790 _prefixObjectCell: function(div)
792 var name = this._referenceName;
793 if (name === "") name = "(empty)";
794 var nameClass = "name";
795 switch (this._referenceType) {
797 nameClass = "console-formatted-number";
802 nameClass = "console-formatted-null";
805 name = "[" + name + "]";
809 if (this._cycledWithAncestorGridNode)
810 div.className += " cycled-ancessor-node";
812 var nameSpan = document.createElement("span");
813 nameSpan.className = nameClass;
814 nameSpan.textContent = name;
815 div.appendChild(nameSpan);
817 var separatorSpan = document.createElement("span");
818 separatorSpan.className = "grayed";
819 separatorSpan.textContent = this._edgeNodeSeparator();
820 div.appendChild(separatorSpan);
826 _edgeNodeSeparator: function()
831 __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
836 * @extends {WebInspector.HeapSnapshotObjectNode}
837 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
838 * @param {!WebInspector.HeapSnapshotProxy} snapshot
839 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
840 * @param {?WebInspector.HeapSnapshotRetainingObjectNode} parentRetainingObjectNode
842 WebInspector.HeapSnapshotRetainingObjectNode = function(dataGrid, snapshot, edge, parentRetainingObjectNode)
844 WebInspector.HeapSnapshotObjectNode.call(this, dataGrid, snapshot, edge, parentRetainingObjectNode);
847 WebInspector.HeapSnapshotRetainingObjectNode.prototype = {
849 * @return {!WebInspector.HeapSnapshotProviderProxy}
851 createProvider: function()
853 return this._snapshot.createRetainingEdgesProvider(this.snapshotNodeIndex);
857 * @param {!WebInspector.HeapSnapshotCommon.Edge} item
858 * @return {!WebInspector.HeapSnapshotRetainingObjectNode}
860 _createChildNode: function(item)
862 return new WebInspector.HeapSnapshotRetainingObjectNode(this._dataGrid, this._snapshot, item, this);
868 _edgeNodeSeparator: function()
875 this._expandRetainersChain(20);
879 * @param {number} maxExpandLevels
881 _expandRetainersChain: function(maxExpandLevels)
884 * @this {!WebInspector.HeapSnapshotRetainingObjectNode}
886 function populateComplete()
888 this.removeEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
889 this._expandRetainersChain(maxExpandLevels);
892 if (!this._populated) {
893 this.addEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
897 WebInspector.HeapSnapshotGenericObjectNode.prototype.expand.call(this);
898 if (--maxExpandLevels > 0 && this.children.length > 0) {
899 var retainer = this.children[0];
900 if (retainer._distance > 1) {
901 retainer._expandRetainersChain(maxExpandLevels);
905 this._dataGrid.dispatchEventToListeners(WebInspector.HeapSnapshotRetainmentDataGrid.Events.ExpandRetainersComplete);
908 __proto__: WebInspector.HeapSnapshotObjectNode.prototype
913 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
914 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
915 * @param {!WebInspector.HeapSnapshotProxy} snapshot
916 * @param {!WebInspector.HeapSnapshotCommon.Node} node
917 * @param {boolean} isDeletedNode
919 WebInspector.HeapSnapshotInstanceNode = function(dataGrid, snapshot, node, isDeletedNode)
921 WebInspector.HeapSnapshotGenericObjectNode.call(this, dataGrid, node);
922 this._baseSnapshotOrSnapshot = snapshot;
923 this._isDeletedNode = isDeletedNode;
924 this.updateHasChildren();
926 var data = this.data;
928 data["countDelta"] = "";
929 data["sizeDelta"] = "";
930 if (this._isDeletedNode) {
931 data["addedCount"] = "";
932 data["addedSize"] = "";
933 data["removedCount"] = "\u2022";
934 data["removedSize"] = Number.withThousandsSeparator(this._shallowSize);
936 data["addedCount"] = "\u2022";
937 data["addedSize"] = Number.withThousandsSeparator(this._shallowSize);
938 data["removedCount"] = "";
939 data["removedSize"] = "";
943 WebInspector.HeapSnapshotInstanceNode.prototype = {
945 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
947 retainersDataSource: function()
949 return {snapshot: this._baseSnapshotOrSnapshot, snapshotNodeIndex: this.snapshotNodeIndex};
953 * @return {!WebInspector.HeapSnapshotProviderProxy}
955 createProvider: function()
957 return this._baseSnapshotOrSnapshot.createEdgesProvider(this.snapshotNodeIndex);
961 * @param {!WebInspector.HeapSnapshotCommon.Edge} item
962 * @return {!WebInspector.HeapSnapshotObjectNode}
964 _createChildNode: function(item)
966 return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._baseSnapshotOrSnapshot, item, null);
970 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
973 _childHashForEntity: function(edge)
975 return edge.edgeIndex;
979 * @param {!WebInspector.HeapSnapshotObjectNode} childNode
982 _childHashForNode: function(childNode)
984 return childNode._edgeIndex;
988 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
990 comparator: function()
992 var sortAscending = this._dataGrid.isSortOrderAscending();
993 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
995 object: ["!edgeName", sortAscending, "retainedSize", false],
996 distance: ["distance", sortAscending, "retainedSize", false],
997 count: ["!edgeName", true, "retainedSize", false],
998 addedSize: ["selfSize", sortAscending, "!edgeName", true],
999 removedSize: ["selfSize", sortAscending, "!edgeName", true],
1000 shallowSize: ["selfSize", sortAscending, "!edgeName", true],
1001 retainedSize: ["retainedSize", sortAscending, "!edgeName", true]
1002 }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
1003 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1006 __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
1011 * @param {!WebInspector.HeapSnapshotConstructorsDataGrid} dataGrid
1012 * @param {string} className
1013 * @param {!WebInspector.HeapSnapshotCommon.Aggregate} aggregate
1014 * @param {!WebInspector.HeapSnapshotCommon.NodeFilter} nodeFilter
1015 * @extends {WebInspector.HeapSnapshotGridNode}
1017 WebInspector.HeapSnapshotConstructorNode = function(dataGrid, className, aggregate, nodeFilter)
1019 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, aggregate.count > 0);
1020 this._name = className;
1021 this._nodeFilter = nodeFilter;
1022 this._distance = aggregate.distance;
1023 this._count = aggregate.count;
1024 this._shallowSize = aggregate.self;
1025 this._retainedSize = aggregate.maxRet;
1027 var snapshot = dataGrid.snapshot;
1028 var countPercent = this._count / snapshot.nodeCount * 100.0;
1029 var retainedSizePercent = this._retainedSize / snapshot.totalSize * 100.0;
1030 var shallowSizePercent = this._shallowSize / snapshot.totalSize * 100.0;
1033 "object": className,
1034 "count": Number.withThousandsSeparator(this._count),
1035 "distance": this._toUIDistance(this._distance),
1036 "shallowSize": Number.withThousandsSeparator(this._shallowSize),
1037 "retainedSize": Number.withThousandsSeparator(this._retainedSize),
1038 "count-percent": this._toPercentString(countPercent),
1039 "shallowSize-percent": this._toPercentString(shallowSizePercent),
1040 "retainedSize-percent": this._toPercentString(retainedSizePercent)
1044 WebInspector.HeapSnapshotConstructorNode.prototype = {
1047 * @return {!WebInspector.HeapSnapshotProviderProxy}
1049 createProvider: function()
1051 return this._dataGrid.snapshot.createNodesProviderForClass(this._name, this._nodeFilter)
1055 * @param {number} snapshotObjectId
1056 * @param {function(boolean)} callback
1058 revealNodeBySnapshotObjectId: function(snapshotObjectId, callback)
1061 * @this {WebInspector.HeapSnapshotConstructorNode}
1063 function didExpand()
1065 this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
1069 * @this {WebInspector.HeapSnapshotConstructorNode}
1070 * @param {number} nodePosition
1072 function didGetNodePosition(nodePosition)
1074 if (nodePosition === -1) {
1078 this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
1083 * @this {WebInspector.HeapSnapshotConstructorNode}
1084 * @param {number} nodePosition
1086 function didPopulateChildren(nodePosition)
1088 var child = this.childForPosition(nodePosition);
1090 this._dataGrid.revealTreeNode([this, child]);
1091 this._dataGrid.highlightNode(/** @type {!WebInspector.HeapSnapshotGridNode} */ (child));
1096 this._dataGrid.resetNameFilter();
1097 this.expandWithoutPopulate(didExpand.bind(this));
1101 * @param {string} filterValue
1104 filteredOut: function(filterValue)
1106 return this._name.toLowerCase().indexOf(filterValue) === -1;
1110 * @param {string} columnIdentifier
1111 * @return {!Element}
1113 createCell: function(columnIdentifier)
1115 var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
1116 if (this._searchMatched)
1117 cell.classList.add("highlight");
1122 * @param {!WebInspector.HeapSnapshotCommon.Node} item
1123 * @return {!WebInspector.HeapSnapshotInstanceNode}
1125 _createChildNode: function(item)
1127 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.snapshot, item, false);
1131 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1133 comparator: function()
1135 var sortAscending = this._dataGrid.isSortOrderAscending();
1136 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
1138 object: ["id", sortAscending, "retainedSize", false],
1139 distance: ["distance", sortAscending, "retainedSize", false],
1140 count: ["id", true, "retainedSize", false],
1141 shallowSize: ["selfSize", sortAscending, "id", true],
1142 retainedSize: ["retainedSize", sortAscending, "id", true]
1143 }[sortColumnIdentifier];
1144 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1148 * @param {!WebInspector.HeapSnapshotCommon.Node} node
1151 _childHashForEntity: function(node)
1157 * @param {!WebInspector.HeapSnapshotInstanceNode} childNode
1160 _childHashForNode: function(childNode)
1162 return childNode.snapshotNodeId;
1165 __proto__: WebInspector.HeapSnapshotGridNode.prototype
1171 * @implements {WebInspector.HeapSnapshotGridNode.ChildrenProvider}
1172 * @param {!WebInspector.HeapSnapshotProviderProxy} addedNodesProvider
1173 * @param {!WebInspector.HeapSnapshotProviderProxy} deletedNodesProvider
1174 * @param {number} addedCount
1175 * @param {number} removedCount
1177 WebInspector.HeapSnapshotDiffNodesProvider = function(addedNodesProvider, deletedNodesProvider, addedCount, removedCount)
1179 this._addedNodesProvider = addedNodesProvider;
1180 this._deletedNodesProvider = deletedNodesProvider;
1181 this._addedCount = addedCount;
1182 this._removedCount = removedCount;
1185 WebInspector.HeapSnapshotDiffNodesProvider.prototype = {
1188 this._addedNodesProvider.dispose();
1189 this._deletedNodesProvider.dispose();
1194 * @param {number} snapshotObjectId
1195 * @param {function(number)} callback
1197 nodePosition: function(snapshotObjectId, callback)
1199 throw new Error("Unreachable");
1203 * @param {function(boolean)} callback
1205 isEmpty: function(callback)
1211 * @param {number} beginPosition
1212 * @param {number} endPosition
1213 * @param {!function(!WebInspector.HeapSnapshotCommon.ItemsRange)} callback
1215 serializeItemsRange: function(beginPosition, endPosition, callback)
1218 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} items
1219 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1221 function didReceiveAllItems(items)
1223 items.totalLength = this._addedCount + this._removedCount;
1228 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} addedItems
1229 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
1230 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1232 function didReceiveDeletedItems(addedItems, itemsRange)
1234 var items = itemsRange.items;
1235 if (!addedItems.items.length)
1236 addedItems.startPosition = this._addedCount + itemsRange.startPosition;
1237 for (var i = 0; i < items.length; i++) {
1238 items[i].isAddedNotRemoved = false;
1239 addedItems.items.push(items[i]);
1241 addedItems.endPosition = this._addedCount + itemsRange.endPosition;
1242 didReceiveAllItems.call(this, addedItems);
1246 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
1247 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1249 function didReceiveAddedItems(itemsRange)
1251 var items = itemsRange.items;
1252 for (var i = 0; i < items.length; i++)
1253 items[i].isAddedNotRemoved = true;
1254 if (itemsRange.endPosition < endPosition)
1255 return this._deletedNodesProvider.serializeItemsRange(0, endPosition - itemsRange.endPosition, didReceiveDeletedItems.bind(this, itemsRange));
1257 itemsRange.totalLength = this._addedCount + this._removedCount;
1258 didReceiveAllItems.call(this, itemsRange);
1261 if (beginPosition < this._addedCount) {
1262 this._addedNodesProvider.serializeItemsRange(beginPosition, endPosition, didReceiveAddedItems.bind(this));
1264 var emptyRange = new WebInspector.HeapSnapshotCommon.ItemsRange(0, 0, 0, []);
1265 this._deletedNodesProvider.serializeItemsRange(beginPosition - this._addedCount, endPosition - this._addedCount, didReceiveDeletedItems.bind(this, emptyRange));
1270 * @param {!WebInspector.HeapSnapshotCommon.ComparatorConfig} comparator
1271 * @param {function()} callback
1273 sortAndRewind: function(comparator, callback)
1276 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1278 function afterSort()
1280 this._deletedNodesProvider.sortAndRewind(comparator, callback);
1282 this._addedNodesProvider.sortAndRewind(comparator, afterSort.bind(this));
1288 * @param {!WebInspector.HeapSnapshotDiffDataGrid} dataGrid
1289 * @param {string} className
1290 * @param {!WebInspector.HeapSnapshotCommon.DiffForClass} diffForClass
1291 * @extends {WebInspector.HeapSnapshotGridNode}
1293 WebInspector.HeapSnapshotDiffNode = function(dataGrid, className, diffForClass)
1295 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, true);
1296 this._name = className;
1297 this._addedCount = diffForClass.addedCount;
1298 this._removedCount = diffForClass.removedCount;
1299 this._countDelta = diffForClass.countDelta;
1300 this._addedSize = diffForClass.addedSize;
1301 this._removedSize = diffForClass.removedSize;
1302 this._sizeDelta = diffForClass.sizeDelta;
1303 this._deletedIndexes = diffForClass.deletedIndexes;
1305 "object": className,
1306 "addedCount": Number.withThousandsSeparator(this._addedCount),
1307 "removedCount": Number.withThousandsSeparator(this._removedCount),
1308 "countDelta": this._signForDelta(this._countDelta) + Number.withThousandsSeparator(Math.abs(this._countDelta)),
1309 "addedSize": Number.withThousandsSeparator(this._addedSize),
1310 "removedSize": Number.withThousandsSeparator(this._removedSize),
1311 "sizeDelta": this._signForDelta(this._sizeDelta) + Number.withThousandsSeparator(Math.abs(this._sizeDelta))
1315 WebInspector.HeapSnapshotDiffNode.prototype = {
1318 * @return {!WebInspector.HeapSnapshotDiffNodesProvider}
1320 createProvider: function()
1322 var tree = this._dataGrid;
1323 return new WebInspector.HeapSnapshotDiffNodesProvider(
1324 tree.snapshot.createAddedNodesProvider(tree.baseSnapshot.uid, this._name),
1325 tree.baseSnapshot.createDeletedNodesProvider(this._deletedIndexes),
1327 this._removedCount);
1331 * @param {string} columnIdentifier
1332 * @return {!Element}
1334 createCell: function(columnIdentifier)
1336 var cell = WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
1337 if (columnIdentifier !== "object")
1338 cell.classList.add("numeric-column");
1343 * @param {!WebInspector.HeapSnapshotCommon.Node} item
1344 * @return {!WebInspector.HeapSnapshotInstanceNode}
1346 _createChildNode: function(item)
1348 if (item.isAddedNotRemoved)
1349 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.snapshot, item, false);
1351 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.baseSnapshot, item, true);
1355 * @param {!WebInspector.HeapSnapshotCommon.Node} node
1358 _childHashForEntity: function(node)
1364 * @param {!WebInspector.HeapSnapshotInstanceNode} childNode
1367 _childHashForNode: function(childNode)
1369 return childNode.snapshotNodeId;
1373 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1375 comparator: function()
1377 var sortAscending = this._dataGrid.isSortOrderAscending();
1378 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
1380 object: ["id", sortAscending, "selfSize", false],
1381 addedCount: ["selfSize", sortAscending, "id", true],
1382 removedCount: ["selfSize", sortAscending, "id", true],
1383 countDelta: ["selfSize", sortAscending, "id", true],
1384 addedSize: ["selfSize", sortAscending, "id", true],
1385 removedSize: ["selfSize", sortAscending, "id", true],
1386 sizeDelta: ["selfSize", sortAscending, "id", true]
1387 }[sortColumnIdentifier];
1388 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1392 * @param {string} filterValue
1395 filteredOut: function(filterValue)
1397 return this._name.toLowerCase().indexOf(filterValue) === -1;
1400 _signForDelta: function(delta)
1407 return "\u2212"; // Math minus sign, same width as plus.
1410 __proto__: WebInspector.HeapSnapshotGridNode.prototype
1416 * @extends {WebInspector.HeapSnapshotGridNode}
1417 * @param {!WebInspector.AllocationDataGrid} dataGrid
1418 * @param {!WebInspector.HeapSnapshotCommon.SerializedAllocationNode} data
1420 WebInspector.AllocationGridNode = function(dataGrid, data)
1422 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, data.hasChildren);
1423 this._populated = false;
1424 this._allocationNode = data;
1426 "liveCount": Number.withThousandsSeparator(data.liveCount),
1427 "count": Number.withThousandsSeparator(data.count),
1428 "liveSize": Number.withThousandsSeparator(data.liveSize),
1429 "size": Number.withThousandsSeparator(data.size),
1434 WebInspector.AllocationGridNode.prototype = {
1435 populate: function()
1437 if (this._populated)
1439 this._populated = true;
1440 this._dataGrid.snapshot.allocationNodeCallers(this._allocationNode.id, didReceiveCallers.bind(this));
1443 * @param {!WebInspector.HeapSnapshotCommon.AllocationNodeCallers} callers
1444 * @this {WebInspector.AllocationGridNode}
1446 function didReceiveCallers(callers)
1448 var callersChain = callers.nodesWithSingleCaller;
1449 var parentNode = this;
1450 var dataGrid = /** @type {!WebInspector.AllocationDataGrid} */ (this._dataGrid);
1451 for (var i = 0; i < callersChain.length; i++) {
1452 var child = new WebInspector.AllocationGridNode(dataGrid, callersChain[i]);
1453 dataGrid.appendNode(parentNode, child);
1455 parentNode._populated = true;
1457 parentNode.expand();
1460 var callersBranch = callers.branchingCallers;
1461 callersBranch.sort(this._dataGrid._createComparator());
1462 for (var i = 0; i < callersBranch.length; i++)
1463 dataGrid.appendNode(parentNode, new WebInspector.AllocationGridNode(dataGrid, callersBranch[i]));
1464 dataGrid.updateVisibleNodes(true);
1473 WebInspector.HeapSnapshotGridNode.prototype.expand.call(this);
1474 if (this.children.length === 1)
1475 this.children[0].expand();
1480 * @param {string} columnIdentifier
1481 * @return {!Element}
1483 createCell: function(columnIdentifier)
1485 if (columnIdentifier !== "name")
1486 return this._createValueCell(columnIdentifier);
1488 var cell = WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
1489 var allocationNode = this._allocationNode;
1490 var target = this._dataGrid.target();
1491 if (allocationNode.scriptId) {
1492 var linkifier = this._dataGrid._linkifier;
1493 var urlElement = linkifier.linkifyScriptLocation(target, String(allocationNode.scriptId), allocationNode.scriptName, allocationNode.line - 1, allocationNode.column - 1, "profile-node-file");
1494 urlElement.style.maxWidth = "75%";
1495 cell.insertBefore(urlElement, cell.firstChild);
1503 allocationNodeId: function()
1505 return this._allocationNode.id;
1508 __proto__: WebInspector.HeapSnapshotGridNode.prototype