Title: [201196] branches/safari-602.1.32-branch
Revision
201196
Author
[email protected]
Date
2016-05-19 15:58:32 -0700 (Thu, 19 May 2016)

Log Message

Merge r201183. rdar://problem/26375866

Modified Paths

Added Paths

Diff

Modified: branches/safari-602.1.32-branch/LayoutTests/ChangeLog (201195 => 201196)


--- branches/safari-602.1.32-branch/LayoutTests/ChangeLog	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/LayoutTests/ChangeLog	2016-05-19 22:58:32 UTC (rev 201196)
@@ -1,5 +1,20 @@
 2016-05-19  Babak Shafiei  <[email protected]>
 
+        Merge r201183. rdar://problem/26375866
+
+    2016-05-19  Joseph Pecoraro  <[email protected]>
+
+            Web Inspector: HeapSnapshot Instances view should remove dead objects
+            https://bugs.webkit.org/show_bug.cgi?id=157920
+            <rdar://problem/26375866>
+
+            Reviewed by Timothy Hatcher.
+
+            * inspector/unit-tests/heap-snapshot-collection-event-expected.txt: Added.
+            * inspector/unit-tests/heap-snapshot-collection-event.html: Added.
+
+2016-05-19  Babak Shafiei  <[email protected]>
+
         Merge r200651. rdar://problem/26188642
 
     2016-05-10  Joseph Pecoraro  <[email protected]>

Added: branches/safari-602.1.32-branch/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event-expected.txt (0 => 201196)


--- branches/safari-602.1.32-branch/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event-expected.txt	                        (rev 0)
+++ branches/safari-602.1.32-branch/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event-expected.txt	2016-05-19 22:58:32 UTC (rev 201196)
@@ -0,0 +1,20 @@
+Testing HeapSnapshot CollectionEvent between snapshots.
+
+
+== Running test suite: HeapSnapshot.CollectionEvent
+-- Running test case: HeapSnapshot
+PASS: Should not have an error creating a snapshot.
+PASS: Should create HeapSnapshotProxy snapshot.
+
+-- Running test case: HeapSnapshotCollectionEvent
+PASS: Should not have an error creating a snapshot.
+PASS: Received HeapSnapshot.CollectionEvent.
+PASS: Collection should include at least 200 nodes (100 objects and 100 strings).
+PASS: Collection should affect the first snapshot.
+
+-- Running test case: HeapSnapshot.prototype.updateCategories
+PASS: 0 Objects were dead before.
+PASS: At least 100 Objects are dead after.
+PASS: 0 strings were dead before.
+PASS: At least 100 strings are dead after.
+

Added: branches/safari-602.1.32-branch/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event.html (0 => 201196)


--- branches/safari-602.1.32-branch/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event.html	                        (rev 0)
+++ branches/safari-602.1.32-branch/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event.html	2016-05-19 22:58:32 UTC (rev 201196)
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script>
+function triggerCreateObjects() {
+    window.list = [];
+    for (let i = 0; i < 100; ++i)
+        window.list.push({key: "value" + i});
+}
+
+function triggerRemoveObjects() {
+    window.list = null;
+}
+
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite("HeapSnapshot.CollectionEvent");
+
+    let snapshot = null;
+
+    suite.addTestCase({
+        name: "HeapSnapshot",
+        test: (resolve, reject) => {
+            InspectorTest.evaluateInPage("triggerCreateObjects()");
+            HeapAgent.snapshot((error, timestamp, snapshotStringData) => {
+                InspectorTest.expectThat(!error, "Should not have an error creating a snapshot.");
+                let workerProxy = WebInspector.HeapSnapshotWorkerProxy.singleton();
+                workerProxy.createSnapshot(snapshotStringData, ({objectId, snapshot: serializedSnapshot}) => {
+                    snapshot = WebInspector.HeapSnapshotProxy.deserialize(objectId, serializedSnapshot);
+                    InspectorTest.expectThat(snapshot, "Should create HeapSnapshotProxy snapshot.");
+                    resolve();
+                });
+            });
+        }
+    });
+
+    suite.addTestCase({
+        name: "HeapSnapshotCollectionEvent",
+        test: (resolve, reject) => {
+            InspectorTest.evaluateInPage("triggerRemoveObjects()");
+
+            let workerProxy = WebInspector.HeapSnapshotWorkerProxy.singleton();
+            HeapAgent.snapshot((error, timestamp, snapshotStringData) => {
+                InspectorTest.expectThat(!error, "Should not have an error creating a snapshot.");
+                workerProxy.createSnapshot(snapshotStringData, ({objectId, snapshot: serializedSnapshot}) => {
+                    // Ignore result. This should trigger the collection event.
+                });
+            });
+
+            workerProxy.addEventListener("HeapSnapshot.CollectionEvent", (event) => {
+                InspectorTest.pass("Received HeapSnapshot.CollectionEvent.");
+                InspectorTest.expectThat(Object.keys(event.data.collectedNodes).length >= 200, "Collection should include at least 200 nodes (100 objects and 100 strings).");
+                InspectorTest.expectThat(event.data.affectedSnapshots.includes(snapshot.identifier), "Collection should affect the first snapshot.");
+                resolve();
+            });
+        }
+    });
+
+    suite.addTestCase({
+        name: "HeapSnapshot.prototype.updateCategories",
+        test: (resolve, reject) => {
+            let categoriesBefore = snapshot.categories;
+            snapshot.updateCategories(() => {
+                let categoriesAfter = snapshot.categories;
+                InspectorTest.expectThat(categoriesBefore.get("Object").deadCount === 0, "0 Objects were dead before.");
+                InspectorTest.expectThat(categoriesAfter.get("Object").deadCount >= 100, "At least 100 Objects are dead after.");
+                InspectorTest.expectThat(categoriesBefore.get("string").deadCount === 0, "0 strings were dead before.");
+                InspectorTest.expectThat(categoriesAfter.get("string").deadCount >= 100, "At least 100 strings are dead after.");
+                resolve();
+            });
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+    <p>Testing HeapSnapshot CollectionEvent between snapshots.</p>
+</body>
+</html>

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/ChangeLog (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/ChangeLog	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/ChangeLog	2016-05-19 22:58:32 UTC (rev 201196)
@@ -1,5 +1,97 @@
 2016-05-19  Babak Shafiei  <[email protected]>
 
+        Merge r201183. rdar://problem/26375866
+
+    2016-05-19  Joseph Pecoraro  <[email protected]>
+
+            Web Inspector: HeapSnapshot Instances view should remove dead objects
+            https://bugs.webkit.org/show_bug.cgi?id=157920
+            <rdar://problem/26375866>
+
+            Reviewed by Timothy Hatcher.
+
+            * UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js:
+            (HeapSnapshotWorker):
+            (HeapSnapshotWorker.prototype.clearSnapshots):
+            (HeapSnapshotWorker.prototype.createSnapshot):
+            Preserve a list of snapshots for this page's session. When
+            new snapshots come in we can determine which nodes have died
+            and update previous snapshots. Emit a CollectionEvent
+            containing the nodes that were deleted and affected snapshots.
+
+            * UserInterface/Workers/HeapSnapshot/HeapSnapshot.js:
+            (HeapSnapshot):
+            Stash the largest node identifier.
+            Create a byte-per-node list to mark it as dead or alive.
+            All snapshots start with all live nodes.
+
+            (HeapSnapshot.prototype.updateDeadNodesAndGatherCollectionData):
+            (HeapSnapshot.prototype._markDeadNodes):
+            When we get a new snapshot we can mark dead nodes in previous
+            snapshots. Determine the nodeIdentifiers of dead nodes, and
+            mark them as dead if they existed in previous snapshots.
+
+            (HeapSnapshot.buildCategories):
+            (HeapSnapshot.prototype.updateCategories):
+            (HeapSnapshotDiff.prototype.updateCategories):
+            Include a "deadCount" in category data. And provide a method
+            to return an updated category list.
+
+            (HeapSnapshot.prototype.serializeNode):
+            Include a "dead" property on nodes when they are first fetched.
+
+            * UserInterface/Proxies/HeapSnapshotDiffProxy.js:
+            (WebInspector.HeapSnapshotDiffProxy.prototype.updateForCollectionEvent):
+            (WebInspector.HeapSnapshotDiffProxy.prototype.updateCategories):
+            * UserInterface/Proxies/HeapSnapshotNodeProxy.js:
+            (WebInspector.HeapSnapshotNodeProxy):
+            (WebInspector.HeapSnapshotNodeProxy.deserialize):
+            * UserInterface/Proxies/HeapSnapshotProxy.js:
+            (WebInspector.HeapSnapshotProxy.prototype.updateForCollectionEvent):
+            (WebInspector.HeapSnapshotProxy.prototype.updateCategories):
+            Update snapshot proxies from a collection event by updating properties
+            and dispatching an event from the model object.
+
+            * UserInterface/Proxies/HeapSnapshotWorkerProxy.js:
+            (WebInspector.HeapSnapshotWorkerProxy):
+            (WebInspector.HeapSnapshotWorkerProxy.prototype.clearSnapshots):
+            (WebInspector.HeapSnapshotWorkerProxy.prototype._mainResourceDidChange):
+            Clear the session snapshot list when the main resource changes.
+            However we can't yet clear the HeapSnapshot objects on the worker
+            because we may still have UI that interact with them.
+
+            * UserInterface/Views/HeapAllocationsTimelineView.js:
+            (WebInspector.HeapAllocationsTimelineView):
+            (WebInspector.HeapAllocationsTimelineView.prototype.closed):
+            Register and unregister for HeapSnapshot collection events.
+
+            (WebInspector.HeapAllocationsTimelineView.prototype._heapSnapshotCollectionEvent.updateHeapSnapshotForEvent):
+            (WebInspector.HeapAllocationsTimelineView.prototype._heapSnapshotCollectionEvent):
+            Update all the snapshots we know about when a collection event happens.
+
+            * UserInterface/Views/HeapSnapshotClassDataGridNode.js:
+            (WebInspector.HeapSnapshotClassDataGridNode.prototype.removeCollectedNodes):
+            (WebInspector.HeapSnapshotClassDataGridNode.prototype.updateCount):
+            (WebInspector.HeapSnapshotClassDataGridNode.prototype._populate):
+            (WebInspector.HeapSnapshotClassDataGridNode.prototype._fetchBatch):
+            * UserInterface/Views/HeapSnapshotContentView.js:
+            (WebInspector.HeapSnapshotContentView.prototype._heapSnapshotDataGridTreeDidPopulate):
+            (WebInspector.HeapSnapshotContentView):
+            * UserInterface/Views/HeapSnapshotDataGridTree.js:
+            (WebInspector.HeapSnapshotDataGridTree):
+            (WebInspector.HeapSnapshotDataGridTree.prototype.removeChild):
+            (WebInspector.HeapSnapshotDataGridTree.prototype.removeCollectedNodes):
+            (WebInspector.HeapSnapshotDataGridTree.prototype._heapSnapshotCollectedNodes):
+            (WebInspector.HeapSnapshotInstancesDataGridTree.prototype.populateTopLevel):
+            (WebInspector.HeapSnapshotInstancesDataGridTree.prototype.removeCollectedNodes):
+            (WebInspector.HeapSnapshotInstancesDataGridTree):
+            Update the Instances DataGridTree UI when a collection event happens.
+            Remove any top level InstanceDataGridNodes that may be showing for collected nodes.
+            Update the category counts on the ClassDataGridNodes.
+            Update FetchMoreDataGridNodes to have updated counts (and replace removed nodes).
+
+2016-05-19  Babak Shafiei  <[email protected]>
+
         Merge r201177. rdar://problem/26373969
 
     2016-05-19  Timothy Hatcher  <[email protected]>

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotDiffProxy.js (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotDiffProxy.js	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotDiffProxy.js	2016-05-19 22:58:32 UTC (rev 201196)
@@ -62,6 +62,16 @@
     get totalObjectCount() { return this._totalObjectCount; }
     get categories() { return this._categories; }
 
+    updateForCollectionEvent(event)
+    {
+        if (!event.data.affectedSnapshots.includes(this._snapshot2._identifier))
+            return;
+
+        this.updateCategories(() => {
+            this.dispatchEventToListeners(WebInspector.HeapSnapshotProxy.Event.CollectedNodes, event.data);
+        });
+    }
+
     allocationBucketCounts(bucketSizes, callback)
     {
         WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, "allocationBucketCounts", bucketSizes, callback);
@@ -74,6 +84,14 @@
         });
     }
 
+    updateCategories(callback)
+    {
+        WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, "updateCategories", (categories) => {
+            this._categories = Map.fromObject(categories);
+            callback();
+        });
+    }
+
     nodeWithIdentifier(nodeIdentifier, callback)
     {
         WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, "nodeWithIdentifier", nodeIdentifier, (serializedNode) => {

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotNodeProxy.js (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotNodeProxy.js	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotNodeProxy.js	2016-05-19 22:58:32 UTC (rev 201196)
@@ -25,7 +25,7 @@
 
 WebInspector.HeapSnapshotNodeProxy = class HeapSnapshotNodeProxy
 {
-    constructor(snapshotObjectId, identifier, className, size, retainedSize, internal, gcRoot, dominatorNodeIdentifier, hasChildren)
+    constructor(snapshotObjectId, identifier, className, size, retainedSize, internal, gcRoot, dead, dominatorNodeIdentifier, hasChildren)
     {
         this._proxyObjectId = snapshotObjectId;
 
@@ -35,6 +35,7 @@
         this.retainedSize = retainedSize;
         this.internal = internal;
         this.gcRoot = gcRoot;
+        this.dead = dead;
         this.dominatorNodeIdentifier = dominatorNodeIdentifier;
         this.hasChildren = hasChildren;
     }
@@ -43,8 +44,8 @@
 
     static deserialize(objectId, serializedNode)
     {
-        let {id, className, size, retainedSize, internal, gcRoot, dominatorNodeIdentifier, hasChildren} = serializedNode;
-        return new WebInspector.HeapSnapshotNodeProxy(objectId, id, className, size, retainedSize, internal, gcRoot, dominatorNodeIdentifier, hasChildren);
+        let {id, className, size, retainedSize, internal, gcRoot, dead, dominatorNodeIdentifier, hasChildren} = serializedNode;
+        return new WebInspector.HeapSnapshotNodeProxy(objectId, id, className, size, retainedSize, internal, gcRoot, dead, dominatorNodeIdentifier, hasChildren);
     }
 
     // Proxied

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js	2016-05-19 22:58:32 UTC (rev 201196)
@@ -55,6 +55,16 @@
     get totalObjectCount() { return this._totalObjectCount; }
     get categories() { return this._categories; }
 
+    updateForCollectionEvent(event)
+    {
+        if (!event.data.affectedSnapshots.includes(this._identifier))
+            return;
+
+        this.updateCategories(() => {
+            this.dispatchEventToListeners(WebInspector.HeapSnapshotProxy.Event.CollectedNodes, event.data);
+        });
+    }
+
     allocationBucketCounts(bucketSizes, callback)
     {
         WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, "allocationBucketCounts", bucketSizes, callback);
@@ -67,6 +77,14 @@
         });
     }
 
+    updateCategories(callback)
+    {
+        WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, "updateCategories", (categories) => {
+            this._categories = Map.fromObject(categories);
+            callback();
+        });
+    }
+
     nodeWithIdentifier(nodeIdentifier, callback)
     {
         WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, "nodeWithIdentifier", nodeIdentifier, (serializedNode) => {
@@ -74,3 +92,7 @@
         });
     }
 };
+
+WebInspector.HeapSnapshotProxy.Event = {
+    CollectedNodes: "heap-snapshot-proxy-did-collect-nodes"
+};

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js	2016-05-19 22:58:32 UTC (rev 201196)
@@ -34,6 +34,8 @@
 
         this._nextCallId = 1;
         this._callbacks = new Map;
+
+        WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
     }
 
     // Static
@@ -47,6 +49,11 @@
 
     // Actions
 
+    clearSnapshots(callback)
+    {
+        this.performAction("clearSnapshots", callback);
+    }
+
     createSnapshot(snapshotStringData, callback)
     {
         this.performAction("createSnapshot", ...arguments);
@@ -88,6 +95,14 @@
 
     // Private
 
+    _mainResourceDidChange(event)
+    {
+        if (!event.target.isMainFrame())
+            return;
+
+        this.clearSnapshots(function(){});
+    }
+
     _postMessage()
     {
         this._heapSnapshotWorker.postMessage(...arguments);

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js	2016-05-19 22:58:32 UTC (rev 201196)
@@ -89,6 +89,8 @@
         this._pendingRecords = [];
 
         timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._heapAllocationsTimelineRecordAdded, this);
+
+        WebInspector.HeapSnapshotWorkerProxy.singleton().addEventListener("HeapSnapshot.CollectionEvent", this._heapSnapshotCollectionEvent, this);
     }
 
     // Public
@@ -227,6 +229,8 @@
         this._dataGrid.closed();
 
         this._contentViewContainer.closeAllContentViews();
+
+        WebInspector.HeapSnapshotWorkerProxy.singleton().removeEventListener("HeapSnapshot.CollectionEvent", this._heapSnapshotCollectionEvent, this);
     }
 
     layout()
@@ -269,6 +273,22 @@
         this.needsLayout();
     }
 
+    _heapSnapshotCollectionEvent(event)
+    {
+        function updateHeapSnapshotForEvent(heapSnapshot) {
+            heapSnapshot.updateForCollectionEvent(event);
+        }
+
+        for (let node of this._dataGrid.children)
+            updateHeapSnapshotForEvent(node.record.heapSnapshot);
+        for (let record of this._pendingRecords)
+            updateHeapSnapshotForEvent(record.heapSnapshot);
+        if (this._heapSnapshotDiff)
+            updateHeapSnapshotForEvent(this._heapSnapshotDiff);
+
+        // FIXME: <https://webkit.org/b/157904> Web Inspector: Snapshot List should show the total size and the total live size
+    }
+
     _snapshotListPathComponentClicked(event)
     {
         this.showHeapSnapshotList();

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotClassDataGridNode.js (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotClassDataGridNode.js	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotClassDataGridNode.js	2016-05-19 22:58:32 UTC (rev 201196)
@@ -92,6 +92,43 @@
         }
     }
 
+    removeCollectedNodes(collectedNodes)
+    {
+        let nodesToRemove = [];
+
+        this.forEachImmediateChild((dataGridNode) => {
+            if (dataGridNode instanceof WebInspector.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()
@@ -99,7 +136,8 @@
         this.removeEventListener("populate", this._populate, this);
 
         this._tree.heapSnapshot.instancesWithClassName(this._data.className, (instances) => {
-            this._instances = 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.
@@ -128,9 +166,11 @@
         }
 
         let count = newCount - oldCount;
-        for (let i = 0; i <= count; ++i) {
-            let instance = this._instances[oldCount + i];
-            this.appendChild(new WebInspector.HeapSnapshotInstanceDataGridNode(instance, this._tree));
+        if (count) {
+            for (let i = 0; i <= count; ++i) {
+                let instance = this._instances[oldCount + i];
+                this.appendChild(new WebInspector.HeapSnapshotInstanceDataGridNode(instance, this._tree));
+            }
         }
 
         if (this._batched)

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js	2016-05-19 22:58:32 UTC (rev 201196)
@@ -86,6 +86,7 @@
 
     _heapSnapshotDataGridTreeDidPopulate()
     {
+        this._dataGrid.removeChildren();
         for (let child of this._heapSnapshotDataGridTree.children)
             this._dataGrid.appendChild(child);
     }

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotDataGridTree.js (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotDataGridTree.js	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotDataGridTree.js	2016-05-19 22:58:32 UTC (rev 201196)
@@ -32,6 +32,7 @@
         console.assert(heapSnapshot instanceof WebInspector.HeapSnapshotProxy || heapSnapshot instanceof WebInspector.HeapSnapshotDiffProxy);
 
         this._heapSnapshot = heapSnapshot;
+        this._heapSnapshot.addEventListener(WebInspector.HeapSnapshotProxy.Event.CollectedNodes, this._heapSnapshotCollectedNodes, this);
 
         this._children = [];
         this._sortComparator = sortComparator;
@@ -106,6 +107,11 @@
         this._children.splice(index, 0, node);
     }
 
+    removeChild(node)
+    {
+        this._children.remove(node, true);
+    }
+
     removeChildren()
     {
         this._children = [];
@@ -160,12 +166,24 @@
         // Implemented by subclasses.
     }
 
+    removeCollectedNodes(collectedNodes)
+    {
+        // Implemented by subclasses.
+    }
+
     didPopulate()
     {
         this.sort();
 
         this.dispatchEventToListeners(WebInspector.HeapSnapshotDataGridTree.Event.DidPopulate);
     }
+
+    // Private
+
+    _heapSnapshotCollectedNodes(event)
+    {
+        this.removeCollectedNodes(event.data.collectedNodes);
+    }
 };
 
 WebInspector.HeapSnapshotDataGridTree.Event = {
@@ -182,14 +200,33 @@
     populateTopLevel()
     {
         // Populate the first level with the different non-internal classes.
-        for (let [className, {size, retainedSize, count, internalCount}] of this.heapSnapshot.categories) {
+        for (let [className, {size, retainedSize, count, internalCount, deadCount}] of this.heapSnapshot.categories) {
             if (count === internalCount)
                 continue;
-            this.appendChild(new WebInspector.HeapSnapshotClassDataGridNode({className, size, retainedSize, count}, this));
+
+            // FIXME: <https://webkit.org/b/157905> Web Inspector: Provide a way to toggle between showing only live objects and live+dead objects
+            let liveCount = count - deadCount;
+            if (!liveCount)
+                continue;
+
+            this.appendChild(new WebInspector.HeapSnapshotClassDataGridNode({className, size, retainedSize, count: liveCount}, this));
         }
 
         this.didPopulate()
     }
+
+    removeCollectedNodes(collectedNodes)
+    {
+        for (let classDataGridNode of this.children) {
+            let {count, deadCount} = this.heapSnapshot.categories.get(classDataGridNode.data.className);
+            let liveCount = count - deadCount;
+            classDataGridNode.updateCount(liveCount);
+            if (liveCount)
+                classDataGridNode.removeCollectedNodes(collectedNodes);
+        }
+
+        this.didPopulate();
+    }
 };
 
 WebInspector.HeapSnapshotObjectGraphDataGridTree = class HeapSnapshotInstancesDataGridTree extends WebInspector.HeapSnapshotDataGridTree

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js	2016-05-19 22:58:32 UTC (rev 201196)
@@ -52,7 +52,7 @@
 
 // Terminology:
 //   - `nodeIndex` is an index into the `nodes` list.
-//   - `nodeOrdinal` is the order of the node in the `nodes` list. (nodeIndex / nodeFieldCount)
+//   - `nodeOrdinal` is the order of the node in the `nodes` list. (nodeIndex / nodeFieldCount).
 //   - `nodeIdentifier` is the node's id value. (nodes[nodeIndex + nodeIdOffset]).
 //   - `edgeIndex` is an index into the `edges` list.
 //
@@ -61,8 +61,9 @@
 //     Iterate edges by walking `edges` (edgeFieldCount) and checking if fromIdentifier is current.
 //   - _nodeOrdinalToFirstIncomingEdge - `nodeOrdinal` to `incomingEdgeIndex` in `incomingEdges`.
 //     Iterate edges by walking `incomingEdges` until `nodeOrdinal+1`'s first incoming edge index.
-//   - _nodeOrdinalToDominatorNodeOrdinal - `nodeOrdinal` to `nodeOrdinal` of dominator
-//   - _nodeOrdinalToRetainedSizes - `nodeOrdinal` to retain size value
+//   - _nodeOrdinalToDominatorNodeOrdinal - `nodeOrdinal` to `nodeOrdinal` of dominator.
+//   - _nodeOrdinalToRetainedSizes - `nodeOrdinal` to retain size value.
+//   - _nodeOrdinalIsDead - `nodeOrdinal` is dead or alive.
 //
 // Temporary Lists:
 //   - nodeOrdinalToPostOrderIndex - `nodeOrdinal` to a `postOrderIndex`.
@@ -96,10 +97,14 @@
 
         this._totalSize = 0;
         this._nodeIdentifierToOrdinal = new Map; // <node identifier> => nodeOrdinal
+        this._lastNodeIdentifier = 0;
         for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) {
             let nodeOrdinal = nodeIndex / nodeFieldCount;
-            this._nodeIdentifierToOrdinal.set(nodes[nodeIndex + nodeIdOffset], nodeOrdinal);
+            let nodeIdentifier = nodes[nodeIndex + nodeIdOffset];
+            this._nodeIdentifierToOrdinal.set(nodeIdentifier, nodeOrdinal);
             this._totalSize += nodes[nodeIndex + nodeSizeOffset];
+            if (nodeIdentifier > this._lastNodeIdentifier)
+                this._lastNodeIdentifier = nodeIdentifier;
         }
 
         // FIXME: Replace toIdentifier and fromIdentifier in edges with nodeIndex to reduce hash lookups?
@@ -125,6 +130,8 @@
 
         postOrderIndexToNodeOrdinal = null;
 
+        this._nodeOrdinalIsDead = new Uint8Array(this._nodeCount);
+
         this._categories = HeapSnapshot.buildCategories(this);
     }
 
@@ -137,6 +144,7 @@
         let nodes = snapshot._nodes;
         let nodeClassNamesTable = snapshot._nodeClassNamesTable;
         let nodeOrdinalToRetainedSizes = snapshot._nodeOrdinalToRetainedSizes;
+        let nodeOrdinalIsDead = snapshot._nodeOrdinalIsDead;
 
         // Skip the <root> node.
         let firstNodeIndex = nodeFieldCount;
@@ -150,16 +158,19 @@
             let size = nodes[nodeIndex + nodeSizeOffset];
             let retainedSize = nodeOrdinalToRetainedSizes[nodeOrdinal];
             let internal = nodes[nodeIndex + nodeInternalOffset] ? true : false;
+            let dead = nodeOrdinalIsDead[nodeOrdinal] ? true : false;
 
             let category = categories[className];
             if (!category)
-                category = categories[className] = {className, size: 0, retainedSize: 0, count: 0, internalCount: 0};
+                category = categories[className] = {className, size: 0, retainedSize: 0, count: 0, internalCount: 0, deadCount: 0};
 
             category.size += size;
             category.retainedSize += retainedSize;
             category.count += 1;
             if (internal)
                 category.internalCount += 1;
+            if (dead)
+                category.deadCount += 1;
         }
 
         return categories;
@@ -228,6 +239,11 @@
         return HeapSnapshot.instancesWithClassName(this, className);
     }
 
+    updateCategories()
+    {
+        return HeapSnapshot.buildCategories(this);
+    }
+
     nodeWithIdentifier(nodeIdentifier)
     {
         let nodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier);
@@ -323,10 +339,60 @@
         };
     }
 
+    updateDeadNodesAndGatherCollectionData(snapshots)
+    {
+        let previousSnapshotIndex = snapshots.indexOf(this) - 1;
+        let previousSnapshot = snapshots[previousSnapshotIndex];
+        console.assert(previousSnapshot instanceof HeapSnapshot);
+        if (!previousSnapshot)
+            return;
+
+        let lastNodeIdentifier = previousSnapshot._lastNodeIdentifier;
+
+        // All of the node identifiers that could have existed prior to this snapshot.
+        let known = new Map;
+        for (let nodeIndex = 0; nodeIndex < this._nodes.length; nodeIndex += nodeFieldCount) {
+            let nodeIdentifier = this._nodes[nodeIndex + nodeIdOffset];
+            if (nodeIdentifier > lastNodeIdentifier)
+                continue;
+            known.set(nodeIdentifier, nodeIndex);
+        }
+
+        // Determine which node identifiers have since been deleted.
+        let collectedNodesList = [];
+        for (let nodeIndex = 0; nodeIndex < previousSnapshot._nodes.length; nodeIndex += nodeFieldCount) {
+            let nodeIdentifier = previousSnapshot._nodes[nodeIndex + nodeIdOffset];
+            let wasDeleted = !known.has(nodeIdentifier);
+            if (wasDeleted)
+                collectedNodesList.push(nodeIdentifier);
+        }
+
+        // Update dead nodes in previous snapshots.
+        let affectedSnapshots = [];
+        for (let snapshot of snapshots) {
+            if (snapshot === this)
+                break;
+            if (snapshot._markDeadNodes(collectedNodesList))
+                affectedSnapshots.push(snapshot._identifier);
+        }
+
+        // Convert list to a map.
+        let collectedNodes = {};
+        for (let i = 0; i < collectedNodesList.length; ++i)
+            collectedNodes[collectedNodesList[i]] = true;
+
+        return {
+            collectedNodes,
+            affectedSnapshots,
+        };
+    }
+
     // Public
 
     serialize()
     {
+        // FIXME: <https://webkit.org/b/157904> Web Inspector: Snapshot List should show the total size and the total live size
+
         return {
             identifier: this._identifier,
             title: this._title,
@@ -356,6 +422,7 @@
             retainedSize: this._nodeOrdinalToRetainedSizes[nodeOrdinal],
             internal: this._nodes[nodeIndex + nodeInternalOffset] ? true : false,
             gcRoot: this._nodeOrdinalIsGCRoot[nodeOrdinal] ? true : false,
+            dead: this._nodeOrdinalIsDead[nodeOrdinal] ? true : false,
             dominatorNodeIdentifier,
             hasChildren,
         };
@@ -619,6 +686,22 @@
         }
     }
 
+    _markDeadNodes(collectedNodesList)
+    {
+        let affected = false;
+
+        for (let i = 0; i < collectedNodesList.length; ++i) {
+            let nodeIdentifier = collectedNodesList[i];
+            if (nodeIdentifier > this._lastNodeIdentifier)
+                continue;
+            let nodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier);
+            this._nodeOrdinalIsDead[nodeOrdinal] = 1;
+            affected = true;
+        }
+
+        return affected;
+    }
+
     _isNodeGlobalObject(nodeIndex)
     {
         let className = this._nodeClassNamesTable[this._nodes[nodeIndex + nodeClassNameOffset]];
@@ -725,6 +808,11 @@
         return HeapSnapshot.instancesWithClassName(this._snapshot2, className, (nodeIdentifier) => this._addedNodeIdentifiers.has(nodeIdentifier));
     }
 
+    updateCategories()
+    {
+        return HeapSnapshot.buildCategories(this._snapshot2, (nodeIdentifier) => this._addedNodeIdentifiers.has(nodeIdentifier));
+    }
+
     nodeWithIdentifier(nodeIdentifier) { return this._snapshot2.nodeWithIdentifier(nodeIdentifier); }
     shortestGCRootPath(nodeIdentifier) { return this._snapshot2.shortestGCRootPath(nodeIdentifier); }
     dominatedNodes(nodeIdentifier) { return this._snapshot2.dominatedNodes(nodeIdentifier); }

Modified: branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js (201195 => 201196)


--- branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js	2016-05-19 22:58:13 UTC (rev 201195)
+++ branches/safari-602.1.32-branch/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js	2016-05-19 22:58:32 UTC (rev 201196)
@@ -33,17 +33,37 @@
     {
         this._nextObjectId = 1;
         this._objects = new Map;
+        this._snapshots = [];
 
         self.addEventListener("message", this._handleMessage.bind(this));
     }
 
     // Actions
 
+    clearSnapshots()
+    {
+        // FIXME: <https://webkit.org/b/157907> Web Inspector: Snapshots should be cleared at some point
+        // this._objects.clear();
+
+        this._snapshots = [];
+    }
+
     createSnapshot(snapshotString, title)
     {
         let objectId = this._nextObjectId++;
         let snapshot = new HeapSnapshot(objectId, snapshotString, title);
+        this._snapshots.push(snapshot);
         this._objects.set(objectId, snapshot);
+
+        if (this._snapshots.length > 1) {
+            setTimeout(() => {
+                let collectionData = snapshot.updateDeadNodesAndGatherCollectionData(this._snapshots);
+                if (!collectionData.affectedSnapshots.length)
+                    return;
+                this.sendEvent("HeapSnapshot.CollectionEvent", collectionData);
+            }, 0);
+        }
+
         return {objectId, snapshot: snapshot.serialize()};
     }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to