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 = createElement("td");
247 cell.className = "numeric-column";
248 if (this.dataGrid.snapshot.totalSize !== 0) {
249 var div = createElement("div");
250 var valueSpan = 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 = 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++);
407 // Merge with the next range.
408 if (nextRange && newEndOfRange === nextRange.from) {
409 range.to = nextRange.to;
410 // Remove "show next" button if there is one.
411 this.removeChildByIndex(insertionIndex);
412 this._retrievedChildrenRanges.splice(rangeIndex + 1, 1);
414 range.to = newEndOfRange;
415 // Remove or update next button.
416 if (newEndOfRange === itemsRange.totalLength)
417 this.removeChildByIndex(insertionIndex);
419 this.allChildren()[insertionIndex].setStartPosition(itemsRange.endPosition);
425 this._instanceCount += items.length;
426 if (firstNotSerializedPosition < toPosition) {
427 serializeNextChunk.call(this);
432 this._dataGrid.updateVisibleNodes(true);
435 this.dispatchEventToListeners(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete);
437 serializeNextChunk.call(this);
440 _saveChildren: function()
442 this._savedChildren = null;
443 var children = this.allChildren();
444 for (var i = 0, l = children.length; i < l; ++i) {
445 var child = children[i];
448 if (!this._savedChildren)
449 this._savedChildren = {};
450 this._savedChildren[this._childHashForNode(child)] = child;
456 this._dataGrid.recursiveSortingEnter();
459 * @this {WebInspector.HeapSnapshotGridNode}
463 this._saveChildren();
464 this._dataGrid.removeAllChildren(this);
465 this._retrievedChildrenRanges = [];
468 * @this {WebInspector.HeapSnapshotGridNode}
470 function afterPopulate()
472 var children = this.allChildren();
473 for (var i = 0, l = children.length; i < l; ++i) {
474 var child = children[i];
478 this._dataGrid.recursiveSortingLeave();
480 var instanceCount = this._instanceCount;
481 this._instanceCount = 0;
482 this._populateChildren(0, instanceCount, afterPopulate.bind(this));
485 this._provider().sortAndRewind(this.comparator(), afterSort.bind(this));
488 __proto__: WebInspector.DataGridNode.prototype
494 * @extends {WebInspector.HeapSnapshotGridNode}
495 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
496 * @param {!WebInspector.HeapSnapshotCommon.Node} node
498 WebInspector.HeapSnapshotGenericObjectNode = function(dataGrid, node)
500 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, false);
501 // node is null for DataGrid root nodes.
504 this._name = node.name;
505 this._type = node.type;
506 this._distance = node.distance;
507 this._shallowSize = node.selfSize;
508 this._retainedSize = node.retainedSize;
509 this.snapshotNodeId = node.id;
510 this.snapshotNodeIndex = node.nodeIndex;
511 if (this._type === "string")
512 this._reachableFromWindow = true;
513 else if (this._type === "object" && this._name.startsWith("Window")) {
514 this._name = this.shortenWindowURL(this._name, false);
515 this._reachableFromWindow = true;
516 } else if (node.canBeQueried)
517 this._reachableFromWindow = true;
518 if (node.detachedDOMTreeNode)
519 this.detachedDOMTreeNode = true;
521 var snapshot = dataGrid.snapshot;
522 var shallowSizePercent = this._shallowSize / snapshot.totalSize * 100.0;
523 var retainedSizePercent = this._retainedSize / snapshot.totalSize * 100.0;
525 "distance": this._toUIDistance(this._distance),
526 "shallowSize": Number.withThousandsSeparator(this._shallowSize),
527 "retainedSize": Number.withThousandsSeparator(this._retainedSize),
528 "shallowSize-percent": this._toPercentString(shallowSizePercent),
529 "retainedSize-percent": this._toPercentString(retainedSizePercent)
533 WebInspector.HeapSnapshotGenericObjectNode.prototype = {
535 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
537 retainersDataSource: function()
539 return {snapshot: this._dataGrid.snapshot, snapshotNodeIndex: this.snapshotNodeIndex};
543 * @param {string} columnIdentifier
546 createCell: function(columnIdentifier)
548 var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : this._createObjectCell();
549 if (this._searchMatched)
550 cell.classList.add("highlight");
557 _createObjectCell: function()
559 var value = this._name;
560 var valueStyle = "object";
561 switch (this._type) {
562 case "concatenated string":
564 value = "\"" + value + "\"";
565 valueStyle = "string";
568 value = "/" + value + "/";
569 valueStyle = "string";
572 value = "function" + (value ? " " : "") + value + "()";
573 valueStyle = "function";
576 valueStyle = "number";
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 console-formatted-" + valueStyle;
609 valueSpan.textContent = value;
610 div.appendChild(valueSpan);
612 var idSpan = createElement("span");
613 idSpan.className = "console-formatted-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 = {
721 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
723 retainersDataSource: function()
725 return {snapshot: this._snapshot, snapshotNodeIndex: this.snapshotNodeIndex};
729 * @return {!WebInspector.HeapSnapshotProviderProxy}
731 createProvider: function()
733 return this._snapshot.createEdgesProvider(this.snapshotNodeIndex);
736 _findAncestorWithSameSnapshotNodeId: function()
738 var ancestor = this._parentObjectNode;
740 if (ancestor.snapshotNodeId === this.snapshotNodeId)
742 ancestor = ancestor._parentObjectNode;
748 * @param {!WebInspector.HeapSnapshotCommon.Edge} item
749 * @return {!WebInspector.HeapSnapshotObjectNode}
751 _createChildNode: function(item)
753 return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._snapshot, item, this);
757 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
760 _childHashForEntity: function(edge)
762 return edge.edgeIndex;
766 * @param {!WebInspector.HeapSnapshotObjectNode} childNode
769 _childHashForNode: function(childNode)
771 return childNode._edgeIndex;
775 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
777 comparator: function()
779 var sortAscending = this._dataGrid.isSortOrderAscending();
780 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
782 object: ["!edgeName", sortAscending, "retainedSize", false],
783 count: ["!edgeName", true, "retainedSize", false],
784 shallowSize: ["selfSize", sortAscending, "!edgeName", true],
785 retainedSize: ["retainedSize", sortAscending, "!edgeName", true],
786 distance: ["distance", sortAscending, "_name", true]
787 }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
788 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
791 _prefixObjectCell: function(div)
793 var name = this._referenceName;
794 if (name === "") name = "(empty)";
795 var nameClass = "name";
796 switch (this._referenceType) {
798 nameClass = "console-formatted-number";
803 nameClass = "console-formatted-null";
806 name = "[" + name + "]";
810 if (this._cycledWithAncestorGridNode)
811 div.className += " cycled-ancessor-node";
813 var nameSpan = createElement("span");
814 nameSpan.className = nameClass;
815 nameSpan.textContent = name;
816 div.appendChild(nameSpan);
818 var separatorSpan = createElement("span");
819 separatorSpan.className = "grayed";
820 separatorSpan.textContent = this._edgeNodeSeparator();
821 div.appendChild(separatorSpan);
827 _edgeNodeSeparator: function()
832 __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
837 * @extends {WebInspector.HeapSnapshotObjectNode}
838 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
839 * @param {!WebInspector.HeapSnapshotProxy} snapshot
840 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
841 * @param {?WebInspector.HeapSnapshotRetainingObjectNode} parentRetainingObjectNode
843 WebInspector.HeapSnapshotRetainingObjectNode = function(dataGrid, snapshot, edge, parentRetainingObjectNode)
845 WebInspector.HeapSnapshotObjectNode.call(this, dataGrid, snapshot, edge, parentRetainingObjectNode);
848 WebInspector.HeapSnapshotRetainingObjectNode.prototype = {
850 * @return {!WebInspector.HeapSnapshotProviderProxy}
852 createProvider: function()
854 return this._snapshot.createRetainingEdgesProvider(this.snapshotNodeIndex);
858 * @param {!WebInspector.HeapSnapshotCommon.Edge} item
859 * @return {!WebInspector.HeapSnapshotRetainingObjectNode}
861 _createChildNode: function(item)
863 return new WebInspector.HeapSnapshotRetainingObjectNode(this._dataGrid, this._snapshot, item, this);
869 _edgeNodeSeparator: function()
876 this._expandRetainersChain(20);
880 * @param {number} maxExpandLevels
882 _expandRetainersChain: function(maxExpandLevels)
885 * @this {!WebInspector.HeapSnapshotRetainingObjectNode}
887 function populateComplete()
889 this.removeEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
890 this._expandRetainersChain(maxExpandLevels);
893 if (!this._populated) {
894 this.addEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
898 WebInspector.HeapSnapshotGenericObjectNode.prototype.expand.call(this);
899 if (--maxExpandLevels > 0 && this.children.length > 0) {
900 var retainer = this.children[0];
901 if (retainer._distance > 1) {
902 retainer._expandRetainersChain(maxExpandLevels);
906 this._dataGrid.dispatchEventToListeners(WebInspector.HeapSnapshotRetainmentDataGrid.Events.ExpandRetainersComplete);
909 __proto__: WebInspector.HeapSnapshotObjectNode.prototype
914 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
915 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
916 * @param {!WebInspector.HeapSnapshotProxy} snapshot
917 * @param {!WebInspector.HeapSnapshotCommon.Node} node
918 * @param {boolean} isDeletedNode
920 WebInspector.HeapSnapshotInstanceNode = function(dataGrid, snapshot, node, isDeletedNode)
922 WebInspector.HeapSnapshotGenericObjectNode.call(this, dataGrid, node);
923 this._baseSnapshotOrSnapshot = snapshot;
924 this._isDeletedNode = isDeletedNode;
925 this.updateHasChildren();
927 var data = this.data;
929 data["countDelta"] = "";
930 data["sizeDelta"] = "";
931 if (this._isDeletedNode) {
932 data["addedCount"] = "";
933 data["addedSize"] = "";
934 data["removedCount"] = "\u2022";
935 data["removedSize"] = Number.withThousandsSeparator(this._shallowSize);
937 data["addedCount"] = "\u2022";
938 data["addedSize"] = Number.withThousandsSeparator(this._shallowSize);
939 data["removedCount"] = "";
940 data["removedSize"] = "";
944 WebInspector.HeapSnapshotInstanceNode.prototype = {
946 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
948 retainersDataSource: function()
950 return {snapshot: this._baseSnapshotOrSnapshot, snapshotNodeIndex: this.snapshotNodeIndex};
954 * @return {!WebInspector.HeapSnapshotProviderProxy}
956 createProvider: function()
958 return this._baseSnapshotOrSnapshot.createEdgesProvider(this.snapshotNodeIndex);
962 * @param {!WebInspector.HeapSnapshotCommon.Edge} item
963 * @return {!WebInspector.HeapSnapshotObjectNode}
965 _createChildNode: function(item)
967 return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._baseSnapshotOrSnapshot, item, null);
971 * @param {!WebInspector.HeapSnapshotCommon.Edge} edge
974 _childHashForEntity: function(edge)
976 return edge.edgeIndex;
980 * @param {!WebInspector.HeapSnapshotObjectNode} childNode
983 _childHashForNode: function(childNode)
985 return childNode._edgeIndex;
989 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
991 comparator: function()
993 var sortAscending = this._dataGrid.isSortOrderAscending();
994 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
996 object: ["!edgeName", sortAscending, "retainedSize", false],
997 distance: ["distance", sortAscending, "retainedSize", false],
998 count: ["!edgeName", true, "retainedSize", false],
999 addedSize: ["selfSize", sortAscending, "!edgeName", true],
1000 removedSize: ["selfSize", sortAscending, "!edgeName", true],
1001 shallowSize: ["selfSize", sortAscending, "!edgeName", true],
1002 retainedSize: ["retainedSize", sortAscending, "!edgeName", true]
1003 }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
1004 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1007 __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
1012 * @param {!WebInspector.HeapSnapshotConstructorsDataGrid} dataGrid
1013 * @param {string} className
1014 * @param {!WebInspector.HeapSnapshotCommon.Aggregate} aggregate
1015 * @param {!WebInspector.HeapSnapshotCommon.NodeFilter} nodeFilter
1016 * @extends {WebInspector.HeapSnapshotGridNode}
1018 WebInspector.HeapSnapshotConstructorNode = function(dataGrid, className, aggregate, nodeFilter)
1020 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, aggregate.count > 0);
1021 this._name = className;
1022 this._nodeFilter = nodeFilter;
1023 this._distance = aggregate.distance;
1024 this._count = aggregate.count;
1025 this._shallowSize = aggregate.self;
1026 this._retainedSize = aggregate.maxRet;
1028 var snapshot = dataGrid.snapshot;
1029 var countPercent = this._count / snapshot.nodeCount * 100.0;
1030 var retainedSizePercent = this._retainedSize / snapshot.totalSize * 100.0;
1031 var shallowSizePercent = this._shallowSize / snapshot.totalSize * 100.0;
1034 "object": className,
1035 "count": Number.withThousandsSeparator(this._count),
1036 "distance": this._toUIDistance(this._distance),
1037 "shallowSize": Number.withThousandsSeparator(this._shallowSize),
1038 "retainedSize": Number.withThousandsSeparator(this._retainedSize),
1039 "count-percent": this._toPercentString(countPercent),
1040 "shallowSize-percent": this._toPercentString(shallowSizePercent),
1041 "retainedSize-percent": this._toPercentString(retainedSizePercent)
1045 WebInspector.HeapSnapshotConstructorNode.prototype = {
1048 * @return {!WebInspector.HeapSnapshotProviderProxy}
1050 createProvider: function()
1052 return this._dataGrid.snapshot.createNodesProviderForClass(this._name, this._nodeFilter)
1056 * @param {number} snapshotObjectId
1057 * @param {function(boolean)} callback
1059 revealNodeBySnapshotObjectId: function(snapshotObjectId, callback)
1062 * @this {WebInspector.HeapSnapshotConstructorNode}
1064 function didExpand()
1066 this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
1070 * @this {WebInspector.HeapSnapshotConstructorNode}
1071 * @param {number} nodePosition
1073 function didGetNodePosition(nodePosition)
1075 if (nodePosition === -1) {
1079 this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
1084 * @this {WebInspector.HeapSnapshotConstructorNode}
1085 * @param {number} nodePosition
1087 function didPopulateChildren(nodePosition)
1089 var child = this.childForPosition(nodePosition);
1091 this._dataGrid.revealTreeNode([this, child]);
1092 this._dataGrid.highlightNode(/** @type {!WebInspector.HeapSnapshotGridNode} */ (child));
1097 this._dataGrid.resetNameFilter();
1098 this.expandWithoutPopulate(didExpand.bind(this));
1102 * @param {string} filterValue
1105 filteredOut: function(filterValue)
1107 return this._name.toLowerCase().indexOf(filterValue) === -1;
1111 * @param {string} columnIdentifier
1112 * @return {!Element}
1114 createCell: function(columnIdentifier)
1116 var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
1117 if (this._searchMatched)
1118 cell.classList.add("highlight");
1123 * @param {!WebInspector.HeapSnapshotCommon.Node} item
1124 * @return {!WebInspector.HeapSnapshotInstanceNode}
1126 _createChildNode: function(item)
1128 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.snapshot, item, false);
1132 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1134 comparator: function()
1136 var sortAscending = this._dataGrid.isSortOrderAscending();
1137 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
1139 object: ["id", sortAscending, "retainedSize", false],
1140 distance: ["distance", sortAscending, "retainedSize", false],
1141 count: ["id", true, "retainedSize", false],
1142 shallowSize: ["selfSize", sortAscending, "id", true],
1143 retainedSize: ["retainedSize", sortAscending, "id", true]
1144 }[sortColumnIdentifier];
1145 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1149 * @param {!WebInspector.HeapSnapshotCommon.Node} node
1152 _childHashForEntity: function(node)
1158 * @param {!WebInspector.HeapSnapshotInstanceNode} childNode
1161 _childHashForNode: function(childNode)
1163 return childNode.snapshotNodeId;
1166 __proto__: WebInspector.HeapSnapshotGridNode.prototype
1172 * @implements {WebInspector.HeapSnapshotGridNode.ChildrenProvider}
1173 * @param {!WebInspector.HeapSnapshotProviderProxy} addedNodesProvider
1174 * @param {!WebInspector.HeapSnapshotProviderProxy} deletedNodesProvider
1175 * @param {number} addedCount
1176 * @param {number} removedCount
1178 WebInspector.HeapSnapshotDiffNodesProvider = function(addedNodesProvider, deletedNodesProvider, addedCount, removedCount)
1180 this._addedNodesProvider = addedNodesProvider;
1181 this._deletedNodesProvider = deletedNodesProvider;
1182 this._addedCount = addedCount;
1183 this._removedCount = removedCount;
1186 WebInspector.HeapSnapshotDiffNodesProvider.prototype = {
1189 this._addedNodesProvider.dispose();
1190 this._deletedNodesProvider.dispose();
1195 * @param {number} snapshotObjectId
1196 * @param {function(number)} callback
1198 nodePosition: function(snapshotObjectId, callback)
1200 throw new Error("Unreachable");
1204 * @param {function(boolean)} callback
1206 isEmpty: function(callback)
1212 * @param {number} beginPosition
1213 * @param {number} endPosition
1214 * @param {!function(!WebInspector.HeapSnapshotCommon.ItemsRange)} callback
1216 serializeItemsRange: function(beginPosition, endPosition, callback)
1219 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} items
1220 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1222 function didReceiveAllItems(items)
1224 items.totalLength = this._addedCount + this._removedCount;
1229 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} addedItems
1230 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
1231 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1233 function didReceiveDeletedItems(addedItems, itemsRange)
1235 var items = itemsRange.items;
1236 if (!addedItems.items.length)
1237 addedItems.startPosition = this._addedCount + itemsRange.startPosition;
1238 for (var i = 0; i < items.length; i++) {
1239 items[i].isAddedNotRemoved = false;
1240 addedItems.items.push(items[i]);
1242 addedItems.endPosition = this._addedCount + itemsRange.endPosition;
1243 didReceiveAllItems.call(this, addedItems);
1247 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
1248 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1250 function didReceiveAddedItems(itemsRange)
1252 var items = itemsRange.items;
1253 for (var i = 0; i < items.length; i++)
1254 items[i].isAddedNotRemoved = true;
1255 if (itemsRange.endPosition < endPosition)
1256 return this._deletedNodesProvider.serializeItemsRange(0, endPosition - itemsRange.endPosition, didReceiveDeletedItems.bind(this, itemsRange));
1258 itemsRange.totalLength = this._addedCount + this._removedCount;
1259 didReceiveAllItems.call(this, itemsRange);
1262 if (beginPosition < this._addedCount) {
1263 this._addedNodesProvider.serializeItemsRange(beginPosition, endPosition, didReceiveAddedItems.bind(this));
1265 var emptyRange = new WebInspector.HeapSnapshotCommon.ItemsRange(0, 0, 0, []);
1266 this._deletedNodesProvider.serializeItemsRange(beginPosition - this._addedCount, endPosition - this._addedCount, didReceiveDeletedItems.bind(this, emptyRange));
1271 * @param {!WebInspector.HeapSnapshotCommon.ComparatorConfig} comparator
1272 * @param {function()} callback
1274 sortAndRewind: function(comparator, callback)
1277 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1279 function afterSort()
1281 this._deletedNodesProvider.sortAndRewind(comparator, callback);
1283 this._addedNodesProvider.sortAndRewind(comparator, afterSort.bind(this));
1289 * @param {!WebInspector.HeapSnapshotDiffDataGrid} dataGrid
1290 * @param {string} className
1291 * @param {!WebInspector.HeapSnapshotCommon.DiffForClass} diffForClass
1292 * @extends {WebInspector.HeapSnapshotGridNode}
1294 WebInspector.HeapSnapshotDiffNode = function(dataGrid, className, diffForClass)
1296 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, true);
1297 this._name = className;
1298 this._addedCount = diffForClass.addedCount;
1299 this._removedCount = diffForClass.removedCount;
1300 this._countDelta = diffForClass.countDelta;
1301 this._addedSize = diffForClass.addedSize;
1302 this._removedSize = diffForClass.removedSize;
1303 this._sizeDelta = diffForClass.sizeDelta;
1304 this._deletedIndexes = diffForClass.deletedIndexes;
1306 "object": className,
1307 "addedCount": Number.withThousandsSeparator(this._addedCount),
1308 "removedCount": Number.withThousandsSeparator(this._removedCount),
1309 "countDelta": this._signForDelta(this._countDelta) + Number.withThousandsSeparator(Math.abs(this._countDelta)),
1310 "addedSize": Number.withThousandsSeparator(this._addedSize),
1311 "removedSize": Number.withThousandsSeparator(this._removedSize),
1312 "sizeDelta": this._signForDelta(this._sizeDelta) + Number.withThousandsSeparator(Math.abs(this._sizeDelta))
1316 WebInspector.HeapSnapshotDiffNode.prototype = {
1319 * @return {!WebInspector.HeapSnapshotDiffNodesProvider}
1321 createProvider: function()
1323 var tree = this._dataGrid;
1324 return new WebInspector.HeapSnapshotDiffNodesProvider(
1325 tree.snapshot.createAddedNodesProvider(tree.baseSnapshot.uid, this._name),
1326 tree.baseSnapshot.createDeletedNodesProvider(this._deletedIndexes),
1328 this._removedCount);
1332 * @param {string} columnIdentifier
1333 * @return {!Element}
1335 createCell: function(columnIdentifier)
1337 var cell = WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
1338 if (columnIdentifier !== "object")
1339 cell.classList.add("numeric-column");
1344 * @param {!WebInspector.HeapSnapshotCommon.Node} item
1345 * @return {!WebInspector.HeapSnapshotInstanceNode}
1347 _createChildNode: function(item)
1349 if (item.isAddedNotRemoved)
1350 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.snapshot, item, false);
1352 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.baseSnapshot, item, true);
1356 * @param {!WebInspector.HeapSnapshotCommon.Node} node
1359 _childHashForEntity: function(node)
1365 * @param {!WebInspector.HeapSnapshotInstanceNode} childNode
1368 _childHashForNode: function(childNode)
1370 return childNode.snapshotNodeId;
1374 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1376 comparator: function()
1378 var sortAscending = this._dataGrid.isSortOrderAscending();
1379 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
1381 object: ["id", sortAscending, "selfSize", false],
1382 addedCount: ["selfSize", sortAscending, "id", true],
1383 removedCount: ["selfSize", sortAscending, "id", true],
1384 countDelta: ["selfSize", sortAscending, "id", true],
1385 addedSize: ["selfSize", sortAscending, "id", true],
1386 removedSize: ["selfSize", sortAscending, "id", true],
1387 sizeDelta: ["selfSize", sortAscending, "id", true]
1388 }[sortColumnIdentifier];
1389 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1393 * @param {string} filterValue
1396 filteredOut: function(filterValue)
1398 return this._name.toLowerCase().indexOf(filterValue) === -1;
1401 _signForDelta: function(delta)
1408 return "\u2212"; // Math minus sign, same width as plus.
1411 __proto__: WebInspector.HeapSnapshotGridNode.prototype
1417 * @extends {WebInspector.HeapSnapshotGridNode}
1418 * @param {!WebInspector.AllocationDataGrid} dataGrid
1419 * @param {!WebInspector.HeapSnapshotCommon.SerializedAllocationNode} data
1421 WebInspector.AllocationGridNode = function(dataGrid, data)
1423 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, data.hasChildren);
1424 this._populated = false;
1425 this._allocationNode = data;
1427 "liveCount": Number.withThousandsSeparator(data.liveCount),
1428 "count": Number.withThousandsSeparator(data.count),
1429 "liveSize": Number.withThousandsSeparator(data.liveSize),
1430 "size": Number.withThousandsSeparator(data.size),
1435 WebInspector.AllocationGridNode.prototype = {
1436 populate: function()
1438 if (this._populated)
1440 this._populated = true;
1441 this._dataGrid.snapshot.allocationNodeCallers(this._allocationNode.id, didReceiveCallers.bind(this));
1444 * @param {!WebInspector.HeapSnapshotCommon.AllocationNodeCallers} callers
1445 * @this {WebInspector.AllocationGridNode}
1447 function didReceiveCallers(callers)
1449 var callersChain = callers.nodesWithSingleCaller;
1450 var parentNode = this;
1451 var dataGrid = /** @type {!WebInspector.AllocationDataGrid} */ (this._dataGrid);
1452 for (var i = 0; i < callersChain.length; i++) {
1453 var child = new WebInspector.AllocationGridNode(dataGrid, callersChain[i]);
1454 dataGrid.appendNode(parentNode, child);
1456 parentNode._populated = true;
1458 parentNode.expand();
1461 var callersBranch = callers.branchingCallers;
1462 callersBranch.sort(this._dataGrid._createComparator());
1463 for (var i = 0; i < callersBranch.length; i++)
1464 dataGrid.appendNode(parentNode, new WebInspector.AllocationGridNode(dataGrid, callersBranch[i]));
1465 dataGrid.updateVisibleNodes(true);
1474 WebInspector.HeapSnapshotGridNode.prototype.expand.call(this);
1475 if (this.children.length === 1)
1476 this.children[0].expand();
1481 * @param {string} columnIdentifier
1482 * @return {!Element}
1484 createCell: function(columnIdentifier)
1486 if (columnIdentifier !== "name")
1487 return this._createValueCell(columnIdentifier);
1489 var cell = WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
1490 var allocationNode = this._allocationNode;
1491 var target = this._dataGrid.target();
1492 if (allocationNode.scriptId) {
1493 var linkifier = this._dataGrid._linkifier;
1494 var urlElement = linkifier.linkifyScriptLocation(target, String(allocationNode.scriptId), allocationNode.scriptName, allocationNode.line - 1, allocationNode.column - 1, "profile-node-file");
1495 urlElement.style.maxWidth = "75%";
1496 cell.insertBefore(urlElement, cell.firstChild);
1504 allocationNodeId: function()
1506 return this._allocationNode.id;
1509 __proto__: WebInspector.HeapSnapshotGridNode.prototype