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 WebInspector.HeapSnapshotGridNode.Events = {
52 PopulateComplete: "PopulateComplete"
56 * @param {!Array.<string>} fieldNames
57 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
59 WebInspector.HeapSnapshotGridNode.createComparator = function(fieldNames)
61 return /** @type {!WebInspector.HeapSnapshotCommon.ComparatorConfig} */ ({fieldName1: fieldNames[0], ascending1: fieldNames[1], fieldName2: fieldNames[2], ascending2: fieldNames[3]});
64 WebInspector.HeapSnapshotGridNode.prototype = {
66 * @return {!WebInspector.HeapSnapshotProviderProxy}
68 createProvider: function()
70 throw new Error("Needs implemented.");
74 * @return {!WebInspector.HeapSnapshotProviderProxy}
78 if (!this._providerObject)
79 this._providerObject = this.createProvider();
80 return this._providerObject;
84 * @param {string} columnIdentifier
87 createCell: function(columnIdentifier)
89 var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
90 if (this._searchMatched)
91 cell.classList.add("highlight");
97 WebInspector.DataGridNode.prototype.collapse.call(this);
98 this._dataGrid.updateVisibleNodes();
103 if (this._providerObject)
104 this._providerObject.dispose();
105 for (var node = this.children[0]; node; node = node.traverseNextNode(true, this, true))
110 _reachableFromWindow: false,
112 queryObjectContent: function(callback)
119 wasDetached: function()
121 this._dataGrid.nodeWasDetached(this);
124 _toPercentString: function(num)
126 return num.toFixed(0) + "\u2009%"; // \u2009 is a thin space.
130 * @param {number} nodePosition
131 * @return {?WebInspector.DataGridNode}
133 childForPosition: function(nodePosition)
135 var indexOfFirsChildInRange = 0;
136 for (var i = 0; i < this._retrievedChildrenRanges.length; i++) {
137 var range = this._retrievedChildrenRanges[i];
138 if (range.from <= nodePosition && nodePosition < range.to) {
139 var childIndex = indexOfFirsChildInRange + nodePosition - range.from;
140 return this.children[childIndex];
142 indexOfFirsChildInRange += range.to - range.from + 1;
147 _createValueCell: function(columnIdentifier)
149 var cell = document.createElement("td");
150 cell.className = columnIdentifier + "-column";
151 if (this.dataGrid.snapshot.totalSize !== 0) {
152 var div = document.createElement("div");
153 var valueSpan = document.createElement("span");
154 valueSpan.textContent = this.data[columnIdentifier];
155 div.appendChild(valueSpan);
156 var percentColumn = columnIdentifier + "-percent";
157 if (percentColumn in this.data) {
158 var percentSpan = document.createElement("span");
159 percentSpan.className = "percent-column";
160 percentSpan.textContent = this.data[percentColumn];
161 div.appendChild(percentSpan);
162 div.classList.add("heap-snapshot-multiple-values");
164 cell.appendChild(div);
169 populate: function(event)
173 this._populated = true;
176 * @this {WebInspector.HeapSnapshotGridNode}
180 this._populateChildren();
182 this._provider().sortAndRewind(this.comparator(), sorted.bind(this));
185 expandWithoutPopulate: function(callback)
187 // Make sure default populate won't take action.
188 this._populated = true;
190 this._provider().sortAndRewind(this.comparator(), callback);
194 * @param {?number=} fromPosition
195 * @param {?number=} toPosition
196 * @param {function()=} afterPopulate
198 _populateChildren: function(fromPosition, toPosition, afterPopulate)
200 fromPosition = fromPosition || 0;
201 toPosition = toPosition || fromPosition + this._dataGrid.defaultPopulateCount();
202 var firstNotSerializedPosition = fromPosition;
205 * @this {WebInspector.HeapSnapshotGridNode}
207 function serializeNextChunk()
209 if (firstNotSerializedPosition >= toPosition)
211 var end = Math.min(firstNotSerializedPosition + this._dataGrid.defaultPopulateCount(), toPosition);
212 this._provider().serializeItemsRange(firstNotSerializedPosition, end, childrenRetrieved.bind(this));
213 firstNotSerializedPosition = end;
217 * @this {WebInspector.HeapSnapshotGridNode}
219 function insertRetrievedChild(item, insertionIndex)
221 if (this._savedChildren) {
222 var hash = this._childHashForEntity(item);
223 if (hash in this._savedChildren) {
224 this.insertChild(this._savedChildren[hash], insertionIndex);
228 this.insertChild(this._createChildNode(item), insertionIndex);
232 * @this {WebInspector.HeapSnapshotGridNode}
234 function insertShowMoreButton(from, to, insertionIndex)
236 var button = new WebInspector.ShowMoreDataGridNode(this._populateChildren.bind(this), from, to, this._dataGrid.defaultPopulateCount());
237 this.insertChild(button, insertionIndex);
241 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
242 * @this {WebInspector.HeapSnapshotGridNode}
244 function childrenRetrieved(itemsRange)
247 var itemPosition = itemsRange.startPosition;
248 var items = itemsRange.items;
249 var insertionIndex = 0;
251 if (!this._retrievedChildrenRanges.length) {
252 if (itemsRange.startPosition > 0) {
253 this._retrievedChildrenRanges.push({from: 0, to: 0});
254 insertShowMoreButton.call(this, 0, itemsRange.startPosition, insertionIndex++);
256 this._retrievedChildrenRanges.push({from: itemsRange.startPosition, to: itemsRange.endPosition});
257 for (var i = 0, l = items.length; i < l; ++i)
258 insertRetrievedChild.call(this, items[i], insertionIndex++);
259 if (itemsRange.endPosition < itemsRange.totalLength)
260 insertShowMoreButton.call(this, itemsRange.endPosition, itemsRange.totalLength, insertionIndex++);
265 while (rangeIndex < this._retrievedChildrenRanges.length) {
266 range = this._retrievedChildrenRanges[rangeIndex];
267 if (range.to >= itemPosition) {
271 insertionIndex += range.to - range.from;
272 // Skip the button if there is one.
273 if (range.to < itemsRange.totalLength)
278 if (!found || itemsRange.startPosition < range.from) {
279 // Update previous button.
280 this.children[insertionIndex - 1].setEndPosition(itemsRange.startPosition);
281 insertShowMoreButton.call(this, itemsRange.startPosition, found ? range.from : itemsRange.totalLength, insertionIndex);
282 range = {from: itemsRange.startPosition, to: itemsRange.startPosition};
284 rangeIndex = this._retrievedChildrenRanges.length;
285 this._retrievedChildrenRanges.splice(rangeIndex, 0, range);
287 insertionIndex += itemPosition - range.from;
289 // At this point insertionIndex is always an index before button or between nodes.
290 // Also it is always true here that range.from <= itemPosition <= range.to
292 // Stretch the range right bound to include all new items.
293 while (range.to < itemsRange.endPosition) {
294 // Skip already added nodes.
295 var skipCount = range.to - itemPosition;
296 insertionIndex += skipCount;
297 itemIndex += skipCount;
298 itemPosition = range.to;
300 // We're at the position before button: ...<?node>x<button>
301 var nextRange = this._retrievedChildrenRanges[rangeIndex + 1];
302 var newEndOfRange = nextRange ? nextRange.from : itemsRange.totalLength;
303 if (newEndOfRange > itemsRange.endPosition)
304 newEndOfRange = itemsRange.endPosition;
305 while (itemPosition < newEndOfRange) {
306 insertRetrievedChild.call(this, items[itemIndex++], insertionIndex++);
309 // Merge with the next range.
310 if (nextRange && newEndOfRange === nextRange.from) {
311 range.to = nextRange.to;
312 // Remove "show next" button if there is one.
313 this.removeChild(this.children[insertionIndex]);
314 this._retrievedChildrenRanges.splice(rangeIndex + 1, 1);
316 range.to = newEndOfRange;
317 // Remove or update next button.
318 if (newEndOfRange === itemsRange.totalLength)
319 this.removeChild(this.children[insertionIndex]);
321 this.children[insertionIndex].setStartPosition(itemsRange.endPosition);
327 this._instanceCount += items.length;
328 if (firstNotSerializedPosition < toPosition) {
329 serializeNextChunk.call(this);
335 this.dispatchEventToListeners(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete);
337 serializeNextChunk.call(this);
340 _saveChildren: function()
342 this._savedChildren = null;
343 for (var i = 0, childrenCount = this.children.length; i < childrenCount; ++i) {
344 var child = this.children[i];
347 if (!this._savedChildren)
348 this._savedChildren = {};
349 this._savedChildren[this._childHashForNode(child)] = child;
355 this._dataGrid.recursiveSortingEnter();
358 * @this {WebInspector.HeapSnapshotGridNode}
362 this._saveChildren();
363 this.removeChildren();
364 this._retrievedChildrenRanges = [];
367 * @this {WebInspector.HeapSnapshotGridNode}
369 function afterPopulate()
371 for (var i = 0, l = this.children.length; i < l; ++i) {
372 var child = this.children[i];
376 this._dataGrid.recursiveSortingLeave();
378 var instanceCount = this._instanceCount;
379 this._instanceCount = 0;
380 this._populateChildren(0, instanceCount, afterPopulate.bind(this));
383 this._provider().sortAndRewind(this.comparator(), afterSort.bind(this));
386 __proto__: WebInspector.DataGridNode.prototype
392 * @extends {WebInspector.HeapSnapshotGridNode}
393 * @param {!WebInspector.HeapSnapshotSortableDataGrid} tree
395 WebInspector.HeapSnapshotGenericObjectNode = function(tree, node)
397 this.snapshotNodeIndex = 0;
398 WebInspector.HeapSnapshotGridNode.call(this, tree, false);
399 // node is null for DataGrid root nodes.
402 this._name = node.name;
403 this._type = node.type;
404 this._distance = node.distance;
405 this._shallowSize = node.selfSize;
406 this._retainedSize = node.retainedSize;
407 this.snapshotNodeId = node.id;
408 this.snapshotNodeIndex = node.nodeIndex;
409 if (this._type === "string")
410 this._reachableFromWindow = true;
411 else if (this._type === "object" && this._name.startsWith("Window")) {
412 this._name = this.shortenWindowURL(this._name, false);
413 this._reachableFromWindow = true;
414 } else if (node.canBeQueried)
415 this._reachableFromWindow = true;
416 if (node.detachedDOMTreeNode)
417 this.detachedDOMTreeNode = true;
420 WebInspector.HeapSnapshotGenericObjectNode.prototype = {
422 * @param {string} columnIdentifier
425 createCell: function(columnIdentifier)
427 var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : this._createObjectCell();
428 if (this._searchMatched)
429 cell.classList.add("highlight");
433 _createObjectCell: function()
435 var cell = document.createElement("td");
436 cell.className = "object-column";
437 var div = document.createElement("div");
438 div.className = "source-code event-properties";
439 div.style.overflow = "visible";
441 var data = this.data["object"];
442 if (this._prefixObjectCell)
443 this._prefixObjectCell(div, data);
445 var valueSpan = document.createElement("span");
446 valueSpan.className = "value console-formatted-" + data.valueStyle;
447 valueSpan.textContent = data.value;
448 div.appendChild(valueSpan);
450 var idSpan = document.createElement("span");
451 idSpan.className = "console-formatted-id";
452 idSpan.textContent = " @" + data["nodeId"];
453 div.appendChild(idSpan);
455 if (this._postfixObjectCell)
456 this._postfixObjectCell(div, data);
458 cell.appendChild(div);
459 cell.classList.add("disclosure");
461 cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px");
462 cell.heapSnapshotNode = this;
468 var data = this._emptyData();
470 var value = this._name;
471 var valueStyle = "object";
472 switch (this._type) {
473 case "concatenated string":
475 value = "\"" + value + "\"";
476 valueStyle = "string";
479 value = "/" + value + "/";
480 valueStyle = "string";
483 value = "function" + (value ? " " : "") + value + "()";
484 valueStyle = "function";
487 valueStyle = "number";
499 if (this._reachableFromWindow)
500 valueStyle += " highlight";
501 if (value === "Object")
503 if (this.detachedDOMTreeNode)
504 valueStyle += " detached-dom-tree-node";
505 data["object"] = { valueStyle: valueStyle, value: value, nodeId: this.snapshotNodeId };
507 data["distance"] = this._distance;
508 data["shallowSize"] = Number.withThousandsSeparator(this._shallowSize);
509 data["retainedSize"] = Number.withThousandsSeparator(this._retainedSize);
510 data["shallowSize-percent"] = this._toPercentString(this._shallowSizePercent);
511 data["retainedSize-percent"] = this._toPercentString(this._retainedSizePercent);
513 return this._enhanceData ? this._enhanceData(data) : data;
516 queryObjectContent: function(callback, objectGroupName)
519 * @param {?Protocol.Error} error
520 * @param {!RuntimeAgent.RemoteObject} object
522 function formatResult(error, object)
524 if (!error && object.type)
525 callback(WebInspector.RemoteObject.fromPayload(object), !!error);
527 callback(WebInspector.RemoteObject.fromPrimitiveValue(WebInspector.UIString("Preview is not available")));
530 if (this._type === "string")
531 callback(WebInspector.RemoteObject.fromPrimitiveValue(this._name));
533 HeapProfilerAgent.getObjectByHeapObjectId(String(this.snapshotNodeId), objectGroupName, formatResult);
536 get _retainedSizePercent()
538 return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0;
541 get _shallowSizePercent()
543 return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0;
546 updateHasChildren: function()
549 * @this {WebInspector.HeapSnapshotGenericObjectNode}
551 function isEmptyCallback(isEmpty)
553 this.hasChildren = !isEmpty;
555 this._provider().isEmpty(isEmptyCallback.bind(this));
559 * @param {string} fullName
560 * @param {boolean} hasObjectId
563 shortenWindowURL: function(fullName, hasObjectId)
565 var startPos = fullName.indexOf("/");
566 var endPos = hasObjectId ? fullName.indexOf("@") : fullName.length;
567 if (startPos !== -1 && endPos !== -1) {
568 var fullURL = fullName.substring(startPos + 1, endPos).trimLeft();
569 var url = fullURL.trimURL();
571 url = url.trimMiddle(40);
572 return fullName.substr(0, startPos + 2) + url + fullName.substr(endPos);
577 __proto__: WebInspector.HeapSnapshotGridNode.prototype
582 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
583 * @param {!WebInspector.HeapSnapshotSortableDataGrid} tree
584 * @param {boolean} isFromBaseSnapshot
586 WebInspector.HeapSnapshotObjectNode = function(tree, isFromBaseSnapshot, edge, parentGridNode)
588 WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, edge.node);
589 this._referenceName = edge.name;
590 this._referenceType = edge.type;
591 this._distance = edge.distance;
592 this.showRetainingEdges = tree.showRetainingEdges;
593 this._isFromBaseSnapshot = isFromBaseSnapshot;
595 this._parentGridNode = parentGridNode;
596 this._cycledWithAncestorGridNode = this._findAncestorWithSameSnapshotNodeId();
597 if (!this._cycledWithAncestorGridNode)
598 this.updateHasChildren();
601 WebInspector.HeapSnapshotObjectNode.prototype = {
603 * @return {!WebInspector.HeapSnapshotProviderProxy}
605 createProvider: function()
607 var tree = this._dataGrid;
608 var showHiddenData = WebInspector.settings.showAdvancedHeapSnapshotProperties.get();
609 var snapshot = this._isFromBaseSnapshot ? tree.baseSnapshot : tree.snapshot;
610 if (this.showRetainingEdges)
611 return snapshot.createRetainingEdgesProvider(this.snapshotNodeIndex, showHiddenData);
613 return snapshot.createEdgesProvider(this.snapshotNodeIndex, showHiddenData);
616 _findAncestorWithSameSnapshotNodeId: function()
618 var ancestor = this._parentGridNode;
620 if (ancestor.snapshotNodeId === this.snapshotNodeId)
622 ancestor = ancestor._parentGridNode;
627 _createChildNode: function(item)
629 return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._isFromBaseSnapshot, item, this);
632 _childHashForEntity: function(edge)
634 var prefix = this.showRetainingEdges ? edge.node.id + "#" : "";
635 return prefix + edge.type + "#" + edge.name;
638 _childHashForNode: function(childNode)
640 var prefix = this.showRetainingEdges ? childNode.snapshotNodeId + "#" : "";
641 return prefix + childNode._referenceType + "#" + childNode._referenceName;
645 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
647 comparator: function()
649 var sortAscending = this._dataGrid.isSortOrderAscending();
650 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
652 object: ["!edgeName", sortAscending, "retainedSize", false],
653 count: ["!edgeName", true, "retainedSize", false],
654 shallowSize: ["selfSize", sortAscending, "!edgeName", true],
655 retainedSize: ["retainedSize", sortAscending, "!edgeName", true],
656 distance: ["distance", sortAscending, "_name", true]
657 }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
658 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
661 _emptyData: function()
663 return { count: "", addedCount: "", removedCount: "", countDelta: "", addedSize: "", removedSize: "", sizeDelta: "" };
666 _enhanceData: function(data)
668 var name = this._referenceName;
669 if (name === "") name = "(empty)";
670 var nameClass = "name";
671 switch (this._referenceType) {
673 nameClass = "console-formatted-number";
678 nameClass = "console-formatted-null";
681 name = "[" + name + "]";
684 data["object"].nameClass = nameClass;
685 data["object"].name = name;
686 data["distance"] = this._distance;
690 _prefixObjectCell: function(div, data)
692 if (this._cycledWithAncestorGridNode)
693 div.className += " cycled-ancessor-node";
695 var nameSpan = document.createElement("span");
696 nameSpan.className = data.nameClass;
697 nameSpan.textContent = data.name;
698 div.appendChild(nameSpan);
700 var separatorSpan = document.createElement("span");
701 separatorSpan.className = "grayed";
702 separatorSpan.textContent = this.showRetainingEdges ? " in " : " :: ";
703 div.appendChild(separatorSpan);
706 __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
711 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
713 WebInspector.HeapSnapshotInstanceNode = function(tree, baseSnapshot, snapshot, node)
715 WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node);
716 this._baseSnapshotOrSnapshot = baseSnapshot || snapshot;
717 this._isDeletedNode = !!baseSnapshot;
718 this.updateHasChildren();
721 WebInspector.HeapSnapshotInstanceNode.prototype = {
723 * @return {!WebInspector.HeapSnapshotProviderProxy}
725 createProvider: function()
727 var showHiddenData = WebInspector.settings.showAdvancedHeapSnapshotProperties.get();
728 return this._baseSnapshotOrSnapshot.createEdgesProvider(
729 this.snapshotNodeIndex,
733 _createChildNode: function(item)
735 return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._isDeletedNode, item, null);
738 _childHashForEntity: function(edge)
740 return edge.type + "#" + edge.name;
743 _childHashForNode: function(childNode)
745 return childNode._referenceType + "#" + childNode._referenceName;
749 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
751 comparator: function()
753 var sortAscending = this._dataGrid.isSortOrderAscending();
754 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
756 object: ["!edgeName", sortAscending, "retainedSize", false],
757 distance: ["distance", sortAscending, "retainedSize", false],
758 count: ["!edgeName", true, "retainedSize", false],
759 addedSize: ["selfSize", sortAscending, "!edgeName", true],
760 removedSize: ["selfSize", sortAscending, "!edgeName", true],
761 shallowSize: ["selfSize", sortAscending, "!edgeName", true],
762 retainedSize: ["retainedSize", sortAscending, "!edgeName", true]
763 }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
764 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
767 _emptyData: function()
769 return {count: "", countDelta: "", sizeDelta: ""};
772 _enhanceData: function(data)
774 if (this._isDeletedNode) {
775 data["addedCount"] = "";
776 data["addedSize"] = "";
777 data["removedCount"] = "\u2022";
778 data["removedSize"] = Number.withThousandsSeparator(this._shallowSize);
780 data["addedCount"] = "\u2022";
781 data["addedSize"] = Number.withThousandsSeparator(this._shallowSize);
782 data["removedCount"] = "";
783 data["removedSize"] = "";
790 return this._isDeletedNode;
793 __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
798 * @param {string} className
799 * @param {!WebInspector.HeapSnapshotCommon.Aggregate} aggregate
800 * @param {string} aggregatesKey
801 * @extends {WebInspector.HeapSnapshotGridNode}
803 WebInspector.HeapSnapshotConstructorNode = function(tree, className, aggregate, aggregatesKey)
805 WebInspector.HeapSnapshotGridNode.call(this, tree, aggregate.count > 0);
806 this._name = className;
807 this._aggregatesKey = aggregatesKey;
808 this._distance = aggregate.distance;
809 this._count = aggregate.count;
810 this._shallowSize = aggregate.self;
811 this._retainedSize = aggregate.maxRet;
814 WebInspector.HeapSnapshotConstructorNode.prototype = {
817 * @return {!WebInspector.HeapSnapshotProviderProxy}
819 createProvider: function()
821 return this._dataGrid.snapshot.createNodesProviderForClass(this._name, this._aggregatesKey)
825 * @param {number} snapshotObjectId
826 * @param {function(boolean)} callback
828 revealNodeBySnapshotObjectId: function(snapshotObjectId, callback)
831 * @this {WebInspector.HeapSnapshotConstructorNode}
835 this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
839 * @this {WebInspector.HeapSnapshotConstructorNode}
841 function didGetNodePosition(nodePosition)
843 if (nodePosition === -1) {
847 this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
852 * @this {WebInspector.HeapSnapshotConstructorNode}
854 function didPopulateChildren(nodePosition)
856 var indexOfFirsChildInRange = 0;
857 for (var i = 0; i < this._retrievedChildrenRanges.length; i++) {
858 var range = this._retrievedChildrenRanges[i];
859 if (range.from <= nodePosition && nodePosition < range.to) {
860 var childIndex = indexOfFirsChildInRange + nodePosition - range.from;
861 var instanceNode = this.children[childIndex];
862 this._dataGrid.highlightNode(/** @type {!WebInspector.HeapSnapshotGridNode} */ (instanceNode));
866 indexOfFirsChildInRange += range.to - range.from + 1;
871 this.expandWithoutPopulate(didExpand.bind(this));
875 * @param {string} columnIdentifier
878 createCell: function(columnIdentifier)
880 var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
881 if (this._searchMatched)
882 cell.classList.add("highlight");
886 _createChildNode: function(item)
888 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, null, this._dataGrid.snapshot, item);
892 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
894 comparator: function()
896 var sortAscending = this._dataGrid.isSortOrderAscending();
897 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
899 object: ["id", sortAscending, "retainedSize", false],
900 distance: ["distance", sortAscending, "retainedSize", false],
901 count: ["id", true, "retainedSize", false],
902 shallowSize: ["selfSize", sortAscending, "id", true],
903 retainedSize: ["retainedSize", sortAscending, "id", true]
904 }[sortColumnIdentifier];
905 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
908 _childHashForEntity: function(node)
913 _childHashForNode: function(childNode)
915 return childNode.snapshotNodeId;
920 var data = { object: this._name };
921 data["count"] = Number.withThousandsSeparator(this._count);
922 data["distance"] = this._distance;
923 data["shallowSize"] = Number.withThousandsSeparator(this._shallowSize);
924 data["retainedSize"] = Number.withThousandsSeparator(this._retainedSize);
925 data["count-percent"] = this._toPercentString(this._countPercent);
926 data["shallowSize-percent"] = this._toPercentString(this._shallowSizePercent);
927 data["retainedSize-percent"] = this._toPercentString(this._retainedSizePercent);
933 return this._count / this.dataGrid.snapshot.nodeCount * 100.0;
936 get _retainedSizePercent()
938 return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0;
941 get _shallowSizePercent()
943 return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0;
946 __proto__: WebInspector.HeapSnapshotGridNode.prototype
952 * @extends {WebInspector.HeapSnapshotProviderProxy}
953 * @param {!WebInspector.HeapSnapshotProviderProxy} addedNodesProvider
954 * @param {!WebInspector.HeapSnapshotProviderProxy} deletedNodesProvider
956 WebInspector.HeapSnapshotDiffNodesProvider = function(addedNodesProvider, deletedNodesProvider, addedCount, removedCount)
958 this._addedNodesProvider = addedNodesProvider;
959 this._deletedNodesProvider = deletedNodesProvider;
960 this._addedCount = addedCount;
961 this._removedCount = removedCount;
964 WebInspector.HeapSnapshotDiffNodesProvider.prototype = {
967 this._addedNodesProvider.dispose();
968 this._deletedNodesProvider.dispose();
971 isEmpty: function(callback)
977 * @param {number} beginPosition
978 * @param {number} endPosition
979 * @param {!function(!WebInspector.HeapSnapshotCommon.ItemsRange)} callback
981 serializeItemsRange: function(beginPosition, endPosition, callback)
984 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} items
985 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
987 function didReceiveAllItems(items)
989 items.totalLength = this._addedCount + this._removedCount;
994 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} addedItems
995 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
996 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
998 function didReceiveDeletedItems(addedItems, itemsRange)
1000 var items = itemsRange.items;
1001 if (!addedItems.items.length)
1002 addedItems.startPosition = this._addedCount + itemsRange.startPosition;
1003 for (var i = 0; i < items.length; i++) {
1004 items[i].isAddedNotRemoved = false;
1005 addedItems.items.push(items[i]);
1007 addedItems.endPosition = this._addedCount + itemsRange.endPosition;
1008 didReceiveAllItems.call(this, addedItems);
1012 * @param {!WebInspector.HeapSnapshotCommon.ItemsRange} itemsRange
1013 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1015 function didReceiveAddedItems(itemsRange)
1017 var items = itemsRange.items;
1018 for (var i = 0; i < items.length; i++)
1019 items[i].isAddedNotRemoved = true;
1020 if (itemsRange.endPosition < endPosition)
1021 return this._deletedNodesProvider.serializeItemsRange(0, endPosition - itemsRange.endPosition, didReceiveDeletedItems.bind(this, itemsRange));
1023 itemsRange.totalLength = this._addedCount + this._removedCount;
1024 didReceiveAllItems.call(this, itemsRange);
1027 if (beginPosition < this._addedCount) {
1028 this._addedNodesProvider.serializeItemsRange(beginPosition, endPosition, didReceiveAddedItems.bind(this));
1030 var emptyRange = new WebInspector.HeapSnapshotCommon.ItemsRange(0, 0, 0, []);
1031 this._deletedNodesProvider.serializeItemsRange(beginPosition - this._addedCount, endPosition - this._addedCount, didReceiveDeletedItems.bind(this, emptyRange));
1035 sortAndRewind: function(comparator, callback)
1038 * @this {WebInspector.HeapSnapshotDiffNodesProvider}
1040 function afterSort()
1042 this._deletedNodesProvider.sortAndRewind(comparator, callback);
1044 this._addedNodesProvider.sortAndRewind(comparator, afterSort.bind(this));
1047 __proto__: WebInspector.HeapSnapshotProviderProxy.prototype
1052 * @param {string} className
1053 * @param {!WebInspector.HeapSnapshotCommon.DiffForClass} diffForClass
1054 * @extends {WebInspector.HeapSnapshotGridNode}
1056 WebInspector.HeapSnapshotDiffNode = function(tree, className, diffForClass)
1058 WebInspector.HeapSnapshotGridNode.call(this, tree, true);
1059 this._name = className;
1061 this._addedCount = diffForClass.addedCount;
1062 this._removedCount = diffForClass.removedCount;
1063 this._countDelta = diffForClass.countDelta;
1064 this._addedSize = diffForClass.addedSize;
1065 this._removedSize = diffForClass.removedSize;
1066 this._sizeDelta = diffForClass.sizeDelta;
1067 this._deletedIndexes = diffForClass.deletedIndexes;
1070 WebInspector.HeapSnapshotDiffNode.prototype = {
1073 * @return {!WebInspector.HeapSnapshotDiffNodesProvider}
1075 createProvider: function()
1077 var tree = this._dataGrid;
1078 return new WebInspector.HeapSnapshotDiffNodesProvider(
1079 tree.snapshot.createAddedNodesProvider(tree.baseSnapshot.uid, this._name),
1080 tree.baseSnapshot.createDeletedNodesProvider(this._deletedIndexes),
1082 this._removedCount);
1085 _createChildNode: function(item)
1087 if (item.isAddedNotRemoved)
1088 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, null, this._dataGrid.snapshot, item);
1090 return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.baseSnapshot, null, item);
1093 _childHashForEntity: function(node)
1098 _childHashForNode: function(childNode)
1100 return childNode.snapshotNodeId;
1104 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1106 comparator: function()
1108 var sortAscending = this._dataGrid.isSortOrderAscending();
1109 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
1111 object: ["id", sortAscending, "selfSize", false],
1112 addedCount: ["selfSize", sortAscending, "id", true],
1113 removedCount: ["selfSize", sortAscending, "id", true],
1114 countDelta: ["selfSize", sortAscending, "id", true],
1115 addedSize: ["selfSize", sortAscending, "id", true],
1116 removedSize: ["selfSize", sortAscending, "id", true],
1117 sizeDelta: ["selfSize", sortAscending, "id", true]
1118 }[sortColumnIdentifier];
1119 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1122 _signForDelta: function(delta)
1129 return "\u2212"; // Math minus sign, same width as plus.
1134 var data = {object: this._name};
1136 data["addedCount"] = Number.withThousandsSeparator(this._addedCount);
1137 data["removedCount"] = Number.withThousandsSeparator(this._removedCount);
1138 data["countDelta"] = this._signForDelta(this._countDelta) + Number.withThousandsSeparator(Math.abs(this._countDelta));
1139 data["addedSize"] = Number.withThousandsSeparator(this._addedSize);
1140 data["removedSize"] = Number.withThousandsSeparator(this._removedSize);
1141 data["sizeDelta"] = this._signForDelta(this._sizeDelta) + Number.withThousandsSeparator(Math.abs(this._sizeDelta));
1146 __proto__: WebInspector.HeapSnapshotGridNode.prototype
1152 * @extends {WebInspector.HeapSnapshotGenericObjectNode}
1154 WebInspector.HeapSnapshotDominatorObjectNode = function(tree, node)
1156 WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node);
1157 this.updateHasChildren();
1160 WebInspector.HeapSnapshotDominatorObjectNode.prototype = {
1163 * @return {!WebInspector.HeapSnapshotProviderProxy}
1165 createProvider: function()
1167 return this._dataGrid.snapshot.createNodesProviderForDominator(this.snapshotNodeIndex);
1171 * @param {number} snapshotObjectId
1172 * @param {function(?WebInspector.DataGridNode)} callback
1174 retrieveChildBySnapshotObjectId: function(snapshotObjectId, callback)
1177 * @this {WebInspector.HeapSnapshotDominatorObjectNode}
1179 function didExpand()
1181 this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
1185 * @this {WebInspector.HeapSnapshotDominatorObjectNode}
1187 function didGetNodePosition(nodePosition)
1189 if (nodePosition === -1) {
1193 this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
1197 * @this {WebInspector.HeapSnapshotDominatorObjectNode}
1199 function didPopulateChildren(nodePosition)
1201 var child = this.childForPosition(nodePosition);
1205 // Make sure hasChildren flag is updated before expanding this node as updateHasChildren response
1206 // may not have been received yet.
1207 this.hasChildren = true;
1208 this.expandWithoutPopulate(didExpand.bind(this));
1211 _createChildNode: function(item)
1213 return new WebInspector.HeapSnapshotDominatorObjectNode(this._dataGrid, item);
1216 _childHashForEntity: function(node)
1221 _childHashForNode: function(childNode)
1223 return childNode.snapshotNodeId;
1227 * @return {!WebInspector.HeapSnapshotCommon.ComparatorConfig}
1229 comparator: function()
1231 var sortAscending = this._dataGrid.isSortOrderAscending();
1232 var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
1234 object: ["id", sortAscending, "retainedSize", false],
1235 shallowSize: ["selfSize", sortAscending, "id", true],
1236 retainedSize: ["retainedSize", sortAscending, "id", true]
1237 }[sortColumnIdentifier];
1238 return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
1241 _emptyData: function()
1246 __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype