OLD | NEW |
(Empty) | |
| 1 |
| 2 |
| 3 |
| 4 WebInspector = {}; |
| 5 WebInspector.UIString = function(s) { return s; }; |
| 6 |
| 7 |
| 8 |
| 9 function binarySearch(object, array, comparator) |
| 10 { |
| 11 var first = 0; |
| 12 var last = array.length - 1; |
| 13 |
| 14 while (first <= last) { |
| 15 var mid = (first + last) >> 1; |
| 16 var c = comparator(object, array[mid]); |
| 17 if (c > 0) |
| 18 first = mid + 1; |
| 19 else if (c < 0) |
| 20 last = mid - 1; |
| 21 else |
| 22 return mid; |
| 23 } |
| 24 |
| 25 |
| 26 return -(first + 1); |
| 27 } |
| 28 |
| 29 Object.defineProperty(Array.prototype, "binaryIndexOf", { value: function(value,
comparator) |
| 30 { |
| 31 var result = binarySearch(value, this, comparator); |
| 32 return result >= 0 ? result : -1; |
| 33 }}); |
| 34 |
| 35 function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunctio
n) |
| 36 { |
| 37 var index = binarySearch(anObject, aList, aFunction); |
| 38 if (index < 0) |
| 39 |
| 40 return -index - 1; |
| 41 else { |
| 42 |
| 43 while (index > 0 && aFunction(anObject, aList[index - 1]) === 0) |
| 44 index--; |
| 45 return index; |
| 46 } |
| 47 } |
| 48 ; |
| 49 |
| 50 |
| 51 WebInspector.HeapSnapshotLoader = function() |
| 52 { |
| 53 this._json = ""; |
| 54 this._state = "find-snapshot-info"; |
| 55 this._snapshot = {}; |
| 56 } |
| 57 |
| 58 WebInspector.HeapSnapshotLoader.prototype = { |
| 59 _findBalancedCurlyBrackets: function() |
| 60 { |
| 61 var counter = 0; |
| 62 var openingBracket = "{".charCodeAt(0), closingBracket = "}".charCodeAt(0); |
| 63 for (var i = 0, l = this._json.length; i < l; ++i) { |
| 64 var character = this._json.charCodeAt(i); |
| 65 if (character === openingBracket) |
| 66 ++counter; |
| 67 else if (character === closingBracket) { |
| 68 if (--counter === 0) |
| 69 return i + 1; |
| 70 } |
| 71 } |
| 72 return -1; |
| 73 }, |
| 74 |
| 75 finishLoading: function() |
| 76 { |
| 77 if (!this._json) |
| 78 return null; |
| 79 this._parseStringsArray(); |
| 80 this._json = ""; |
| 81 var result = new WebInspector.HeapSnapshot(this._snapshot); |
| 82 this._json = ""; |
| 83 this._snapshot = {}; |
| 84 return result; |
| 85 }, |
| 86 |
| 87 _parseNodes: function() |
| 88 { |
| 89 var index = 0; |
| 90 var char0 = "0".charCodeAt(0), char9 = "9".charCodeAt(0), closingBracket = "]".c
harCodeAt(0); |
| 91 var length = this._json.length; |
| 92 while (true) { |
| 93 while (index < length) { |
| 94 var code = this._json.charCodeAt(index); |
| 95 if (char0 <= code && code <= char9) |
| 96 break; |
| 97 else if (code === closingBracket) { |
| 98 this._json = this._json.slice(index + 1); |
| 99 |
| 100 this._snapshot.nodes = this._snapshot.nodes.slice(0); |
| 101 return false; |
| 102 } |
| 103 ++index; |
| 104 } |
| 105 if (index === length) { |
| 106 this._json = ""; |
| 107 return true; |
| 108 } |
| 109 var startIndex = index; |
| 110 while (index < length) { |
| 111 var code = this._json.charCodeAt(index); |
| 112 if (char0 > code || code > char9) |
| 113 break; |
| 114 ++index; |
| 115 } |
| 116 if (index === length) { |
| 117 this._json = this._json.slice(startIndex); |
| 118 return true; |
| 119 } |
| 120 this._snapshot.nodes.push(parseInt(this._json.slice(startIndex, index))); |
| 121 } |
| 122 }, |
| 123 |
| 124 _parseStringsArray: function() |
| 125 { |
| 126 var closingBracketIndex = this._json.lastIndexOf("]"); |
| 127 if (closingBracketIndex === -1) |
| 128 throw new Error("Incomplete JSON"); |
| 129 this._json = this._json.slice(0, closingBracketIndex + 1); |
| 130 this._snapshot.strings = JSON.parse(this._json); |
| 131 }, |
| 132 |
| 133 pushJSONChunk: function(chunk) |
| 134 { |
| 135 this._json += chunk; |
| 136 switch (this._state) { |
| 137 case "find-snapshot-info": { |
| 138 var snapshotToken = "\"snapshot\""; |
| 139 var snapshotTokenIndex = this._json.indexOf(snapshotToken); |
| 140 if (snapshotTokenIndex === -1) |
| 141 throw new Error("Snapshot token not found"); |
| 142 this._json = this._json.slice(snapshotTokenIndex + snapshotToken.length + 1); |
| 143 this._state = "parse-snapshot-info"; |
| 144 this.pushJSONChunk(""); |
| 145 break; |
| 146 } |
| 147 case "parse-snapshot-info": { |
| 148 var closingBracketIndex = this._findBalancedCurlyBrackets(); |
| 149 if (closingBracketIndex === -1) |
| 150 return; |
| 151 this._snapshot.snapshot = JSON.parse(this._json.slice(0, closingBracketIndex)); |
| 152 this._json = this._json.slice(closingBracketIndex); |
| 153 this._state = "find-nodes"; |
| 154 this.pushJSONChunk(""); |
| 155 break; |
| 156 } |
| 157 case "find-nodes": { |
| 158 var nodesToken = "\"nodes\""; |
| 159 var nodesTokenIndex = this._json.indexOf(nodesToken); |
| 160 if (nodesTokenIndex === -1) |
| 161 return; |
| 162 var bracketIndex = this._json.indexOf("[", nodesTokenIndex); |
| 163 if (bracketIndex === -1) |
| 164 return; |
| 165 this._json = this._json.slice(bracketIndex + 1); |
| 166 this._state = "parse-nodes-meta-info"; |
| 167 this.pushJSONChunk(""); |
| 168 break; |
| 169 } |
| 170 case "parse-nodes-meta-info": { |
| 171 var closingBracketIndex = this._findBalancedCurlyBrackets(); |
| 172 if (closingBracketIndex === -1) |
| 173 return; |
| 174 this._snapshot.nodes = [JSON.parse(this._json.slice(0, closingBracketIndex))]; |
| 175 this._json = this._json.slice(closingBracketIndex); |
| 176 this._state = "parse-nodes"; |
| 177 this.pushJSONChunk(""); |
| 178 break; |
| 179 } |
| 180 case "parse-nodes": { |
| 181 if (this._parseNodes()) |
| 182 return; |
| 183 this._state = "find-strings"; |
| 184 this.pushJSONChunk(""); |
| 185 break; |
| 186 } |
| 187 case "find-strings": { |
| 188 var stringsToken = "\"strings\""; |
| 189 var stringsTokenIndex = this._json.indexOf(stringsToken); |
| 190 if (stringsTokenIndex === -1) |
| 191 return; |
| 192 var bracketIndex = this._json.indexOf("[", stringsTokenIndex); |
| 193 if (bracketIndex === -1) |
| 194 return; |
| 195 this._json = this._json.slice(bracketIndex); |
| 196 this._state = "accumulate-strings"; |
| 197 break; |
| 198 } |
| 199 case "accumulate-strings": |
| 200 break; |
| 201 } |
| 202 } |
| 203 }; |
| 204 |
| 205 WebInspector.HeapSnapshotArraySlice = function(snapshot, arrayName, start, end) |
| 206 { |
| 207 |
| 208 |
| 209 this._snapshot = snapshot; |
| 210 this._arrayName = arrayName; |
| 211 this._start = start; |
| 212 this.length = end - start; |
| 213 } |
| 214 |
| 215 WebInspector.HeapSnapshotArraySlice.prototype = { |
| 216 item: function(index) |
| 217 { |
| 218 return this._snapshot[this._arrayName][this._start + index]; |
| 219 } |
| 220 } |
| 221 |
| 222 WebInspector.HeapSnapshotEdge = function(snapshot, edges, edgeIndex) |
| 223 { |
| 224 this._snapshot = snapshot; |
| 225 this._edges = edges; |
| 226 this.edgeIndex = edgeIndex || 0; |
| 227 } |
| 228 |
| 229 WebInspector.HeapSnapshotEdge.prototype = { |
| 230 clone: function() |
| 231 { |
| 232 return new WebInspector.HeapSnapshotEdge(this._snapshot, this._edges, this.edgeI
ndex); |
| 233 }, |
| 234 |
| 235 get hasStringName() |
| 236 { |
| 237 if (!this.isShortcut) |
| 238 return this._hasStringName; |
| 239 return isNaN(parseInt(this._name, 10)); |
| 240 }, |
| 241 |
| 242 get isElement() |
| 243 { |
| 244 return this._type() === this._snapshot._edgeElementType; |
| 245 }, |
| 246 |
| 247 get isHidden() |
| 248 { |
| 249 return this._type() === this._snapshot._edgeHiddenType; |
| 250 }, |
| 251 |
| 252 get isInternal() |
| 253 { |
| 254 return this._type() === this._snapshot._edgeInternalType; |
| 255 }, |
| 256 |
| 257 get isInvisible() |
| 258 { |
| 259 return this._type() === this._snapshot._edgeInvisibleType; |
| 260 }, |
| 261 |
| 262 get isShortcut() |
| 263 { |
| 264 return this._type() === this._snapshot._edgeShortcutType; |
| 265 }, |
| 266 |
| 267 get name() |
| 268 { |
| 269 if (!this.isShortcut) |
| 270 return this._name; |
| 271 var numName = parseInt(this._name, 10); |
| 272 return isNaN(numName) ? this._name : numName; |
| 273 }, |
| 274 |
| 275 get node() |
| 276 { |
| 277 return new WebInspector.HeapSnapshotNode(this._snapshot, this.nodeIndex); |
| 278 }, |
| 279 |
| 280 get nodeIndex() |
| 281 { |
| 282 return this._edges.item(this.edgeIndex + this._snapshot._edgeToNodeOffset); |
| 283 }, |
| 284 |
| 285 get rawEdges() |
| 286 { |
| 287 return this._edges; |
| 288 }, |
| 289 |
| 290 toString: function() |
| 291 { |
| 292 switch (this.type) { |
| 293 case "context": return "->" + this.name; |
| 294 case "element": return "[" + this.name + "]"; |
| 295 case "property": |
| 296 return this.name.indexOf(" ") === -1 ? "." + this.name : "[\"" + this.name + "\"
]"; |
| 297 case "shortcut": |
| 298 var name = this.name; |
| 299 if (typeof name === "string") |
| 300 return this.name.indexOf(" ") === -1 ? "." + this.name : "[\"" + this.name + "\"
]"; |
| 301 else |
| 302 return "[" + this.name + "]"; |
| 303 case "internal": |
| 304 case "hidden": |
| 305 case "invisible": |
| 306 return "{" + this.name + "}"; |
| 307 }; |
| 308 return "?" + this.name + "?"; |
| 309 }, |
| 310 |
| 311 get type() |
| 312 { |
| 313 return this._snapshot._edgeTypes[this._type()]; |
| 314 }, |
| 315 |
| 316 get _hasStringName() |
| 317 { |
| 318 return !this.isElement && !this.isHidden; |
| 319 }, |
| 320 |
| 321 get _name() |
| 322 { |
| 323 return this._hasStringName ? this._snapshot._strings[this._nameOrIndex] : this._
nameOrIndex; |
| 324 }, |
| 325 |
| 326 get _nameOrIndex() |
| 327 { |
| 328 return this._edges.item(this.edgeIndex + this._snapshot._edgeNameOffset); |
| 329 }, |
| 330 |
| 331 _type: function() |
| 332 { |
| 333 return this._edges.item(this.edgeIndex + this._snapshot._edgeTypeOffset); |
| 334 } |
| 335 }; |
| 336 |
| 337 WebInspector.HeapSnapshotEdgeIterator = function(edge) |
| 338 { |
| 339 this.edge = edge; |
| 340 } |
| 341 |
| 342 WebInspector.HeapSnapshotEdgeIterator.prototype = { |
| 343 first: function() |
| 344 { |
| 345 this.edge.edgeIndex = 0; |
| 346 }, |
| 347 |
| 348 hasNext: function() |
| 349 { |
| 350 return this.edge.edgeIndex < this.edge._edges.length; |
| 351 }, |
| 352 |
| 353 get index() |
| 354 { |
| 355 return this.edge.edgeIndex; |
| 356 }, |
| 357 |
| 358 set index(newIndex) |
| 359 { |
| 360 this.edge.edgeIndex = newIndex; |
| 361 }, |
| 362 |
| 363 get item() |
| 364 { |
| 365 return this.edge; |
| 366 }, |
| 367 |
| 368 next: function() |
| 369 { |
| 370 this.edge.edgeIndex += this.edge._snapshot._edgeFieldsCount; |
| 371 } |
| 372 }; |
| 373 |
| 374 WebInspector.HeapSnapshotRetainerEdge = function(snapshot, retainers, retainerIn
dex) |
| 375 { |
| 376 this._snapshot = snapshot; |
| 377 this._retainers = retainers; |
| 378 this.retainerIndex = retainerIndex || 0; |
| 379 } |
| 380 |
| 381 WebInspector.HeapSnapshotRetainerEdge.prototype = { |
| 382 clone: function() |
| 383 { |
| 384 return new WebInspector.HeapSnapshotRetainerEdge(this._snapshot, this._retainers
, this.retainerIndex); |
| 385 }, |
| 386 |
| 387 get hasStringName() |
| 388 { |
| 389 return this._edge.hasStringName; |
| 390 }, |
| 391 |
| 392 get isElement() |
| 393 { |
| 394 return this._edge.isElement; |
| 395 }, |
| 396 |
| 397 get isHidden() |
| 398 { |
| 399 return this._edge.isHidden; |
| 400 }, |
| 401 |
| 402 get isInternal() |
| 403 { |
| 404 return this._edge.isInternal; |
| 405 }, |
| 406 |
| 407 get isInvisible() |
| 408 { |
| 409 return this._edge.isInvisible; |
| 410 }, |
| 411 |
| 412 get isShortcut() |
| 413 { |
| 414 return this._edge.isShortcut; |
| 415 }, |
| 416 |
| 417 get name() |
| 418 { |
| 419 return this._edge.name; |
| 420 }, |
| 421 |
| 422 get node() |
| 423 { |
| 424 return this._node; |
| 425 }, |
| 426 |
| 427 get nodeIndex() |
| 428 { |
| 429 return this._nodeIndex; |
| 430 }, |
| 431 |
| 432 get retainerIndex() |
| 433 { |
| 434 return this._retainerIndex; |
| 435 }, |
| 436 |
| 437 set retainerIndex(newIndex) |
| 438 { |
| 439 if (newIndex !== this._retainerIndex) { |
| 440 this._retainerIndex = newIndex; |
| 441 this._setupEdge(); |
| 442 } |
| 443 }, |
| 444 |
| 445 _setupEdge: function() |
| 446 { |
| 447 var globalEdgeIndex = this._retainers.item(this._retainerIndex); |
| 448 this._nodeIndex = this._snapshot._findNearestNodeIndex(globalEdgeIndex); |
| 449 this._node = new WebInspector.HeapSnapshotNode(this._snapshot, this._nodeIndex); |
| 450 var edgeIndex = globalEdgeIndex - this._nodeIndex - this._snapshot._firstEdgeOff
set; |
| 451 this._edge = new WebInspector.HeapSnapshotEdge(this._snapshot, this._node.rawEdg
es, edgeIndex); |
| 452 }, |
| 453 |
| 454 toString: function() |
| 455 { |
| 456 return this._edge.toString(); |
| 457 }, |
| 458 |
| 459 get type() |
| 460 { |
| 461 return this._edge.type; |
| 462 } |
| 463 } |
| 464 |
| 465 WebInspector.HeapSnapshotRetainerEdgeIterator = function(retainer) |
| 466 { |
| 467 this.retainer = retainer; |
| 468 } |
| 469 |
| 470 WebInspector.HeapSnapshotRetainerEdgeIterator.prototype = { |
| 471 first: function() |
| 472 { |
| 473 this.retainer.retainerIndex = 0; |
| 474 }, |
| 475 |
| 476 hasNext: function() |
| 477 { |
| 478 return this.retainer.retainerIndex < this.retainer._retainers.length; |
| 479 }, |
| 480 |
| 481 get index() |
| 482 { |
| 483 return this.retainer.retainerIndex; |
| 484 }, |
| 485 |
| 486 set index(newIndex) |
| 487 { |
| 488 this.retainer.retainerIndex = newIndex; |
| 489 }, |
| 490 |
| 491 get item() |
| 492 { |
| 493 return this.retainer; |
| 494 }, |
| 495 |
| 496 next: function() |
| 497 { |
| 498 ++this.retainer.retainerIndex; |
| 499 } |
| 500 }; |
| 501 |
| 502 WebInspector.HeapSnapshotNode = function(snapshot, nodeIndex) |
| 503 { |
| 504 this._snapshot = snapshot; |
| 505 this._firstNodeIndex = nodeIndex; |
| 506 this.nodeIndex = nodeIndex; |
| 507 } |
| 508 |
| 509 WebInspector.HeapSnapshotNode.prototype = { |
| 510 get className() |
| 511 { |
| 512 switch (this.type) { |
| 513 case "hidden": |
| 514 return WebInspector.UIString("(system)"); |
| 515 case "object": { |
| 516 var commentPos = this.name.indexOf("/"); |
| 517 return commentPos !== -1 ? this.name.substring(0, commentPos).trimRight() : this
.name; |
| 518 } |
| 519 case "native": { |
| 520 var entitiesCountPos = this.name.indexOf("/"); |
| 521 return entitiesCountPos !== -1 ? this.name.substring(0, entitiesCountPos).trimRi
ght() : this.name; |
| 522 } |
| 523 case "code": |
| 524 return WebInspector.UIString("(compiled code)"); |
| 525 default: |
| 526 return "(" + this.type + ")"; |
| 527 } |
| 528 }, |
| 529 |
| 530 get dominatorIndex() |
| 531 { |
| 532 return this._nodes[this.nodeIndex + this._snapshot._dominatorOffset]; |
| 533 }, |
| 534 |
| 535 get edges() |
| 536 { |
| 537 return new WebInspector.HeapSnapshotEdgeIterator(new WebInspector.HeapSnapshotEd
ge(this._snapshot, this.rawEdges)); |
| 538 }, |
| 539 |
| 540 get edgesCount() |
| 541 { |
| 542 return this._nodes[this.nodeIndex + this._snapshot._edgesCountOffset]; |
| 543 }, |
| 544 |
| 545 get id() |
| 546 { |
| 547 return this._nodes[this.nodeIndex + this._snapshot._nodeIdOffset]; |
| 548 }, |
| 549 |
| 550 get instancesCount() |
| 551 { |
| 552 return this._nodes[this.nodeIndex + this._snapshot._nodeInstancesCountOffset]; |
| 553 }, |
| 554 |
| 555 get isHidden() |
| 556 { |
| 557 return this._type() === this._snapshot._nodeHiddenType; |
| 558 }, |
| 559 |
| 560 get isRoot() |
| 561 { |
| 562 return this.nodeIndex === this._snapshot._rootNodeIndex; |
| 563 }, |
| 564 |
| 565 get name() |
| 566 { |
| 567 return this._snapshot._strings[this._name()]; |
| 568 }, |
| 569 |
| 570 get rawEdges() |
| 571 { |
| 572 var firstEdgeIndex = this._firstEdgeIndex(); |
| 573 return new WebInspector.HeapSnapshotArraySlice(this._snapshot, "_nodes", firstEd
geIndex, firstEdgeIndex + this.edgesCount * this._snapshot._edgeFieldsCount); |
| 574 }, |
| 575 |
| 576 get retainedSize() |
| 577 { |
| 578 return this._nodes[this.nodeIndex + this._snapshot._nodeRetainedSizeOffset]; |
| 579 }, |
| 580 |
| 581 get retainers() |
| 582 { |
| 583 return new WebInspector.HeapSnapshotRetainerEdgeIterator(new WebInspector.HeapSn
apshotRetainerEdge(this._snapshot, this._snapshot._retainersForNode(this))); |
| 584 }, |
| 585 |
| 586 get selfSize() |
| 587 { |
| 588 return this._nodes[this.nodeIndex + this._snapshot._nodeSelfSizeOffset]; |
| 589 }, |
| 590 |
| 591 get type() |
| 592 { |
| 593 return this._snapshot._nodeTypes[this._type()]; |
| 594 }, |
| 595 |
| 596 _name: function() |
| 597 { |
| 598 return this._nodes[this.nodeIndex + this._snapshot._nodeNameOffset]; |
| 599 }, |
| 600 |
| 601 get _nodes() |
| 602 { |
| 603 return this._snapshot._nodes; |
| 604 }, |
| 605 |
| 606 _firstEdgeIndex: function() |
| 607 { |
| 608 return this.nodeIndex + this._snapshot._firstEdgeOffset; |
| 609 }, |
| 610 |
| 611 get _nextNodeIndex() |
| 612 { |
| 613 return this._firstEdgeIndex() + this.edgesCount * this._snapshot._edgeFieldsCoun
t; |
| 614 }, |
| 615 |
| 616 _type: function() |
| 617 { |
| 618 return this._nodes[this.nodeIndex + this._snapshot._nodeTypeOffset]; |
| 619 } |
| 620 }; |
| 621 |
| 622 WebInspector.HeapSnapshotNodeIterator = function(node) |
| 623 { |
| 624 this.node = node; |
| 625 } |
| 626 |
| 627 WebInspector.HeapSnapshotNodeIterator.prototype = { |
| 628 first: function() |
| 629 { |
| 630 this.node.nodeIndex = this.node._firstNodeIndex; |
| 631 }, |
| 632 |
| 633 hasNext: function() |
| 634 { |
| 635 return this.node.nodeIndex < this.node._nodes.length; |
| 636 }, |
| 637 |
| 638 get index() |
| 639 { |
| 640 return this.node.nodeIndex; |
| 641 }, |
| 642 |
| 643 set index(newIndex) |
| 644 { |
| 645 this.node.nodeIndex = newIndex; |
| 646 }, |
| 647 |
| 648 get item() |
| 649 { |
| 650 return this.node; |
| 651 }, |
| 652 |
| 653 next: function() |
| 654 { |
| 655 this.node.nodeIndex = this.node._nextNodeIndex; |
| 656 } |
| 657 } |
| 658 |
| 659 WebInspector.HeapSnapshot = function(profile) |
| 660 { |
| 661 this.uid = profile.snapshot.uid; |
| 662 this._nodes = profile.nodes; |
| 663 this._strings = profile.strings; |
| 664 |
| 665 this._init(); |
| 666 } |
| 667 |
| 668 WebInspector.HeapSnapshot.prototype = { |
| 669 _init: function() |
| 670 { |
| 671 this._metaNodeIndex = 0; |
| 672 this._rootNodeIndex = 1; |
| 673 var meta = this._nodes[this._metaNodeIndex]; |
| 674 this._nodeTypeOffset = meta.fields.indexOf("type"); |
| 675 this._nodeNameOffset = meta.fields.indexOf("name"); |
| 676 this._nodeIdOffset = meta.fields.indexOf("id"); |
| 677 this._nodeInstancesCountOffset = this._nodeIdOffset; |
| 678 this._nodeSelfSizeOffset = meta.fields.indexOf("self_size"); |
| 679 this._nodeRetainedSizeOffset = meta.fields.indexOf("retained_size"); |
| 680 this._dominatorOffset = meta.fields.indexOf("dominator"); |
| 681 this._edgesCountOffset = meta.fields.indexOf("children_count"); |
| 682 this._firstEdgeOffset = meta.fields.indexOf("children"); |
| 683 this._nodeTypes = meta.types[this._nodeTypeOffset]; |
| 684 this._nodeHiddenType = this._nodeTypes.indexOf("hidden"); |
| 685 var edgesMeta = meta.types[this._firstEdgeOffset]; |
| 686 this._edgeFieldsCount = edgesMeta.fields.length; |
| 687 this._edgeTypeOffset = edgesMeta.fields.indexOf("type"); |
| 688 this._edgeNameOffset = edgesMeta.fields.indexOf("name_or_index"); |
| 689 this._edgeToNodeOffset = edgesMeta.fields.indexOf("to_node"); |
| 690 this._edgeTypes = edgesMeta.types[this._edgeTypeOffset]; |
| 691 this._edgeElementType = this._edgeTypes.indexOf("element"); |
| 692 this._edgeHiddenType = this._edgeTypes.indexOf("hidden"); |
| 693 this._edgeInternalType = this._edgeTypes.indexOf("internal"); |
| 694 this._edgeShortcutType = this._edgeTypes.indexOf("shortcut"); |
| 695 this._edgeInvisibleType = this._edgeTypes.length; |
| 696 this._edgeTypes.push("invisible"); |
| 697 |
| 698 this._markInvisibleEdges(); |
| 699 }, |
| 700 |
| 701 dispose: function() |
| 702 { |
| 703 delete this._nodes; |
| 704 delete this._strings; |
| 705 delete this._retainers; |
| 706 delete this._retainerIndex; |
| 707 delete this._nodeIndex; |
| 708 if (this._aggregates) { |
| 709 delete this._aggregates; |
| 710 this._aggregatesIndexesSorted = false; |
| 711 } |
| 712 delete this._baseNodeIds; |
| 713 }, |
| 714 |
| 715 get _allNodes() |
| 716 { |
| 717 return new WebInspector.HeapSnapshotNodeIterator(this.rootNode); |
| 718 }, |
| 719 |
| 720 get nodeCount() |
| 721 { |
| 722 if (this._nodeCount) |
| 723 return this._nodeCount; |
| 724 |
| 725 this._nodeCount = 0; |
| 726 for (var iter = this._allNodes; iter.hasNext(); iter.next()) |
| 727 ++this._nodeCount; |
| 728 return this._nodeCount; |
| 729 }, |
| 730 |
| 731 nodeFieldValuesByIndex: function(fieldName, indexes) |
| 732 { |
| 733 var node = new WebInspector.HeapSnapshotNode(this); |
| 734 var result = new Array(indexes.length); |
| 735 for (var i = 0, l = indexes.length; i < l; ++i) { |
| 736 node.nodeIndex = indexes[i]; |
| 737 result[i] = node[fieldName]; |
| 738 } |
| 739 return result; |
| 740 }, |
| 741 |
| 742 get rootNode() |
| 743 { |
| 744 return new WebInspector.HeapSnapshotNode(this, this._rootNodeIndex); |
| 745 }, |
| 746 |
| 747 get rootNodeIndex() |
| 748 { |
| 749 return this._rootNodeIndex; |
| 750 }, |
| 751 |
| 752 get totalSize() |
| 753 { |
| 754 return this.rootNode.retainedSize; |
| 755 }, |
| 756 |
| 757 _retainersForNode: function(node) |
| 758 { |
| 759 if (!this._retainers) |
| 760 this._buildRetainers(); |
| 761 |
| 762 var retIndexFrom = this._getRetainerIndex(node.nodeIndex); |
| 763 var retIndexTo = this._getRetainerIndex(node._nextNodeIndex); |
| 764 return new WebInspector.HeapSnapshotArraySlice(this, "_retainers", retIndexFrom,
retIndexTo); |
| 765 }, |
| 766 |
| 767 aggregates: function(sortedIndexes) |
| 768 { |
| 769 if (!this._aggregates) |
| 770 this._buildAggregates(); |
| 771 if (sortedIndexes && !this._aggregatesIndexesSorted) |
| 772 this._sortAggregateIndexes(); |
| 773 return this._aggregates; |
| 774 }, |
| 775 |
| 776 _buildRetainers: function() |
| 777 { |
| 778 if (!this._nodeIndex) |
| 779 this._buildNodeIndex(); |
| 780 |
| 781 this._retainerIndex = new Array(this._nodeIndex.length); |
| 782 for (var i = 0, l = this._retainerIndex.length; i < l; ++i) |
| 783 this._retainerIndex[i] = 0; |
| 784 for (var nodesIter = this._allNodes; nodesIter.hasNext(); nodesIter.next()) { |
| 785 var node = nodesIter.node; |
| 786 for (var edgesIter = node.edges; edgesIter.hasNext(); edgesIter.next()) { |
| 787 var edge = edgesIter.edge; |
| 788 var nodeIndex = edge.nodeIndex; |
| 789 var position = this._findNodePositionInIndex(nodeIndex); |
| 790 ++this._retainerIndex[position]; |
| 791 } |
| 792 } |
| 793 var retainerCount = 0; |
| 794 for (i = 0, l = this._retainerIndex.length; i < l; ++i) |
| 795 retainerCount += this._retainerIndex[i]; |
| 796 this._retainers = new Array(retainerCount + 1); |
| 797 var retainerPosition = 0; |
| 798 for (i = 0, l = this._retainerIndex.length; i < l; ++i) { |
| 799 retainerCount = this._retainers[retainerPosition] = this._retainerIndex[i]; |
| 800 this._retainerIndex[i] = retainerPosition; |
| 801 retainerPosition += retainerCount; |
| 802 } |
| 803 for (nodesIter = this._allNodes; nodesIter.hasNext(); nodesIter.next()) { |
| 804 var node = nodesIter.node; |
| 805 for (var edgesIter = node.edges; edgesIter.hasNext(); edgesIter.next()) { |
| 806 var edge = edgesIter.edge; |
| 807 var nodeIndex = edge.nodeIndex; |
| 808 var retIndex = this._getRetainerIndex(nodeIndex); |
| 809 var idx = retIndex + (--this._retainers[retIndex]); |
| 810 this._retainers[idx] = node.nodeIndex + this._firstEdgeOffset + edge.edgeIndex; |
| 811 } |
| 812 } |
| 813 }, |
| 814 |
| 815 _buildAggregates: function() |
| 816 { |
| 817 this._aggregates = {}; |
| 818 for (var iter = this._allNodes; iter.hasNext(); iter.next()) { |
| 819 var node = iter.node; |
| 820 var className = node.className; |
| 821 var nameMatters = node.type === "object" || node.type === "native"; |
| 822 if (node.type !== "native" && node.selfSize === 0) |
| 823 continue; |
| 824 if (!(className in this._aggregates)) |
| 825 this._aggregates[className] = { count: 0, self: 0, maxRet: 0, type: node.type, n
ame: nameMatters ? node.name : null, idxs: [] }; |
| 826 var clss = this._aggregates[className]; |
| 827 ++clss.count; |
| 828 clss.self += node.selfSize; |
| 829 if (node.retainedSize > clss.maxRet) |
| 830 clss.maxRet = node.retainedSize; |
| 831 clss.idxs.push(node.nodeIndex); |
| 832 } |
| 833 |
| 834 for (var className in this._aggregates) |
| 835 this._aggregates[className].idxs = this._aggregates[className].idxs.slice(0); |
| 836 }, |
| 837 |
| 838 _sortAggregateIndexes: function() |
| 839 { |
| 840 var nodeA = new WebInspector.HeapSnapshotNode(this); |
| 841 var nodeB = new WebInspector.HeapSnapshotNode(this); |
| 842 for (var clss in this._aggregates) |
| 843 this._aggregates[clss].idxs.sort( |
| 844 function(idxA, idxB) { |
| 845 nodeA.nodeIndex = idxA; |
| 846 nodeB.nodeIndex = idxB; |
| 847 return nodeA.id < nodeB.id ? -1 : 1; |
| 848 }); |
| 849 |
| 850 this._aggregatesIndexesSorted = true; |
| 851 }, |
| 852 |
| 853 _buildNodeIndex: function() |
| 854 { |
| 855 var count = 0; |
| 856 for (var nodesIter = this._allNodes; nodesIter.hasNext(); nodesIter.next(), ++co
unt); |
| 857 this._nodeIndex = new Array(count + 1); |
| 858 count = 0; |
| 859 for (nodesIter = this._allNodes; nodesIter.hasNext(); nodesIter.next(), ++count) |
| 860 this._nodeIndex[count] = nodesIter.index; |
| 861 this._nodeIndex[count] = this._nodes.length; |
| 862 }, |
| 863 |
| 864 _findNodePositionInIndex: function(index) |
| 865 { |
| 866 return binarySearch(index, this._nodeIndex, this._numbersComparator); |
| 867 }, |
| 868 |
| 869 _findNearestNodeIndex: function(index) |
| 870 { |
| 871 var result = this._findNodePositionInIndex(index); |
| 872 if (result < 0) { |
| 873 result = -result - 1; |
| 874 nodeIndex = this._nodeIndex[result]; |
| 875 |
| 876 if (nodeIndex > index) |
| 877 nodeIndex = this._nodeIndex[result - 1]; |
| 878 } else |
| 879 var nodeIndex = this._nodeIndex[result]; |
| 880 return nodeIndex; |
| 881 }, |
| 882 |
| 883 _getRetainerIndex: function(nodeIndex) |
| 884 { |
| 885 var nodePosition = this._findNodePositionInIndex(nodeIndex); |
| 886 return this._retainerIndex[nodePosition]; |
| 887 }, |
| 888 |
| 889 _markInvisibleEdges: function() |
| 890 { |
| 891 |
| 892 |
| 893 |
| 894 for (var iter = this.rootNode.edges; iter.hasNext(); iter.next()) { |
| 895 var edge = iter.edge; |
| 896 if (!edge.isShortcut) |
| 897 continue; |
| 898 var node = edge.node; |
| 899 var propNames = {}; |
| 900 for (var innerIter = node.edges; innerIter.hasNext(); innerIter.next()) { |
| 901 var globalObjEdge = innerIter.edge; |
| 902 if (globalObjEdge.isShortcut) |
| 903 propNames[globalObjEdge._nameOrIndex] = true; |
| 904 } |
| 905 for (innerIter.first(); innerIter.hasNext(); innerIter.next()) { |
| 906 var globalObjEdge = innerIter.edge; |
| 907 if (!globalObjEdge.isShortcut |
| 908 && globalObjEdge.node.isHidden |
| 909 && globalObjEdge._hasStringName |
| 910 && (globalObjEdge._nameOrIndex in propNames)) |
| 911 this._nodes[globalObjEdge._edges._start + globalObjEdge.edgeIndex + this._edgeTy
peOffset] = this._edgeInvisibleType; |
| 912 } |
| 913 } |
| 914 }, |
| 915 |
| 916 _numbersComparator: function(a, b) |
| 917 { |
| 918 return a < b ? -1 : (a > b ? 1 : 0); |
| 919 }, |
| 920 |
| 921 baseSnapshotHasNode: function(baseSnapshotId, className, nodeId) |
| 922 { |
| 923 return this._baseNodeIds[baseSnapshotId][className].binaryIndexOf(nodeId, this._
numbersComparator) !== -1; |
| 924 }, |
| 925 |
| 926 pushBaseIds: function(baseSnapshotId, className, nodeIds) |
| 927 { |
| 928 if (!this._baseNodeIds) |
| 929 this._baseNodeIds = []; |
| 930 if (!this._baseNodeIds[baseSnapshotId]) |
| 931 this._baseNodeIds[baseSnapshotId] = {}; |
| 932 this._baseNodeIds[baseSnapshotId][className] = nodeIds; |
| 933 }, |
| 934 |
| 935 createDiff: function(className) |
| 936 { |
| 937 return new WebInspector.HeapSnapshotsDiff(this, className); |
| 938 }, |
| 939 |
| 940 _parseFilter: function(filter) |
| 941 { |
| 942 if (!filter) |
| 943 return null; |
| 944 var parsedFilter = eval("(function(){return " + filter + "})()"); |
| 945 return parsedFilter.bind(this); |
| 946 }, |
| 947 |
| 948 createEdgesProvider: function(nodeIndex, filter) |
| 949 { |
| 950 return new WebInspector.HeapSnapshotEdgesProvider(this, nodeIndex, this._parseFi
lter(filter)); |
| 951 }, |
| 952 |
| 953 createNodesProvider: function(filter) |
| 954 { |
| 955 return new WebInspector.HeapSnapshotNodesProvider(this, this._parseFilter(filter
)); |
| 956 }, |
| 957 |
| 958 createNodesProviderForClass: function(className) |
| 959 { |
| 960 return new WebInspector.HeapSnapshotNodesProvider(this, null, className); |
| 961 }, |
| 962 |
| 963 createPathFinder: function(targetNodeIndex, skipHidden) |
| 964 { |
| 965 return new WebInspector.HeapSnapshotPathFinder(this, targetNodeIndex, skipHidden
); |
| 966 }, |
| 967 |
| 968 updateStaticData: function() |
| 969 { |
| 970 return {nodeCount: this.nodeCount, rootNodeIndex: this._rootNodeIndex, totalSize
: this.totalSize, uid: this.uid}; |
| 971 } |
| 972 }; |
| 973 |
| 974 WebInspector.HeapSnapshotFilteredOrderedIterator = function(iterator, filter, it
erationOrder) |
| 975 { |
| 976 this._filter = filter; |
| 977 this._iterator = iterator; |
| 978 this._iterationOrder = iterationOrder ? iterationOrder.slice(0) : null; |
| 979 this._position = 0; |
| 980 this._lastComparator = null; |
| 981 } |
| 982 |
| 983 WebInspector.HeapSnapshotFilteredOrderedIterator.prototype = { |
| 984 _createIterationOrder: function() |
| 985 { |
| 986 this._iterationOrder = []; |
| 987 var iterator = this._iterator; |
| 988 if (!this._filter) { |
| 989 for (iterator.first(); iterator.hasNext(); iterator.next()) |
| 990 this._iterationOrder.push(iterator.index); |
| 991 } else { |
| 992 for (iterator.first(); iterator.hasNext(); iterator.next()) { |
| 993 if (this._filter(iterator.item)) |
| 994 this._iterationOrder.push(iterator.index); |
| 995 } |
| 996 } |
| 997 }, |
| 998 |
| 999 first: function() |
| 1000 { |
| 1001 this._position = 0; |
| 1002 }, |
| 1003 |
| 1004 hasNext: function() |
| 1005 { |
| 1006 return this._position < this._iterationOrder.length; |
| 1007 }, |
| 1008 |
| 1009 get isEmpty() |
| 1010 { |
| 1011 if (this._iterationOrder) |
| 1012 return !this._iterationOrder.length; |
| 1013 var iterator = this._iterator; |
| 1014 if (!this._filter) { |
| 1015 iterator.first(); |
| 1016 return !iterator.hasNext(); |
| 1017 } |
| 1018 for (iterator.first(); iterator.hasNext(); iterator.next()) |
| 1019 if (this._filter(iterator.item)) return false; |
| 1020 return true; |
| 1021 }, |
| 1022 |
| 1023 get item() |
| 1024 { |
| 1025 this._iterator.index = this._iterationOrder[this._position]; |
| 1026 return this._iterator.item; |
| 1027 }, |
| 1028 |
| 1029 get length() |
| 1030 { |
| 1031 if (!this._iterationOrder) |
| 1032 this._createIterationOrder(); |
| 1033 return this._iterationOrder.length; |
| 1034 }, |
| 1035 |
| 1036 next: function() |
| 1037 { |
| 1038 ++this._position; |
| 1039 }, |
| 1040 |
| 1041 serializeNextItems: function(count) |
| 1042 { |
| 1043 var result = new Array(count); |
| 1044 for (var i = 0 ; i < count && this.hasNext(); ++i, this.next()) |
| 1045 result[i] = this._serialize(this.item); |
| 1046 result.length = i; |
| 1047 result.hasNext = this.hasNext(); |
| 1048 result.totalLength = this.length; |
| 1049 return result; |
| 1050 }, |
| 1051 |
| 1052 sortAndRewind: function(comparator) |
| 1053 { |
| 1054 var result = this.sort(comparator); |
| 1055 if (result) |
| 1056 this.first(); |
| 1057 return result; |
| 1058 } |
| 1059 } |
| 1060 |
| 1061 WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator = fu
nction(fieldNames) |
| 1062 { |
| 1063 return {fieldName1:fieldNames[0], ascending1:fieldNames[1], fieldName2:fieldName
s[2], ascending2:fieldNames[3]}; |
| 1064 } |
| 1065 |
| 1066 WebInspector.HeapSnapshotEdgesProvider = function(snapshot, nodeIndex, filter) |
| 1067 { |
| 1068 this.snapshot = snapshot; |
| 1069 var node = new WebInspector.HeapSnapshotNode(snapshot, nodeIndex); |
| 1070 WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, new WebInspector.Hea
pSnapshotEdgeIterator(new WebInspector.HeapSnapshotEdge(snapshot, node.rawEdges)
), filter); |
| 1071 } |
| 1072 |
| 1073 WebInspector.HeapSnapshotEdgesProvider.prototype = { |
| 1074 _serialize: function(edge) |
| 1075 { |
| 1076 return {name: edge.name, node: WebInspector.HeapSnapshotNodesProvider.prototype.
_serialize(edge.node), nodeIndex: edge.nodeIndex, type: edge.type}; |
| 1077 }, |
| 1078 |
| 1079 sort: function(comparator) |
| 1080 { |
| 1081 if (this._lastComparator === comparator) |
| 1082 return false; |
| 1083 this._lastComparator = comparator; |
| 1084 var fieldName1 = comparator.fieldName1; |
| 1085 var fieldName2 = comparator.fieldName2; |
| 1086 var ascending1 = comparator.ascending1; |
| 1087 var ascending2 = comparator.ascending2; |
| 1088 |
| 1089 var edgeA = this._iterator.item.clone(); |
| 1090 var edgeB = edgeA.clone(); |
| 1091 var nodeA = new WebInspector.HeapSnapshotNode(this.snapshot); |
| 1092 var nodeB = new WebInspector.HeapSnapshotNode(this.snapshot); |
| 1093 |
| 1094 function sortByEdgeFieldName(ascending, indexA, indexB) |
| 1095 { |
| 1096 edgeA.edgeIndex = indexA; |
| 1097 edgeB.edgeIndex = indexB; |
| 1098 if (edgeB.name === "__proto__") return -1; |
| 1099 if (edgeA.name === "__proto__") return 1; |
| 1100 var result = |
| 1101 edgeA.hasStringName === edgeB.hasStringName ? |
| 1102 (edgeA.name < edgeB.name ? -1 : (edgeA.name > edgeB.name ? 1 : 0)) : |
| 1103 (edgeA.hasStringName ? -1 : 1); |
| 1104 return ascending ? result : -result; |
| 1105 } |
| 1106 |
| 1107 function sortByNodeField(fieldName, ascending, indexA, indexB) |
| 1108 { |
| 1109 edgeA.edgeIndex = indexA; |
| 1110 edgeB.edgeIndex = indexB; |
| 1111 nodeA.nodeIndex = edgeA.nodeIndex; |
| 1112 nodeB.nodeIndex = edgeB.nodeIndex; |
| 1113 var valueA = nodeA[fieldName]; |
| 1114 var valueB = nodeB[fieldName]; |
| 1115 var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0); |
| 1116 return ascending ? result : -result; |
| 1117 } |
| 1118 |
| 1119 if (!this._iterationOrder) |
| 1120 this._createIterationOrder(); |
| 1121 |
| 1122 function sortByEdgeAndNode(indexA, indexB) { |
| 1123 var result = sortByEdgeFieldName(ascending1, indexA, indexB); |
| 1124 if (result === 0) |
| 1125 result = sortByNodeField(fieldName2, ascending2, indexA, indexB); |
| 1126 return result; |
| 1127 } |
| 1128 |
| 1129 function sortByNodeAndEdge(indexA, indexB) { |
| 1130 var result = sortByNodeField(fieldName1, ascending1, indexA, indexB); |
| 1131 if (result === 0) |
| 1132 result = sortByEdgeFieldName(ascending2, indexA, indexB); |
| 1133 return result; |
| 1134 } |
| 1135 |
| 1136 function sortByNodeAndNode(indexA, indexB) { |
| 1137 var result = sortByNodeField(fieldName1, ascending1, indexA, indexB); |
| 1138 if (result === 0) |
| 1139 result = sortByNodeField(fieldName2, ascending2, indexA, indexB); |
| 1140 return result; |
| 1141 } |
| 1142 |
| 1143 if (fieldName1 === "!edgeName") |
| 1144 this._iterationOrder.sort(sortByEdgeAndNode); |
| 1145 else if (fieldName2 === "!edgeName") |
| 1146 this._iterationOrder.sort(sortByNodeAndEdge); |
| 1147 else |
| 1148 this._iterationOrder.sort(sortByNodeAndNode); |
| 1149 return true; |
| 1150 } |
| 1151 }; |
| 1152 |
| 1153 WebInspector.HeapSnapshotEdgesProvider.prototype.__proto__ = WebInspector.HeapSn
apshotFilteredOrderedIterator.prototype; |
| 1154 |
| 1155 WebInspector.HeapSnapshotNodesProvider = function(snapshot, filter, className) |
| 1156 { |
| 1157 this.snapshot = snapshot; |
| 1158 if (!className) |
| 1159 WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, snapshot._allNodes,
filter); |
| 1160 else |
| 1161 WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, snapshot._allNodes,
null, snapshot.aggregates(false)[className].idxs); |
| 1162 } |
| 1163 |
| 1164 WebInspector.HeapSnapshotNodesProvider.prototype = { |
| 1165 _serialize: function(node) |
| 1166 { |
| 1167 return {id: node.id, name: node.name, nodeIndex: node.nodeIndex, retainedSize: n
ode.retainedSize, selfSize: node.selfSize, type: node.type}; |
| 1168 }, |
| 1169 |
| 1170 sort: function(comparator) |
| 1171 { |
| 1172 if (this._lastComparator === comparator) |
| 1173 return false; |
| 1174 this._lastComparator = comparator; |
| 1175 var fieldName1 = comparator.fieldName1; |
| 1176 var fieldName2 = comparator.fieldName2; |
| 1177 var ascending1 = comparator.ascending1; |
| 1178 var ascending2 = comparator.ascending2; |
| 1179 |
| 1180 var nodeA = new WebInspector.HeapSnapshotNode(this.snapshot); |
| 1181 var nodeB = new WebInspector.HeapSnapshotNode(this.snapshot); |
| 1182 |
| 1183 function sortByNodeField(fieldName, ascending, indexA, indexB) |
| 1184 { |
| 1185 nodeA.nodeIndex = indexA; |
| 1186 nodeB.nodeIndex = indexB; |
| 1187 var valueA = nodeA[fieldName]; |
| 1188 var valueB = nodeB[fieldName]; |
| 1189 var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0); |
| 1190 return ascending ? result : -result; |
| 1191 } |
| 1192 |
| 1193 if (!this._iterationOrder) |
| 1194 this._createIterationOrder(); |
| 1195 |
| 1196 function sortByComparator(indexA, indexB) { |
| 1197 var result = sortByNodeField(fieldName1, ascending1, indexA, indexB); |
| 1198 if (result === 0) |
| 1199 result = sortByNodeField(fieldName2, ascending2, indexA, indexB); |
| 1200 return result; |
| 1201 } |
| 1202 |
| 1203 this._iterationOrder.sort(sortByComparator); |
| 1204 return true; |
| 1205 } |
| 1206 }; |
| 1207 |
| 1208 WebInspector.HeapSnapshotNodesProvider.prototype.__proto__ = WebInspector.HeapSn
apshotFilteredOrderedIterator.prototype; |
| 1209 |
| 1210 WebInspector.HeapSnapshotPathFinder = function(snapshot, targetNodeIndex, skipHi
dden) |
| 1211 { |
| 1212 this._snapshot = snapshot; |
| 1213 this._maxLength = 1; |
| 1214 this._lengthLimit = 15; |
| 1215 this._targetNodeIndex = targetNodeIndex; |
| 1216 this._currentPath = null; |
| 1217 this._skipHidden = skipHidden; |
| 1218 this._rootChildren = this._fillRootChildren(); |
| 1219 } |
| 1220 |
| 1221 WebInspector.HeapSnapshotPathFinder.prototype = { |
| 1222 findNext: function() |
| 1223 { |
| 1224 for (var i = 0; i < 100000; ++i) { |
| 1225 if (!this._buildNextPath()) { |
| 1226 if (++this._maxLength >= this._lengthLimit) |
| 1227 return null; |
| 1228 this._currentPath = null; |
| 1229 if (!this._buildNextPath()) |
| 1230 return null; |
| 1231 } |
| 1232 if (this._isPathFound()) |
| 1233 return {path:this._pathToString(this._currentPath), route:this._pathToRoute(this
._currentPath), len:this._currentPath.length}; |
| 1234 } |
| 1235 |
| 1236 return false; |
| 1237 }, |
| 1238 |
| 1239 updateRoots: function(filter) |
| 1240 { |
| 1241 if (filter) |
| 1242 filter = eval("(function(){return " + filter + "})()"); |
| 1243 this._rootChildren = this._fillRootChildren(filter); |
| 1244 this._reset(); |
| 1245 }, |
| 1246 |
| 1247 _reset: function() |
| 1248 { |
| 1249 this._maxLength = 1; |
| 1250 this._currentPath = null; |
| 1251 }, |
| 1252 |
| 1253 _fillRootChildren: function(filter) |
| 1254 { |
| 1255 var result = []; |
| 1256 for (var iter = this._snapshot.rootNode.edges; iter.hasNext(); iter.next()) { |
| 1257 if (!filter || filter(iter.edge.node)) |
| 1258 result[iter.edge.nodeIndex] = true; |
| 1259 } |
| 1260 return result; |
| 1261 }, |
| 1262 |
| 1263 _appendToCurrentPath: function(iter) |
| 1264 { |
| 1265 this._currentPath._cache[this._lastEdge.nodeIndex] = true; |
| 1266 this._currentPath.push(iter); |
| 1267 }, |
| 1268 |
| 1269 _removeLastFromCurrentPath: function() |
| 1270 { |
| 1271 this._currentPath.pop(); |
| 1272 delete this._currentPath._cache[this._lastEdge.nodeIndex]; |
| 1273 }, |
| 1274 |
| 1275 _hasInPath: function(nodeIndex) |
| 1276 { |
| 1277 return this._targetNodeIndex === nodeIndex |
| 1278 || !!this._currentPath._cache[nodeIndex]; |
| 1279 }, |
| 1280 |
| 1281 _isPathFound: function() |
| 1282 { |
| 1283 return this._currentPath.length === this._maxLength |
| 1284 && this._lastEdge.nodeIndex in this._rootChildren; |
| 1285 }, |
| 1286 |
| 1287 get _lastEdgeIter() |
| 1288 { |
| 1289 return this._currentPath[this._currentPath.length - 1]; |
| 1290 }, |
| 1291 |
| 1292 get _lastEdge() |
| 1293 { |
| 1294 return this._lastEdgeIter.item; |
| 1295 }, |
| 1296 |
| 1297 _skipEdge: function(edge) |
| 1298 { |
| 1299 return edge.isInvisible |
| 1300 || (this._skipHidden && (edge.isHidden || edge.node.isHidden)) |
| 1301 || this._hasInPath(edge.nodeIndex); |
| 1302 }, |
| 1303 |
| 1304 _nextEdgeIter: function() |
| 1305 { |
| 1306 var iter = this._lastEdgeIter; |
| 1307 while (iter.hasNext() && this._skipEdge(iter.item)) |
| 1308 iter.next(); |
| 1309 return iter; |
| 1310 }, |
| 1311 |
| 1312 _buildNextPath: function() |
| 1313 { |
| 1314 if (this._currentPath !== null) { |
| 1315 var iter = this._lastEdgeIter; |
| 1316 while (true) { |
| 1317 iter.next(); |
| 1318 iter = this._nextEdgeIter(); |
| 1319 if (iter.hasNext()) |
| 1320 return true; |
| 1321 while (true) { |
| 1322 if (this._currentPath.length > 1) { |
| 1323 this._removeLastFromCurrentPath(); |
| 1324 iter = this._lastEdgeIter; |
| 1325 iter.next(); |
| 1326 iter = this._nextEdgeIter(); |
| 1327 if (iter.hasNext()) { |
| 1328 while (this._currentPath.length < this._maxLength) { |
| 1329 iter = this._nextEdgeIter(); |
| 1330 if (iter.hasNext()) |
| 1331 this._appendToCurrentPath(iter.item.node.retainers); |
| 1332 else |
| 1333 return true; |
| 1334 } |
| 1335 return true; |
| 1336 } |
| 1337 } else |
| 1338 return false; |
| 1339 } |
| 1340 } |
| 1341 } else { |
| 1342 var node = new WebInspector.HeapSnapshotNode(this._snapshot, this._targetNodeInd
ex); |
| 1343 this._currentPath = [node.retainers]; |
| 1344 this._currentPath._cache = {}; |
| 1345 while (this._currentPath.length < this._maxLength) { |
| 1346 var iter = this._nextEdgeIter(); |
| 1347 if (iter.hasNext()) |
| 1348 this._appendToCurrentPath(iter.item.node.retainers); |
| 1349 else |
| 1350 break; |
| 1351 } |
| 1352 return true; |
| 1353 } |
| 1354 }, |
| 1355 |
| 1356 _nodeToString: function(node) |
| 1357 { |
| 1358 if (node.id === 1) |
| 1359 return node.name; |
| 1360 else |
| 1361 return node.name + "@" + node.id; |
| 1362 }, |
| 1363 |
| 1364 _pathToString: function(path) |
| 1365 { |
| 1366 if (!path) |
| 1367 return ""; |
| 1368 var sPath = []; |
| 1369 for (var j = 0; j < path.length; ++j) |
| 1370 sPath.push(path[j].item.toString()); |
| 1371 sPath.push(this._nodeToString(path[path.length - 1].item.node)); |
| 1372 sPath.reverse(); |
| 1373 return sPath.join(""); |
| 1374 }, |
| 1375 |
| 1376 _pathToRoute: function(path) |
| 1377 { |
| 1378 if (!path) |
| 1379 return []; |
| 1380 var route = []; |
| 1381 route.push(this._targetNodeIndex); |
| 1382 for (var i = 0; i < path.length; ++i) |
| 1383 route.push(path[i].item.nodeIndex); |
| 1384 route.reverse(); |
| 1385 return route; |
| 1386 } |
| 1387 }; |
| 1388 |
| 1389 WebInspector.HeapSnapshotsDiff = function(snapshot, className) |
| 1390 { |
| 1391 this._snapshot = snapshot; |
| 1392 this._className = className; |
| 1393 }; |
| 1394 |
| 1395 WebInspector.HeapSnapshotsDiff.prototype = { |
| 1396 calculate: function() |
| 1397 { |
| 1398 var aggregates = this._snapshot.aggregates(true)[this._className]; |
| 1399 var indexes = aggregates ? aggregates.idxs : []; |
| 1400 var i = 0, l = this._baseIds.length; |
| 1401 var j = 0, m = indexes.length; |
| 1402 var diff = { addedCount: 0, removedCount: 0, addedSize: 0, removedSize: 0 }; |
| 1403 |
| 1404 var nodeB = new WebInspector.HeapSnapshotNode(this._snapshot, indexes[j]); |
| 1405 while (i < l && j < m) { |
| 1406 var nodeAId = this._baseIds[i]; |
| 1407 if (nodeAId < nodeB.id) { |
| 1408 diff.removedCount++; |
| 1409 diff.removedSize += this._baseSelfSizes[i]; |
| 1410 ++i; |
| 1411 } else if (nodeAId > nodeB.id) { |
| 1412 diff.addedCount++; |
| 1413 diff.addedSize += nodeB.selfSize; |
| 1414 nodeB.nodeIndex = indexes[++j]; |
| 1415 } else { |
| 1416 ++i; |
| 1417 nodeB.nodeIndex = indexes[++j]; |
| 1418 } |
| 1419 } |
| 1420 while (i < l) { |
| 1421 diff.removedCount++; |
| 1422 diff.removedSize += this._baseSelfSizes[i]; |
| 1423 ++i; |
| 1424 } |
| 1425 while (j < m) { |
| 1426 diff.addedCount++; |
| 1427 diff.addedSize += nodeB.selfSize; |
| 1428 nodeB.nodeIndex = indexes[++j]; |
| 1429 } |
| 1430 diff.countDelta = diff.addedCount - diff.removedCount; |
| 1431 diff.sizeDelta = diff.addedSize - diff.removedSize; |
| 1432 return diff; |
| 1433 }, |
| 1434 |
| 1435 pushBaseIds: function(baseIds) |
| 1436 { |
| 1437 this._baseIds = baseIds; |
| 1438 }, |
| 1439 |
| 1440 pushBaseSelfSizes: function(baseSelfSizes) |
| 1441 { |
| 1442 this._baseSelfSizes = baseSelfSizes; |
| 1443 } |
| 1444 }; |
| 1445 ; |
| 1446 |
| 1447 |
| 1448 WebInspector.HeapSnapshotWorkerDispatcher = function(globalObject, postMessage) |
| 1449 { |
| 1450 this._objects = []; |
| 1451 this._global = globalObject; |
| 1452 this._postMessage = postMessage; |
| 1453 } |
| 1454 |
| 1455 WebInspector.HeapSnapshotWorkerDispatcher.prototype = { |
| 1456 _findFunction: function(name) |
| 1457 { |
| 1458 var path = name.split("."); |
| 1459 var result = this._global; |
| 1460 for (var i = 0; i < path.length; ++i) |
| 1461 result = result[path[i]]; |
| 1462 return result; |
| 1463 }, |
| 1464 |
| 1465 dispatchMessage: function(event) |
| 1466 { |
| 1467 var data = event.data; |
| 1468 switch (data.disposition) { |
| 1469 case "create": { |
| 1470 var constructorFunction = this._findFunction(data.methodName); |
| 1471 this._objects[data.objectId] = new constructorFunction(); |
| 1472 this._postMessage({callId: data.callId}); |
| 1473 break; |
| 1474 } |
| 1475 case "dispose": { |
| 1476 delete this._objects[data.objectId]; |
| 1477 this._postMessage({callId: data.callId}); |
| 1478 break; |
| 1479 } |
| 1480 case "getter": { |
| 1481 var object = this._objects[data.objectId]; |
| 1482 var result = object[data.methodName]; |
| 1483 this._postMessage({callId: data.callId, result: result}); |
| 1484 break; |
| 1485 } |
| 1486 case "factory": { |
| 1487 var object = this._objects[data.objectId]; |
| 1488 var result = object[data.methodName].apply(object, data.methodArguments); |
| 1489 if (result) |
| 1490 this._objects[data.newObjectId] = result; |
| 1491 this._postMessage({callId: data.callId, result: !!result}); |
| 1492 break; |
| 1493 } |
| 1494 case "method": { |
| 1495 var object = this._objects[data.objectId]; |
| 1496 var result = object[data.methodName].apply(object, data.methodArguments); |
| 1497 this._postMessage({callId: data.callId, result: result}); |
| 1498 break; |
| 1499 } |
| 1500 } |
| 1501 } |
| 1502 }; |
| 1503 ; |
| 1504 |
| 1505 function postMessageWrapper(message) |
| 1506 { |
| 1507 postMessage(message); |
| 1508 } |
| 1509 |
| 1510 var dispatcher = new WebInspector.HeapSnapshotWorkerDispatcher(this, postMessage
Wrapper); |
| 1511 addEventListener("message", dispatcher.dispatchMessage.bind(dispatcher), false); |
OLD | NEW |