blob: 5791ac1722d4b810ec70b537f27cee7e0dbf667f [file] [log] [blame]
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
WI.HeapSnapshotClassDataGridNode = class HeapSnapshotClassDataGridNode extends WI.DataGridNode
{
constructor(data, tree)
{
super(data, true);
this._data = data;
this._tree = tree;
this._batched = false;
this._instances = null;
this.addEventListener("populate", this._populate, this);
}
// Protected
get data() { return this._data; }
createCellContent(columnIdentifier)
{
if (columnIdentifier === "retainedSize") {
let size = this._data.retainedSize;
let fragment = document.createDocumentFragment();
let sizeElement = fragment.appendChild(document.createElement("span"));
sizeElement.classList.add("size");
sizeElement.textContent = Number.bytesToString(size);
let percentElement = fragment.appendChild(document.createElement("span"));
percentElement.classList.add("percentage");
percentElement.textContent = emDash;
return fragment;
}
if (columnIdentifier === "size")
return Number.bytesToString(this._data.size);
if (columnIdentifier === "className") {
const internal = false;
let {className, isObjectSubcategory} = this._data;
let fragment = document.createDocumentFragment();
let iconElement = fragment.appendChild(document.createElement("img"));
iconElement.classList.add("icon", WI.HeapSnapshotClusterContentView.iconStyleClassNameForClassName(className, internal, isObjectSubcategory));
let nameElement = fragment.appendChild(document.createElement("span"));
nameElement.classList.add("class-name");
nameElement.textContent = className;
return fragment;
}
return super.createCellContent(columnIdentifier);
}
sort()
{
if (this._batched) {
this._removeFetchMoreDataGridNode();
this._sortInstances();
this._updateBatchedChildren();
this._appendFetchMoreDataGridNode();
return;
}
let children = this.children;
children.sort(this._tree._sortComparator);
for (let i = 0; i < children.length; ++i) {
children[i]._recalculateSiblings(i);
children[i].sort();
}
}
removeCollectedNodes(collectedNodes)
{
let nodesToRemove = [];
this.forEachImmediateChild((dataGridNode) => {
if (dataGridNode instanceof WI.HeapSnapshotInstanceDataGridNode) {
let heapSnapshotNode = dataGridNode.node;
if (heapSnapshotNode.id in collectedNodes)
nodesToRemove.push(dataGridNode);
}
});
if (nodesToRemove.length) {
for (let dataGridNode of nodesToRemove)
this.removeChild(dataGridNode);
}
if (this._instances) {
this._instances = this._instances.filter((instance) => !(instance.id in collectedNodes));
this._fetchBatch(nodesToRemove.length);
}
}
updateCount(count)
{
if (count === this._data.count)
return;
if (!count) {
this._tree.removeChild(this);
return;
}
this._data.count = count;
this.needsRefresh();
}
// Private
_populate()
{
this.removeEventListener("populate", this._populate, this);
this._tree.heapSnapshot.instancesWithClassName(this._data.className, (instances) => {
// FIXME: <https://webkit.org/b/157905> Web Inspector: Provide a way to toggle between showing only live objects and live+dead objects
this._instances = instances.filter((instance) => !instance.dead);
this._sortInstances();
// Batch.
if (instances.length > WI.HeapSnapshotClassDataGridNode.ChildrenBatchLimit) {
this._batched = true;
this._fetchBatch(WI.HeapSnapshotClassDataGridNode.ChildrenBatchLimit);
return;
}
for (let instance of this._instances)
this.appendChild(new WI.HeapSnapshotInstanceDataGridNode(instance, this._tree));
});
}
_fetchBatch(batchSize)
{
if (this._batched && this.children.length)
this._removeFetchMoreDataGridNode();
let oldCount = this.children.length;
let newCount = oldCount + batchSize;
if (newCount >= this._instances.length) {
newCount = this._instances.length - 1;
this._batched = false;
}
let count = newCount - oldCount;
if (count) {
for (let i = 0; i <= count; ++i) {
let instance = this._instances[oldCount + i];
this.appendChild(new WI.HeapSnapshotInstanceDataGridNode(instance, this._tree));
}
}
if (this._batched)
this._appendFetchMoreDataGridNode();
}
_sortInstances()
{
this._instances.sort((a, b) => {
let fakeDataGridNodeA = {data: a};
let fakeDataGridNodeB = {data: b};
return this._tree._sortComparator(fakeDataGridNodeA, fakeDataGridNodeB);
});
}
_updateBatchedChildren()
{
let count = this.children.length;
this.removeChildren();
for (let i = 0; i < count; ++i)
this.appendChild(new WI.HeapSnapshotInstanceDataGridNode(this._instances[i], this._tree));
}
_removeFetchMoreDataGridNode()
{
console.assert(this.children[this.children.length - 1] instanceof WI.HeapSnapshotInstanceFetchMoreDataGridNode);
this.removeChild(this.children[this.children.length - 1]);
}
_appendFetchMoreDataGridNode()
{
console.assert(!(this.children[this.children.length - 1] instanceof WI.HeapSnapshotInstanceFetchMoreDataGridNode));
let count = this.children.length;
let totalCount = this._instances.length;
let remainingCount = totalCount - count;
let batchSize = remainingCount >= WI.HeapSnapshotClassDataGridNode.ChildrenBatchLimit ? WI.HeapSnapshotClassDataGridNode.ChildrenBatchLimit : 0;
this.appendChild(new WI.HeapSnapshotInstanceFetchMoreDataGridNode(this._tree, batchSize, remainingCount, this._fetchBatch.bind(this)));
}
};
WI.HeapSnapshotClassDataGridNode.ChildrenBatchLimit = 100;