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);
187 _toPercentString: function(num)
189 return num.toFixed(0) + "\u2009%"; // \u2009 is a thin space.
193 * @return {!Array.<!WebInspector.DataGridNode>}
195 allChildren: function()
197 return this._dataGrid.allChildren(this);
201 * @param {number} index
203 removeChildByIndex: function(index)
205 this._dataGrid.removeChildByIndex(this, index);
209 * @param {number} nodePosition
210 * @return {?WebInspector.DataGridNode}
212 childForPosition: function(nodePosition)
214 var indexOfFirstChildInRange = 0;
215 for (var i = 0; i < this._retrievedChildrenRanges.length; i++) {
216 var range = this._retrievedChildrenRanges[i];
217 if (range.from <= nodePosition && nodePosition < range.to) {
218 var childIndex = indexOfFirstChildInRange + nodePosition - range.from;
219 return this.allChildren()[childIndex];
221 indexOfFirstChildInRange += range.to - range.from + 1;
227 * @param {string} columnIdentifier
230 _createValueCell: function(columnIdentifier)
232 var cell = document.createElement("td");
233 cell.className = columnIdentifier + "-column";
234 if (this.dataGrid.snapshot.totalSize !== 0) {
235 var div = document.createElement("div");
236 var valueSpan = document.createElement("span");
237 valueSpan.textContent = this.data[columnIdentifier];
238 div.appendChild(valueSpan);
239 var percentColumn = columnIdentifier + "-percent";
240 if (percentColumn in this.data) {
241 var percentSpan = document.createElement("span");
242 percentSpan.className = "percent-column";
243 percentSpan.textContent = this.data[percentColumn];
244 div.appendChild(percentSpan);
245 div.classList.add("heap-snapshot-multiple-values");
247 cell.appendChild(div);
252 populate: function(event)
256 this._populated = true;
259 * @this {WebInspector.HeapSnapshotGridNode}
263 this._populateChildren();
265 this._provider().sortAndRewind(this.comparator(), sorted.bind(this));
268 expandWithoutPopulate: function(callback)
270 // Make sure default populate won't take action.
271 this._populated = true;
273 this._provider().sortAndRewind(this.comparator(), callback);
277 * @param {?number=} fromPosition
278 * @param {?number=} toPosition
279 * @param {function()=} afterPopulate
281 _populateChildren: function(fromPosition, toPosition, afterPopulate)
283 fromPosition = fromPosition || 0;
284 toPosition = toPosition || fromPosition + this._dataGrid.defaultPopulateCount();
285 var firstNotSerializedPosition = fromPosition;
288 * @this {WebInspector.HeapSnapshotGridNode}
290 function serializeNextChunk()
292 if (firstNotSerializedPosition >= toPosition)
294 var end = Math.min(firstNotSerializedPosition + this._dataGrid.defaultPopulateCount(), toPosition);
295 this._provider().serializeItemsRange(firstNotSerializedPosition, end, childrenRetrieved.bind(this));
296 firstNotSerializedPosition = end;
300 * @this {WebInspector.HeapSnapshotGridNode}
302 function insertRetrievedChild(item, insertionIndex)
304 if (this._savedChildren) {
305 var hash = this._childHashForEntity(item);
306 if (hash in this._savedChildren) {
307 this._dataGrid.insertChild(this, this._savedChildren[hash], insertionIndex);
311 this._dataGrid.insertChild(this, this._createChildNode(item), insertionIndex);
315 * @this {WebInspector.HeapSnapshotGridNode}
317 function insertShowMoreButton(from, to, insertionIndex)
319 var button = new WebInspector.ShowMoreDataGridNode(this._populateChildren.bind(this), from, to, this._dataGrid.defaultPopulateCount());
320 this._dataGrid.insertChild(this, button, insertionIndex);
324 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
325 * @this {WebInspector.HeapSnapshotGridNode}
327 function childrenRetrieved(itemsRange)
330 var itemPosition = itemsRange.startPosition;
331 var items = itemsRange.items;
332 var insertionIndex = 0;
334 if (!this._retrievedChildrenRanges.length) {
335 if (itemsRange.startPosition > 0) {
336 this._retrievedChildrenRanges.push({from: 0, to: 0});
337 insertShowMoreButton.call(this, 0, itemsRange.startPosition, insertionIndex++);
339 this._retrievedChildrenRanges.push({from: itemsRange.startPosition, to: itemsRange.endPosition});
340 for (var i = 0, l = items.length; i < l; ++i)
341 insertRetrievedChild.call(this, items[i], insertionIndex++);
342 if (itemsRange.endPosition < itemsRange.totalLength)
343 insertShowMoreButton.call(this, itemsRange.endPosition, itemsRange.totalLength, insertionIndex++);
348 while (rangeIndex < this._retrievedChildrenRanges.length) {
349 range = this._retrievedChildrenRanges[rangeIndex];
350 if (range.to >= itemPosition) {
354 insertionIndex += range.to - range.from;
355 // Skip the button if there is one.
356 if (range.to < itemsRange.totalLength)
361 if (!found || itemsRange.startPosition < range.from) {
362 // Update previous button.
363 this.allChildren()[insertionIndex - 1].setEndPosition(itemsRange.startPosition);
364 insertShowMoreButton.call(this, itemsRange.startPosition, found ? range.from : itemsRange.totalLength, insertionIndex);
365 range = {from: itemsRange.startPosition, to: itemsRange.startPosition};
367 rangeIndex = this._retrievedChildrenRanges.length;
368 this._retrievedChildrenRanges.splice(rangeIndex, 0, range);
370 insertionIndex += itemPosition - range.from;
372 // At this point insertionIndex is always an index before button or between nodes.
373 // Also it is always true here that range.from <= itemPosition <= range.to
375 // Stretch the range right bound to include all new items.
376 while (range.to < itemsRange.endPosition) {
377 // Skip already added nodes.
378 var skipCount = range.to - itemPosition;
379 insertionIndex += skipCount;
380 itemIndex += skipCount;
381 itemPosition = range.to;
383 // We're at the position before button: ...<?node>x<button>
384 var nextRange = this._retrievedChildrenRanges[rangeIndex + 1];
385 var newEndOfRange = nextRange ? nextRange.from : itemsRange.totalLength;
386 if (newEndOfRange > itemsRange.endPosition)
387 newEndOfRange = itemsRange.endPosition;
388 while (itemPosition < newEndOfRange) {
389 insertRetrievedChild.call(this, items[itemIndex++], insertionIndex++);
392 // Merge with the next range.
393 if (nextRange && newEndOfRange === nextRange.from) {
394 range.to = nextRange.to;
395 // Remove "show next" button if there is one.
396 this.removeChildByIndex(insertionIndex);
397 this._retrievedChildrenRanges.splice(rangeIndex + 1, 1);
399 range.to = newEndOfRange;
400 // Remove or update next button.
401 if (newEndOfRange === itemsRange.totalLength)
402 this.removeChildByIndex(insertionIndex);
404 this.allChildren()[insertionIndex].setStartPosition(itemsRange.endPosition);
410 this._instanceCount += items.length;
411 if (firstNotSerializedPosition < toPosition) {
412 serializeNextChunk.call(this);
417 this._dataGrid.updateVisibleNodes(true);
420 this.dispatchEventToListeners(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete);
422 serializeNextChunk.call(this);
425 _saveChildren: function()
427 this._savedChildren = null;
428 var children = this.allChildren();
429 for (var i = 0, l = children.length; i < l; ++i) {
430 var child = children[i];
433 if (!this._savedChildren)
434 this._savedChildren = {};
435 this._savedChildren[this._childHashForNode(child)] = child;
441 this._dataGrid.recursiveSortingEnter();
444 * @this {WebInspector.HeapSnapshotGridNode}
448 this._saveChildren();
449 this._dataGrid.removeAllChildren(this);
450 this._retrievedChildrenRanges = [];
453 * @this {WebInspector.HeapSnapshotGridNode}
455 function afterPopulate()
457 var children = this.allChildren();
458 for (var i = 0, l = children.length; i < l; ++i) {
459 var child = children[i];
463 this._dataGrid.recursiveSortingLeave();
465 var instanceCount = this._instanceCount;
466 this._instanceCount = 0;
467 this._populateChildren(0, instanceCount, afterPopulate.bind(this));
470 this._provider().sortAndRewind(this.comparator(), afterSort.bind(this));
473 __proto__: WebInspector.DataGridNode.prototype
479 * @extends {WebInspector.HeapSnapshotGridNode}
480 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
482 WebInspector.HeapSnapshotGenericObjectNode = function(dataGrid, node)
484 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, false);
485 // node is null for DataGrid root nodes.
488 this._name = node.name;
489 this._type = node.type;
490 this._distance = node.distance;
491 this._shallowSize = node.selfSize;
492 this._retainedSize = node.retainedSize;
493 this.snapshotNodeId = node.id;
494 this.snapshotNodeIndex = node.nodeIndex;
495 if (this._type === "string")
496 this._reachableFromWindow = true;
497 else if (this._type === "object" && this._name.startsWith("Window")) {
498 this._name = this.shortenWindowURL(this._name, false);
499 this._reachableFromWindow = true;
500 } else if (node.canBeQueried)
501 this._reachableFromWindow = true;
502 if (node.detachedDOMTreeNode)
503 this.detachedDOMTreeNode = true;
505 var snapshot = dataGrid.snapshot;
506 var shallowSizePercent = this._shallowSize / snapshot.totalSize * 100.0;
507 var retainedSizePercent = this._retainedSize / snapshot.totalSize * 100.0;
509 "distance": this._distance,
510 "shallowSize": Number.withThousandsSeparator(this._shallowSize),
511 "retainedSize": Number.withThousandsSeparator(this._retainedSize),
512 "shallowSize-percent": this._toPercentString(shallowSizePercent),
513 "retainedSize-percent": this._toPercentString(retainedSizePercent)
517 WebInspector.HeapSnapshotGenericObjectNode.prototype = {
519 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
521 retainersDataSource: function()
523 return {snapshot: this._dataGrid.snapshot, snapshotNodeIndex: this.snapshotNodeIndex};
527 * @param {string} columnIdentifier
530 createCell: function(columnIdentifier)
532 var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : this._createObjectCell();
533 if (this._searchMatched)
534 cell.classList.add("highlight");
541 _createObjectCell: function()
543 var value = this._name;
544 var valueStyle = "object";
545 switch (this._type) {
546 case "concatenated string":
548 value = "\"" + value + "\"";
549 valueStyle = "string";
552 value = "/" + value + "/";
553 valueStyle = "string";
556 value = "function" + (value ? " " : "") + value + "()";
557 valueStyle = "function";
560 valueStyle = "number";
572 if (this._reachableFromWindow)
573 valueStyle += " highlight";
574 if (value === "Object")
576 if (this.detachedDOMTreeNode)
577 valueStyle += " detached-dom-tree-node";
578 return this._createObjectCellWithValue(valueStyle, value);
581 _createObjectCellWithValue: function(valueStyle, value)
583 var cell = document.createElement("td");
584 cell.className = "object-column";
585 var div = document.createElement("div");
586 div.className = "source-code event-properties";
587 div.style.overflow = "visible";
589 this._prefixObjectCell(div);
591 var valueSpan = document.createElement("span");
592 valueSpan.className = "value console-formatted-" + valueStyle;
593 valueSpan.textContent = value;
594 div.appendChild(valueSpan);
596 var idSpan = document.createElement("span");
597 idSpan.className = "console-formatted-id";
598 idSpan.textContent = " @" + this.snapshotNodeId;
599 div.appendChild(idSpan);
601 cell.appendChild(div);
602 cell.classList.add("disclosure");
604 cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px");
605 cell.heapSnapshotNode = this;
609 _prefixObjectCell: function(div)
613 queryObjectContent: function(callback, objectGroupName)
616 * @param {?Protocol.Error} error
617 * @param {!RuntimeAgent.RemoteObject} object
619 function formatResult(error, object)
621 if (!error && object.type)
622 callback(WebInspector.RemoteObject.fromPayload(object), !!error);
624 callback(WebInspector.RemoteObject.fromPrimitiveValue(WebInspector.UIString("Preview is not available")));
627 if (this._type === "string")
628 callback(WebInspector.RemoteObject.fromPrimitiveValue(this._name));
630 HeapProfilerAgent.getObjectByHeapObjectId(String(this.snapshotNodeId), objectGroupName, formatResult);
633 updateHasChildren: function()
636 * @this {WebInspector.HeapSnapshotGenericObjectNode}
638 function isEmptyCallback(isEmpty)
640 this.hasChildren = !isEmpty;
642 this._provider().isEmpty(isEmptyCallback.bind(this));
646 * @param {string} fullName
647 * @param {boolean} hasObjectId
650 shortenWindowURL: function(fullName, hasObjectId)
652 var startPos = fullName.indexOf("/");
653 var endPos = hasObjectId ? fullName.indexOf("@") : fullName.length;
654 if (startPos !== -1 && endPos !== -1) {
655 var fullURL = fullName.substring(startPos + 1, endPos).trimLeft();
656 var url = fullURL.trimURL();
658 url = url.trimMiddle(40);
659 return fullName.substr(0, startPos + 2) + url + fullName.substr(endPos);
664 __proto__: WebInspector.HeapSnapshotGridNode.prototype
669 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
670 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
671 * @param {!WebInspector.HeapSnapshotProxy} snapshot
673 WebInspector.HeapSnapshotObjectNode = function(dataGrid, snapshot, edge, parentGridNode)
675 WebInspector.HeapSnapshotGenericObjectNode.call(this, dataGrid, edge.node);
676 this._referenceName = edge.name;
677 this._referenceType = edge.type;
678 this.showRetainingEdges = dataGrid.showRetainingEdges;
679 this._snapshot = snapshot;
681 this._parentGridNode = parentGridNode;
682 this._cycledWithAncestorGridNode = this._findAncestorWithSameSnapshotNodeId();
683 if (!this._cycledWithAncestorGridNode)
684 this.updateHasChildren();
686 var data = this.data;
688 data["addedCount"] = "";
689 data["removedCount"] = "";
690 data["countDelta"] = "";
691 data["addedSize"] = "";
692 data["removedSize"] = "";
693 data["sizeDelta"] = "";
696 WebInspector.HeapSnapshotObjectNode.prototype = {
698 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
700 retainersDataSource: function()
702 return {snapshot: this._snapshot, snapshotNodeIndex: this.snapshotNodeIndex};
706 * @return {!WebInspector.HeapSnapshotProviderProxy}
708 createProvider: function()
710 var tree = this._dataGrid;
711 if (this.showRetainingEdges)
712 return this._snapshot.createRetainingEdgesProvider(this.snapshotNodeIndex);
714 return this._snapshot.createEdgesProvider(this.snapshotNodeIndex);
717 _findAncestorWithSameSnapshotNodeId: function()
719 var ancestor = this._parentGridNode;
721 if (ancestor.snapshotNodeId === this.snapshotNodeId)
723 ancestor = ancestor._parentGridNode;
728 _createChildNode: function(item)
730 return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._snapshot, item, this);
733 _childHashForEntity: function(edge)
735 var prefix = this.showRetainingEdges ? edge.node.id + "#" : "";
736 return prefix + edge.type + "#" + edge.name;
739 _childHashForNode: function(childNode)
741 var prefix = this.showRetainingEdges ? childNode.snapshotNodeId + "#" : "";
742 return prefix + childNode._referenceType + "#" + childNode._referenceName;
746 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
748 comparator: function()
750 var sortAscending = this._dataGrid.isSortOrderAscending();
751 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
753 object: ["!edgeName", sortAscending, "retainedSize", false],
754 count: ["!edgeName", true, "retainedSize", false],
755 shallowSize: ["selfSize", sortAscending, "!edgeName", true],
756 retainedSize: ["retainedSize", sortAscending, "!edgeName", true],
757 distance: ["distance", sortAscending, "_name", true]
758 }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
759 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
762 _prefixObjectCell: function(div)
764 var name = this._referenceName;
765 if (name === "") name = "(empty)";
766 var nameClass = "name";
767 switch (this._referenceType) {
769 nameClass = "console-formatted-number";
774 nameClass = "console-formatted-null";
777 name = "[" + name + "]";
781 if (this._cycledWithAncestorGridNode)
782 div.className += " cycled-ancessor-node";
784 var nameSpan = document.createElement("span");
785 nameSpan.className = nameClass;
786 nameSpan.textContent = name;
787 div.appendChild(nameSpan);
789 var separatorSpan = document.createElement("span");
790 separatorSpan.className = "grayed";
791 separatorSpan.textContent = this.showRetainingEdges ? " in " : " :: ";
792 div.appendChild(separatorSpan);
795 __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
800 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
801 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
802 * @param {!WebInspector.HeapSnapshotProxy} snapshot
803 * @param {boolean} isDeletedNode
805 WebInspector.HeapSnapshotInstanceNode = function(dataGrid, snapshot, node, isDeletedNode)
807 WebInspector.HeapSnapshotGenericObjectNode.call(this, dataGrid, node);
808 this._baseSnapshotOrSnapshot = snapshot;
809 this._isDeletedNode = isDeletedNode;
810 this.updateHasChildren();
812 var data = this.data;
814 data["countDelta"] = "";
815 data["sizeDelta"] = "";
816 if (this._isDeletedNode) {
817 data["addedCount"] = "";
818 data["addedSize"] = "";
819 data["removedCount"] = "\u2022";
820 data["removedSize"] = Number.withThousandsSeparator(this._shallowSize);
822 data["addedCount"] = "\u2022";
823 data["addedSize"] = Number.withThousandsSeparator(this._shallowSize);
824 data["removedCount"] = "";
825 data["removedSize"] = "";
829 WebInspector.HeapSnapshotInstanceNode.prototype = {
831 * @return {?{snapshot:!WebInspector.HeapSnapshotProxy, snapshotNodeIndex:number}}
833 retainersDataSource: function()
835 return {snapshot: this._baseSnapshotOrSnapshot, snapshotNodeIndex: this.snapshotNodeIndex};
839 * @return {!WebInspector.HeapSnapshotProviderProxy}
841 createProvider: function()
843 return this._baseSnapshotOrSnapshot.createEdgesProvider(this.snapshotNodeIndex);
846 _createChildNode: function(item)
848 return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._baseSnapshotOrSnapshot, item, null);
851 _childHashForEntity: function(edge)
853 return edge.type + "#" + edge.name;
856 _childHashForNode: function(childNode)
858 return childNode._referenceType + "#" + childNode._referenceName;
862 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
864 comparator: function()
866 var sortAscending = this._dataGrid.isSortOrderAscending();
867 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
869 object: ["!edgeName", sortAscending, "retainedSize", false],
870 distance: ["distance", sortAscending, "retainedSize", false],
871 count: ["!edgeName", true, "retainedSize", false],
872 addedSize: ["selfSize", sortAscending, "!edgeName", true],
873 removedSize: ["selfSize", sortAscending, "!edgeName", true],
874 shallowSize: ["selfSize", sortAscending, "!edgeName", true],
875 retainedSize: ["retainedSize", sortAscending, "!edgeName", true]
876 }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
877 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
880 __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
885 * @param {!WebInspector.HeapSnapshotConstructorsDataGrid} dataGrid
886 * @param {string} className
887 * @param {!WebInspector.HeapSnapshotCommon.Aggregate} aggregate
888 * @param {!WebInspector.HeapSnapshotCommon.NodeFilter} nodeFilter
889 * @extends {WebInspector.HeapSnapshotGridNode}
891 WebInspector.HeapSnapshotConstructorNode = function(dataGrid, className, aggregate, nodeFilter)
893 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, aggregate.count > 0);
894 this._name = className;
895 this._nodeFilter = nodeFilter;
896 this._distance = aggregate.distance;
897 this._count = aggregate.count;
898 this._shallowSize = aggregate.self;
899 this._retainedSize = aggregate.maxRet;
901 var snapshot = dataGrid.snapshot;
902 var countPercent = this._count / snapshot.nodeCount * 100.0;
903 var retainedSizePercent = this._retainedSize / snapshot.totalSize * 100.0;
904 var shallowSizePercent = this._shallowSize / snapshot.totalSize * 100.0;
908 "count": Number.withThousandsSeparator(this._count),
909 "distance": this._distance,
910 "shallowSize": Number.withThousandsSeparator(this._shallowSize),
911 "retainedSize": Number.withThousandsSeparator(this._retainedSize),
912 "count-percent": this._toPercentString(countPercent),
913 "shallowSize-percent": this._toPercentString(shallowSizePercent),
914 "retainedSize-percent": this._toPercentString(retainedSizePercent)
918 WebInspector.HeapSnapshotConstructorNode.prototype = {
921 * @return {!WebInspector.HeapSnapshotProviderProxy}
923 createProvider: function()
925 return this._dataGrid.snapshot.createNodesProviderForClass(this._name, this._nodeFilter)
929 * @param {number} snapshotObjectId
930 * @param {function(boolean)} callback
932 revealNodeBySnapshotObjectId: function(snapshotObjectId, callback)
935 * @this {WebInspector.HeapSnapshotConstructorNode}
939 this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
943 * @this {WebInspector.HeapSnapshotConstructorNode}
944 * @param {number} nodePosition
946 function didGetNodePosition(nodePosition)
948 if (nodePosition === -1) {
952 this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
957 * @this {WebInspector.HeapSnapshotConstructorNode}
958 * @param {number} nodePosition
960 function didPopulateChildren(nodePosition)
962 var child = this.childForPosition(nodePosition);
964 this._dataGrid.revealTreeNode([this, child]);
965 this._dataGrid.highlightNode(/** @type {!WebInspector.HeapSnapshotGridNode} */ (child));
970 this._dataGrid.resetNameFilter(this.expandWithoutPopulate.bind(this, didExpand.bind(this)));
976 filteredOut: function()
978 return this._name.toLowerCase().indexOf(this._dataGrid._nameFilter) === -1;
982 * @param {string} columnIdentifier
985 createCell: function(columnIdentifier)
987 var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
988 if (this._searchMatched)
989 cell.classList.add("highlight");
993 _createChildNode: function(item)
995 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.snapshot, item, false);
999 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1001 comparator: function()
1003 var sortAscending = this._dataGrid.isSortOrderAscending();
1004 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
1006 object: ["id", sortAscending, "retainedSize", false],
1007 distance: ["distance", sortAscending, "retainedSize", false],
1008 count: ["id", true, "retainedSize", false],
1009 shallowSize: ["selfSize", sortAscending, "id", true],
1010 retainedSize: ["retainedSize", sortAscending, "id", true]
1011 }[sortColumnIdentifier];
1012 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1015 _childHashForEntity: function(node)
1020 _childHashForNode: function(childNode)
1022 return childNode.snapshotNodeId;
1025 __proto__: WebInspector.HeapSnapshotGridNode.prototype
1031 * @implements {WebInspector.HeapSnapshotGridNode.ChildrenProvider}
1032 * @param {!WebInspector.HeapSnapshotProviderProxy} addedNodesProvider
1033 * @param {!WebInspector.HeapSnapshotProviderProxy} deletedNodesProvider
1035 WebInspector.HeapSnapshotDiffNodesProvider = function(addedNodesProvider, deletedNodesProvider, addedCount, removedCount)
1037 this._addedNodesProvider = addedNodesProvider;
1038 this._deletedNodesProvider = deletedNodesProvider;
1039 this._addedCount = addedCount;
1040 this._removedCount = removedCount;
1043 WebInspector.HeapSnapshotDiffNodesProvider.prototype = {
1046 this._addedNodesProvider.dispose();
1047 this._deletedNodesProvider.dispose();
1052 * @param {number} snapshotObjectId
1053 * @param {function(number)} callback
1055 nodePosition: function(snapshotObjectId, callback)
1057 throw new Error("Unreachable");
1061 * @param {function(boolean)} callback
1063 isEmpty: function(callback)
1069 * @param {number} beginPosition
1070 * @param {number} endPosition
1071 * @param {!function(!WebInspector.HeapSnapshotCommon.ItemsRange)} callback
1073 serializeItemsRange: function(beginPosition, endPosition, callback)
1076 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} items
1077 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1079 function didReceiveAllItems(items)
1081 items.totalLength = this._addedCount + this._removedCount;
1086 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} addedItems
1087 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
1088 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1090 function didReceiveDeletedItems(addedItems, itemsRange)
1092 var items = itemsRange.items;
1093 if (!addedItems.items.length)
1094 addedItems.startPosition = this._addedCount + itemsRange.startPosition;
1095 for (var i = 0; i < items.length; i++) {
1096 items[i].isAddedNotRemoved = false;
1097 addedItems.items.push(items[i]);
1099 addedItems.endPosition = this._addedCount + itemsRange.endPosition;
1100 didReceiveAllItems.call(this, addedItems);
1104 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
1105 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1107 function didReceiveAddedItems(itemsRange)
1109 var items = itemsRange.items;
1110 for (var i = 0; i < items.length; i++)
1111 items[i].isAddedNotRemoved = true;
1112 if (itemsRange.endPosition < endPosition)
1113 return this._deletedNodesProvider.serializeItemsRange(0, endPosition - itemsRange.endPosition, didReceiveDeletedItems.bind(this, itemsRange));
1115 itemsRange.totalLength = this._addedCount + this._removedCount;
1116 didReceiveAllItems.call(this, itemsRange);
1119 if (beginPosition < this._addedCount) {
1120 this._addedNodesProvider.serializeItemsRange(beginPosition, endPosition, didReceiveAddedItems.bind(this));
1122 var emptyRange = new WebInspector.HeapSnapshotCommon.ItemsRange(0, 0, 0, []);
1123 this._deletedNodesProvider.serializeItemsRange(beginPosition - this._addedCount, endPosition - this._addedCount, didReceiveDeletedItems.bind(this, emptyRange));
1128 * @param {!WebInspector.HeapSnapshotCommon.ComparatorConfig} comparator
1129 * @param {function()} callback
1131 sortAndRewind: function(comparator, callback)
1134 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1136 function afterSort()
1138 this._deletedNodesProvider.sortAndRewind(comparator, callback);
1140 this._addedNodesProvider.sortAndRewind(comparator, afterSort.bind(this));
1146 * @param {!WebInspector.HeapSnapshotDiffDataGrid} dataGrid
1147 * @param {string} className
1148 * @param {!WebInspector.HeapSnapshotCommon.DiffForClass} diffForClass
1149 * @extends {WebInspector.HeapSnapshotGridNode}
1151 WebInspector.HeapSnapshotDiffNode = function(dataGrid, className, diffForClass)
1153 WebInspector.HeapSnapshotGridNode.call(this, dataGrid, true);
1154 this._name = className;
1155 this._addedCount = diffForClass.addedCount;
1156 this._removedCount = diffForClass.removedCount;
1157 this._countDelta = diffForClass.countDelta;
1158 this._addedSize = diffForClass.addedSize;
1159 this._removedSize = diffForClass.removedSize;
1160 this._sizeDelta = diffForClass.sizeDelta;
1161 this._deletedIndexes = diffForClass.deletedIndexes;
1163 "object": className,
1164 "addedCount": Number.withThousandsSeparator(this._addedCount),
1165 "removedCount": Number.withThousandsSeparator(this._removedCount),
1166 "countDelta": this._signForDelta(this._countDelta) + Number.withThousandsSeparator(Math.abs(this._countDelta)),
1167 "addedSize": Number.withThousandsSeparator(this._addedSize),
1168 "removedSize": Number.withThousandsSeparator(this._removedSize),
1169 "sizeDelta": this._signForDelta(this._sizeDelta) + Number.withThousandsSeparator(Math.abs(this._sizeDelta))
1173 WebInspector.HeapSnapshotDiffNode.prototype = {
1176 * @return {!WebInspector.HeapSnapshotDiffNodesProvider}
1178 createProvider: function()
1180 var tree = this._dataGrid;
1181 return new WebInspector.HeapSnapshotDiffNodesProvider(
1182 tree.snapshot.createAddedNodesProvider(tree.baseSnapshot.uid, this._name),
1183 tree.baseSnapshot.createDeletedNodesProvider(this._deletedIndexes),
1185 this._removedCount);
1188 _createChildNode: function(item)
1190 if (item.isAddedNotRemoved)
1191 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.snapshot, item, false);
1193 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.baseSnapshot, item, true);
1196 _childHashForEntity: function(node)
1201 _childHashForNode: function(childNode)
1203 return childNode.snapshotNodeId;
1207 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1209 comparator: function()
1211 var sortAscending = this._dataGrid.isSortOrderAscending();
1212 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
1214 object: ["id", sortAscending, "selfSize", false],
1215 addedCount: ["selfSize", sortAscending, "id", true],
1216 removedCount: ["selfSize", sortAscending, "id", true],
1217 countDelta: ["selfSize", sortAscending, "id", true],
1218 addedSize: ["selfSize", sortAscending, "id", true],
1219 removedSize: ["selfSize", sortAscending, "id", true],
1220 sizeDelta: ["selfSize", sortAscending, "id", true]
1221 }[sortColumnIdentifier];
1222 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1228 filteredOut: function()
1230 return this._name.toLowerCase().indexOf(this._dataGrid._nameFilter) === -1;
1233 _signForDelta: function(delta)
1240 return "\u2212"; // Math minus sign, same width as plus.
1243 __proto__: WebInspector.HeapSnapshotGridNode.prototype
1249 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
1250 * @param {!WebInspector.HeapSnapshotSortableDataGrid} dataGrid
1252 WebInspector.HeapSnapshotDominatorObjectNode = function(dataGrid, node)
1254 WebInspector.HeapSnapshotGenericObjectNode.call(this, dataGrid, node);
1255 this.updateHasChildren();
1258 WebInspector.HeapSnapshotDominatorObjectNode.prototype = {
1261 * @return {!WebInspector.HeapSnapshotProviderProxy}
1263 createProvider: function()
1265 return this._dataGrid.snapshot.createNodesProviderForDominator(this.snapshotNodeIndex);
1269 * @param {number} snapshotObjectId
1270 * @param {function(?WebInspector.DataGridNode)} callback
1272 retrieveChildBySnapshotObjectId: function(snapshotObjectId, callback)
1275 * @this {WebInspector.HeapSnapshotDominatorObjectNode}
1277 function didExpand()
1279 this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
1283 * @this {WebInspector.HeapSnapshotDominatorObjectNode}
1285 function didGetNodePosition(nodePosition)
1287 if (nodePosition === -1) {
1291 this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
1295 * @this {WebInspector.HeapSnapshotDominatorObjectNode}
1297 function didPopulateChildren(nodePosition)
1299 var child = this.childForPosition(nodePosition);
1303 // Make sure hasChildren flag is updated before expanding this node as updateHasChildren response
1304 // may not have been received yet.
1305 this.hasChildren = true;
1306 this.expandWithoutPopulate(didExpand.bind(this));
1309 _createChildNode: function(item)
1311 return new WebInspector.HeapSnapshotDominatorObjectNode(this._dataGrid, item);
1314 _childHashForEntity: function(node)
1319 _childHashForNode: function(childNode)
1321 return childNode.snapshotNodeId;
1325 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1327 comparator: function()
1329 var sortAscending = this._dataGrid.isSortOrderAscending();
1330 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
1332 object: ["id", sortAscending, "retainedSize", false],
1333 shallowSize: ["selfSize", sortAscending, "id", true],
1334 retainedSize: ["retainedSize", sortAscending, "id", true]
1335 }[sortColumnIdentifier];
1336 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1339 __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
1345 * @extends {WebInspector.DataGridNode}
1346 * @param {!WebInspector.AllocationDataGrid} dataGrid
1347 * @param {!WebInspector.HeapSnapshotCommon.SerializedAllocationNode} data
1349 WebInspector.AllocationGridNode = function(dataGrid, data)
1351 WebInspector.DataGridNode.call(this, data, data.hasChildren);
1352 this._dataGrid = dataGrid;
1353 this._populated = false;
1356 WebInspector.AllocationGridNode.prototype = {
1357 populate: function()
1359 if (this._populated)
1361 this._populated = true;
1362 this._dataGrid.snapshot.allocationNodeCallers(this.data.id, didReceiveCallers.bind(this));
1365 * @param {!WebInspector.HeapSnapshotCommon.AllocationNodeCallers} callers
1366 * @this {WebInspector.AllocationGridNode}
1368 function didReceiveCallers(callers)
1370 var callersChain = callers.nodesWithSingleCaller;
1371 var parentNode = this;
1372 for (var i = 0; i < callersChain.length; i++) {
1373 var child = new WebInspector.AllocationGridNode(this._dataGrid, callersChain[i]);
1374 parentNode.appendChild(child);
1376 parentNode._populated = true;
1378 parentNode.expand();
1381 var callersBranch = callers.branchingCallers;
1382 callersBranch.sort(this._dataGrid._createComparator());
1383 for (var i = 0; i < callersBranch.length; i++)
1384 parentNode.appendChild(new WebInspector.AllocationGridNode(this._dataGrid, callersBranch[i]));
1393 WebInspector.DataGridNode.prototype.expand.call(this);
1394 if (this.children.length === 1)
1395 this.children[0].expand();
1400 * @param {string} columnIdentifier
1401 * @return {!Element}
1403 createCell: function(columnIdentifier)
1405 var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
1407 if (columnIdentifier !== "name")
1410 var functionInfo = this.data;
1411 if (functionInfo.scriptName) {
1412 var urlElement = this._dataGrid._linkifier.linkifyLocation(functionInfo.scriptName, functionInfo.line - 1, functionInfo.column - 1, "profile-node-file");
1413 urlElement.style.maxWidth = "75%";
1414 cell.insertBefore(urlElement, cell.firstChild);
1423 allocationNodeId: function()
1425 return this.data.id;
1428 __proto__: WebInspector.DataGridNode.prototype