1 /* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 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 13 * distribution. 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. 17 * 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. 29 */ 30 31 WebInspector.HeapSnapshotGridNode = function(tree, hasChildren) 32 { 33 WebInspector.DataGridNode.call(this, null, hasChildren); 34 this._defaultPopulateCount = tree._defaultPopulateCount; 35 this._provider = null; 36 this.addEventListener("populate", this._populate, this); 37 } 38 39 WebInspector.HeapSnapshotGridNode.prototype = { 40 createCell: function(columnIdentifier) 41 { 42 var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier); 43 if (this._searchMatched) 44 cell.addStyleClass("highlight"); 45 return cell; 46 }, 47 48 _populate: function(event) 49 { 50 WebInspector.PleaseWaitMessage.prototype.startAction(this.dataGrid.element, doPopulate.bind(this)); 51 52 function doPopulate() 53 { 54 this.removeEventListener("populate", this._populate, this); 55 function sorted(ignored) 56 { 57 this.populateChildren(); 58 } 59 this._provider.sortAndRewind(this.comparator(), sorted.bind(this)); 60 } 61 }, 62 63 populateChildren: function(provider, howMany, atIndex, afterPopulate, suppressNotifyAboutCompletion) 64 { 65 if (!howMany && provider) { 66 howMany = provider.instanceCount; 67 provider.instanceCount = 0; 68 } 69 provider = provider || this._provider; 70 if (!("instanceCount" in provider)) 71 provider.instanceCount = 0; 72 howMany = howMany || this._defaultPopulateCount; 73 atIndex = atIndex || this.children.length; 74 var haveSavedChildren = !!this._savedChildren; 75 if (haveSavedChildren) { 76 haveSavedChildren = false; 77 for (var c in this._savedChildren) { 78 haveSavedChildren = true; 79 break; 80 } 81 } 82 83 function childrenRetrieved(items, hasNext, length) 84 { 85 for (var i = 0, l = items.length; i < l; ++i) { 86 var item = items[i]; 87 if (haveSavedChildren) { 88 var hash = this._childHashForEntity(item); 89 if (hash in this._savedChildren) { 90 this.insertChild(this._savedChildren[hash], atIndex++); 91 continue; 92 } 93 } 94 this.insertChild(this._createChildNode(item, provider), atIndex++); 95 } 96 provider.instanceCount += items.length; 97 98 if (hasNext) 99 this.insertChild(new WebInspector.ShowMoreDataGridNode(this.populateChildren.bind(this, provider), this._defaultPopulateCount, length), atIndex++); 100 if (afterPopulate) 101 afterPopulate(); 102 if (!suppressNotifyAboutCompletion) { 103 function notify() 104 { 105 this.dispatchEventToListeners("populate complete"); 106 } 107 setTimeout(notify.bind(this), 0); 108 } 109 } 110 provider.getNextItems(howMany, childrenRetrieved.bind(this)); 111 }, 112 113 _saveChildren: function() 114 { 115 this._savedChildren = {}; 116 for (var i = 0, childrenCount = this.children.length; i < childrenCount; ++i) { 117 var child = this.children[i]; 118 if (child.expanded) 119 this._savedChildren[this._childHashForNode(child)] = child; 120 } 121 }, 122 123 sort: function() 124 { 125 function doSort() 126 { 127 function afterSort(sorted) 128 { 129 if (!sorted) 130 return; 131 this._saveChildren(); 132 this.removeChildren(); 133 134 function afterPopulate() 135 { 136 for (var i = 0, l = this.children.length; i < l; ++i) { 137 var child = this.children[i]; 138 if (child.expanded) 139 child.sort(); 140 } 141 this.dataGrid.dispatchEventToListeners("sorting complete"); 142 } 143 this.populateChildren(this._provider, null, null, afterPopulate.bind(this)); 144 } 145 this._provider.sortAndRewind(this.comparator(), afterSort.bind(this)); 146 } 147 this.dataGrid.dispatchEventToListeners("start sorting"); 148 WebInspector.PleaseWaitMessage.prototype.startAction(this.dataGrid.element, doSort.bind(this)); 149 } 150 }; 151 152 WebInspector.HeapSnapshotGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; 153 154 WebInspector.HeapSnapshotGenericObjectNode = function(tree, node) 155 { 156 WebInspector.HeapSnapshotGridNode.call(this, tree, false); 157 this._name = node.name; 158 this._type = node.type; 159 this._shallowSize = node.selfSize; 160 this._retainedSize = node.retainedSize; 161 this.snapshotNodeId = node.id; 162 this.snapshotNodeIndex = node.nodeIndex; 163 }; 164 165 WebInspector.HeapSnapshotGenericObjectNode.prototype = { 166 createCell: function(columnIdentifier) 167 { 168 var cell = columnIdentifier !== "object" ? WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier) : this._createObjectCell(); 169 if (this._searchMatched) 170 cell.addStyleClass("highlight"); 171 return cell; 172 }, 173 174 _createObjectCell: function() 175 { 176 var cell = document.createElement("td"); 177 cell.className = "object-column"; 178 var div = document.createElement("div"); 179 div.className = "source-code event-properties"; 180 div.style.overflow = "hidden"; 181 var data = this.data["object"]; 182 if (this._prefixObjectCell) 183 this._prefixObjectCell(div, data); 184 var valueSpan = document.createElement("span"); 185 valueSpan.className = "value console-formatted-" + data.valueStyle; 186 valueSpan.textContent = data.value; 187 div.appendChild(valueSpan); 188 cell.appendChild(div); 189 cell.addStyleClass("disclosure"); 190 if (this.depth) 191 cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px"); 192 return cell; 193 }, 194 195 get _countPercent() 196 { 197 return this._count / this.dataGrid.snapshot.nodeCount * 100.0; 198 }, 199 200 get data() 201 { 202 var data = this._emptyData(); 203 204 var value = this._name; 205 var valueStyle = "object"; 206 switch (this._type) { 207 case "string": 208 value = "\"" + value + "\""; 209 valueStyle = "string"; 210 break; 211 case "regexp": 212 value = "/" + value + "/"; 213 valueStyle = "string"; 214 break; 215 case "closure": 216 value = "function " + value + "()"; 217 valueStyle = "function"; 218 break; 219 case "number": 220 valueStyle = "number"; 221 break; 222 case "hidden": 223 valueStyle = "null"; 224 break; 225 case "array": 226 value += "[]"; 227 break; 228 }; 229 data["object"] = { valueStyle: valueStyle, value: value + " @" + this.snapshotNodeId }; 230 231 var view = this.dataGrid.snapshotView; 232 data["shallowSize"] = view.showShallowSizeAsPercent ? WebInspector.UIString("%.2f%%", this._shallowSizePercent) : Number.bytesToString(this._shallowSize); 233 data["retainedSize"] = view.showRetainedSizeAsPercent ? WebInspector.UIString("%.2f%%", this._retainedSizePercent) : Number.bytesToString(this._retainedSize); 234 235 return this._enhanceData ? this._enhanceData(data) : data; 236 }, 237 238 get _retainedSizePercent() 239 { 240 return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0; 241 }, 242 243 get _shallowSizePercent() 244 { 245 return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0; 246 }, 247 248 _updateHasChildren: function() 249 { 250 function isEmptyCallback(isEmpty) 251 { 252 this.hasChildren = !isEmpty; 253 } 254 this._provider.isEmpty(isEmptyCallback.bind(this)); 255 } 256 } 257 258 WebInspector.HeapSnapshotGenericObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype; 259 260 WebInspector.HeapSnapshotObjectNode = function(tree, edge) 261 { 262 WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, edge.node); 263 this._referenceName = edge.name; 264 this._referenceType = edge.type; 265 this._provider = this._createProvider(tree.snapshot, edge.nodeIndex); 266 this._updateHasChildren(); 267 } 268 269 WebInspector.HeapSnapshotObjectNode.prototype = { 270 _createChildNode: function(item) 271 { 272 return new WebInspector.HeapSnapshotObjectNode(this.dataGrid, item); 273 }, 274 275 _createProvider: function(snapshot, nodeIndex) 276 { 277 var showHiddenData = WebInspector.DetailedHeapshotView.prototype.showHiddenData; 278 return snapshot.createEdgesProvider( 279 nodeIndex, 280 function(edge) { 281 return !edge.isInvisible 282 && (showHiddenData || (!edge.isHidden && !edge.node.isHidden)); 283 }); 284 }, 285 286 _childHashForEntity: function(edge) 287 { 288 return edge.type + "#" + edge.name; 289 }, 290 291 _childHashForNode: function(childNode) 292 { 293 return childNode._referenceType + "#" + childNode._referenceName; 294 }, 295 296 comparator: function() 297 { 298 var sortAscending = this.dataGrid.sortOrder === "ascending"; 299 var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; 300 var sortFields = { 301 object: ["!edgeName", sortAscending, "retainedSize", false], 302 count: ["!edgeName", true, "retainedSize", false], 303 shallowSize: ["selfSize", sortAscending, "!edgeName", true], 304 retainedSize: ["retainedSize", sortAscending, "!edgeName", true] 305 }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false]; 306 return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields); 307 }, 308 309 _emptyData: function() 310 { 311 return {count:"", addedCount: "", removedCount: "", countDelta:"", addedSize: "", removedSize: "", sizeDelta: ""}; 312 }, 313 314 _enhanceData: function(data) 315 { 316 var name = this._referenceName; 317 if (name === "") name = "(empty)"; 318 var nameClass = "name"; 319 switch (this._referenceType) { 320 case "context": 321 nameClass = "console-formatted-number"; 322 break; 323 case "internal": 324 case "hidden": 325 nameClass = "console-formatted-null"; 326 break; 327 } 328 data["object"].nameClass = nameClass; 329 data["object"].name = name; 330 return data; 331 }, 332 333 _prefixObjectCell: function(div, data) 334 { 335 var nameSpan = document.createElement("span"); 336 nameSpan.className = data.nameClass; 337 nameSpan.textContent = data.name; 338 var separatorSpan = document.createElement("span"); 339 separatorSpan.className = "separator"; 340 separatorSpan.textContent = ": "; 341 div.appendChild(nameSpan); 342 div.appendChild(separatorSpan); 343 } 344 } 345 346 WebInspector.HeapSnapshotObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype; 347 348 WebInspector.HeapSnapshotInstanceNode = function(tree, baseSnapshot, snapshot, node) 349 { 350 WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node); 351 this._isDeletedNode = !!baseSnapshot; 352 this._provider = this._createProvider(baseSnapshot || snapshot, node.nodeIndex); 353 this._updateHasChildren(); 354 }; 355 356 WebInspector.HeapSnapshotInstanceNode.prototype = { 357 _createChildNode: function(item) 358 { 359 return new WebInspector.HeapSnapshotObjectNode(this.dataGrid, item); 360 }, 361 362 _createProvider: function(snapshot, nodeIndex) 363 { 364 var showHiddenData = WebInspector.DetailedHeapshotView.prototype.showHiddenData; 365 return snapshot.createEdgesProvider( 366 nodeIndex, 367 function(edge) { 368 return !edge.isInvisible 369 && (showHiddenData || (!edge.isHidden && !edge.node.isHidden)); 370 }); 371 }, 372 373 _childHashForEntity: function(edge) 374 { 375 return edge.type + "#" + edge.name; 376 }, 377 378 _childHashForNode: function(childNode) 379 { 380 return childNode._referenceType + "#" + childNode._referenceName; 381 }, 382 383 comparator: function() 384 { 385 var sortAscending = this.dataGrid.sortOrder === "ascending"; 386 var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; 387 var sortFields = { 388 object: ["!edgeName", sortAscending, "retainedSize", false], 389 count: ["!edgeName", true, "retainedSize", false], 390 addedSize: ["selfSize", sortAscending, "!edgeName", true], 391 removedSize: ["selfSize", sortAscending, "!edgeName", true], 392 shallowSize: ["selfSize", sortAscending, "!edgeName", true], 393 retainedSize: ["retainedSize", sortAscending, "!edgeName", true] 394 }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false]; 395 return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields); 396 }, 397 398 _emptyData: function() 399 { 400 return {count:"", countDelta:"", sizeDelta: ""}; 401 }, 402 403 _enhanceData: function(data) 404 { 405 if (this._isDeletedNode) { 406 data["addedCount"] = ""; 407 data["addedSize"] = ""; 408 data["removedCount"] = "\u2022"; 409 data["removedSize"] = Number.bytesToString(this._shallowSize); 410 } else { 411 data["addedCount"] = "\u2022"; 412 data["addedSize"] = Number.bytesToString(this._shallowSize); 413 data["removedCount"] = ""; 414 data["removedSize"] = ""; 415 } 416 return data; 417 } 418 } 419 420 WebInspector.HeapSnapshotInstanceNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype; 421 422 WebInspector.HeapSnapshotConstructorNode = function(tree, className, aggregate) 423 { 424 WebInspector.HeapSnapshotGridNode.call(this, tree, aggregate.count > 0); 425 this._name = className; 426 this._count = aggregate.count; 427 this._shallowSize = aggregate.self; 428 this._retainedSize = aggregate.maxRet; 429 this._provider = this._createNodesProvider(tree.snapshot, aggregate.type, className); 430 } 431 432 WebInspector.HeapSnapshotConstructorNode.prototype = { 433 _createChildNode: function(item) 434 { 435 return new WebInspector.HeapSnapshotInstanceNode(this.dataGrid, null, this.dataGrid.snapshot, item); 436 }, 437 438 _createNodesProvider: function(snapshot, nodeType, nodeClassName) 439 { 440 return snapshot.createNodesProvider( 441 function (node) { 442 return node.type === nodeType 443 && (nodeClassName === null || node.className === nodeClassName); 444 }); 445 }, 446 447 comparator: function() 448 { 449 var sortAscending = this.dataGrid.sortOrder === "ascending"; 450 var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; 451 var sortFields = { 452 object: ["id", sortAscending, "retainedSize", false], 453 count: ["id", true, "retainedSize", false], 454 shallowSize: ["selfSize", sortAscending, "id", true], 455 retainedSize: ["retainedSize", sortAscending, "id", true] 456 }[sortColumnIdentifier]; 457 return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields); 458 }, 459 460 _childHashForEntity: function(node) 461 { 462 return node.id; 463 }, 464 465 _childHashForNode: function(childNode) 466 { 467 return childNode.snapshotNodeId; 468 }, 469 470 get data() 471 { 472 var data = {object: this._name, count: this._count}; 473 var view = this.dataGrid.snapshotView; 474 data["count"] = view.showCountAsPercent ? WebInspector.UIString("%.2f%%", this._countPercent) : this._count; 475 data["shallowSize"] = view.showShallowSizeAsPercent ? WebInspector.UIString("%.2f%%", this._shallowSizePercent) : Number.bytesToString(this._shallowSize); 476 data["retainedSize"] = "> " + (view.showRetainedSizeAsPercent ? WebInspector.UIString("%.2f%%", this._retainedSizePercent) : Number.bytesToString(this._retainedSize)); 477 return data; 478 }, 479 480 get _countPercent() 481 { 482 return this._count / this.dataGrid.snapshot.nodeCount * 100.0; 483 }, 484 485 get _retainedSizePercent() 486 { 487 return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0; 488 }, 489 490 get _shallowSizePercent() 491 { 492 return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0; 493 } 494 }; 495 496 WebInspector.HeapSnapshotConstructorNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype; 497 498 WebInspector.HeapSnapshotIteratorsTuple = function(it1, it2) 499 { 500 this._it1 = it1; 501 this._it2 = it2; 502 } 503 504 WebInspector.HeapSnapshotIteratorsTuple.prototype = { 505 sortAndRewind: function(comparator, callback) 506 { 507 function afterSort(ignored) 508 { 509 this._it2.sortAndRewind(comparator, callback); 510 } 511 this._it1.sortAndRewind(comparator, afterSort.bind(this)); 512 } 513 }; 514 515 WebInspector.HeapSnapshotDiffNode = function(tree, className, baseAggregate, aggregate) 516 { 517 WebInspector.HeapSnapshotGridNode.call(this, tree, true); 518 this._name = className; 519 this._baseIndexes = baseAggregate ? baseAggregate.idxs : []; 520 this._indexes = aggregate ? aggregate.idxs : []; 521 this._provider = this._createNodesProvider(tree.baseSnapshot, tree.snapshot, aggregate ? aggregate.type : baseAggregate.type, className); 522 } 523 524 WebInspector.HeapSnapshotDiffNode.prototype = { 525 calculateDiff: function(dataGrid, callback) 526 { 527 var diff = dataGrid.snapshot.createDiff(this._name); 528 529 function diffCalculated(diffResult) 530 { 531 this._diff = diffResult; 532 this._baseIndexes = null; 533 this._indexes = null; 534 callback(this._diff.addedSize === 0 && this._diff.removedSize === 0); 535 } 536 function baseSelfSizesReceived(baseSelfSizes) 537 { 538 diff.pushBaseSelfSizes(baseSelfSizes); 539 diff.calculate(diffCalculated.bind(this)); 540 } 541 function baseIdsReceived(baseIds) 542 { 543 diff.pushBaseIds(dataGrid.baseSnapshot.uid, baseIds); 544 dataGrid.snapshot.pushBaseIds(dataGrid.baseSnapshot.uid, this._name, baseIds); 545 dataGrid.baseSnapshot.nodeFieldValuesByIndex("selfSize", this._baseIndexes, baseSelfSizesReceived.bind(this)); 546 } 547 function idsReceived(ids) 548 { 549 dataGrid.baseSnapshot.pushBaseIds(dataGrid.snapshot.uid, this._name, ids); 550 } 551 dataGrid.baseSnapshot.nodeFieldValuesByIndex("id", this._baseIndexes, baseIdsReceived.bind(this)); 552 dataGrid.snapshot.nodeFieldValuesByIndex("id", this._indexes, idsReceived.bind(this)); 553 }, 554 555 _createChildNode: function(item, provider) 556 { 557 if (provider === this._provider._it1) 558 return new WebInspector.HeapSnapshotInstanceNode(this.dataGrid, null, provider.snapshot, item); 559 else 560 return new WebInspector.HeapSnapshotInstanceNode(this.dataGrid, provider.snapshot, null, item); 561 }, 562 563 _createNodesProvider: function(baseSnapshot, snapshot, nodeType, nodeClassName) 564 { 565 var className = this._name; 566 return new WebInspector.HeapSnapshotIteratorsTuple( 567 createProvider(snapshot, baseSnapshot), createProvider(baseSnapshot, snapshot)); 568 569 function createProvider(snapshot, otherSnapshot) 570 { 571 var otherSnapshotId = otherSnapshot.uid; 572 var provider = snapshot.createNodesProvider( 573 function (node) { 574 return node.type === nodeType 575 && (nodeClassName === null || node.className === nodeClassName) 576 && !this.baseSnapshotHasNode(otherSnapshotId, className, node.id); 577 }); 578 provider.snapshot = snapshot; 579 return provider; 580 } 581 }, 582 583 _childHashForEntity: function(node) 584 { 585 return node.id; 586 }, 587 588 _childHashForNode: function(childNode) 589 { 590 return childNode.snapshotNodeId; 591 }, 592 593 comparator: function() 594 { 595 var sortAscending = this.dataGrid.sortOrder === "ascending"; 596 var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; 597 var sortFields = { 598 object: ["id", sortAscending, "selfSize", false], 599 addedCount: ["selfSize", sortAscending, "id", true], 600 removedCount: ["selfSize", sortAscending, "id", true], 601 countDelta: ["selfSize", sortAscending, "id", true], 602 addedSize: ["selfSize", sortAscending, "id", true], 603 removedSize: ["selfSize", sortAscending, "id", true], 604 sizeDelta: ["selfSize", sortAscending, "id", true] 605 }[sortColumnIdentifier]; 606 return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields); 607 }, 608 609 populateChildren: function(provider, howMany, atIndex, afterPopulate) 610 { 611 if (!provider && !howMany) { 612 var firstProviderPopulated = function() 613 { 614 WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it2, this._defaultPopulateCount, atIndex, afterPopulate); 615 }; 616 WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it1, this._defaultPopulateCount, atIndex, firstProviderPopulated.bind(this), true); 617 } else if (!howMany) { 618 var firstProviderPopulated = function() 619 { 620 WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it2, null, atIndex, afterPopulate); 621 }; 622 WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it1, null, atIndex, firstProviderPopulated.bind(this), true); 623 } else 624 WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, provider, howMany, atIndex, afterPopulate); 625 }, 626 627 _signForDelta: function(delta) 628 { 629 if (delta === 0) 630 return ""; 631 if (delta > 0) 632 return "+"; 633 else 634 return "\u2212"; // Math minus sign, same width as plus. 635 }, 636 637 get data() 638 { 639 var data = {object: this._name}; 640 641 data["addedCount"] = this._diff.addedCount; 642 data["removedCount"] = this._diff.removedCount; 643 var countDelta = this._diff.countDelta; 644 data["countDelta"] = WebInspector.UIString("%s%d", this._signForDelta(countDelta), Math.abs(countDelta)); 645 data["addedSize"] = Number.bytesToString(this._diff.addedSize); 646 data["removedSize"] = Number.bytesToString(this._diff.removedSize); 647 var sizeDelta = this._diff.sizeDelta; 648 data["sizeDelta"] = WebInspector.UIString("%s%s", this._signForDelta(sizeDelta), Number.bytesToString(Math.abs(sizeDelta))); 649 650 return data; 651 } 652 }; 653 654 WebInspector.HeapSnapshotDiffNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype; 655 656 WebInspector.HeapSnapshotDominatorObjectNode = function(tree, node) 657 { 658 WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node); 659 this._provider = this._createProvider(tree.snapshot, node.nodeIndex); 660 this._updateHasChildren(); 661 }; 662 663 WebInspector.HeapSnapshotDominatorObjectNode.prototype = { 664 _createChildNode: function(item) 665 { 666 return new WebInspector.HeapSnapshotDominatorObjectNode(this.dataGrid, item); 667 }, 668 669 _createProvider: function(snapshot, nodeIndex) 670 { 671 var showHiddenData = WebInspector.DetailedHeapshotView.prototype.showHiddenData; 672 return snapshot.createNodesProvider( 673 function (node) { 674 var dominatorIndex = node.dominatorIndex; 675 return dominatorIndex === nodeIndex 676 && dominatorIndex !== node.nodeIndex 677 && (showHiddenData || !node.isHidden); 678 }); 679 }, 680 681 _childHashForEntity: function(node) 682 { 683 return node.id; 684 }, 685 686 _childHashForNode: function(childNode) 687 { 688 return childNode.snapshotNodeId; 689 }, 690 691 comparator: function() 692 { 693 var sortAscending = this.dataGrid.sortOrder === "ascending"; 694 var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; 695 var sortFields = { 696 object: ["id", sortAscending, "retainedSize", false], 697 shallowSize: ["selfSize", sortAscending, "id", true], 698 retainedSize: ["retainedSize", sortAscending, "id", true] 699 }[sortColumnIdentifier]; 700 return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields); 701 }, 702 703 _emptyData: function() 704 { 705 return {}; 706 } 707 }; 708 709 WebInspector.HeapSnapshotDominatorObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype; 710 711 function MixInSnapshotNodeFunctions(sourcePrototype, targetPrototype) 712 { 713 targetPrototype._childHashForEntity = sourcePrototype._childHashForEntity; 714 targetPrototype._childHashForNode = sourcePrototype._childHashForNode; 715 targetPrototype.comparator = sourcePrototype.comparator; 716 targetPrototype._createChildNode = sourcePrototype._createChildNode; 717 targetPrototype._createProvider = sourcePrototype._createProvider; 718 targetPrototype.populateChildren = sourcePrototype.populateChildren; 719 targetPrototype._saveChildren = sourcePrototype._saveChildren; 720 targetPrototype.sort = sourcePrototype.sort; 721 } 722