• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
31WebInspector.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
39WebInspector.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
152WebInspector.HeapSnapshotGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype;
153
154WebInspector.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
165WebInspector.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
258WebInspector.HeapSnapshotGenericObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype;
259
260WebInspector.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
269WebInspector.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
346WebInspector.HeapSnapshotObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype;
347
348WebInspector.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
356WebInspector.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
420WebInspector.HeapSnapshotInstanceNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype;
421
422WebInspector.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
432WebInspector.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
496WebInspector.HeapSnapshotConstructorNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype;
497
498WebInspector.HeapSnapshotIteratorsTuple = function(it1, it2)
499{
500    this._it1 = it1;
501    this._it2 = it2;
502}
503
504WebInspector.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
515WebInspector.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
524WebInspector.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
654WebInspector.HeapSnapshotDiffNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype;
655
656WebInspector.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
663WebInspector.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
709WebInspector.HeapSnapshotDominatorObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype;
710
711function 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