<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[201183] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/201183">201183</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-05-19 14:30:55 -0700 (Thu, 19 May 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: HeapSnapshot Instances view should remove dead objects
https://bugs.webkit.org/show_bug.cgi?id=157920
&lt;rdar://problem/26375866&gt;

Patch by Joseph Pecoraro &lt;pecoraro@apple.com&gt; on 2016-05-19
Reviewed by Timothy Hatcher.

Source/WebInspectorUI:

* 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 &quot;deadCount&quot; in category data. And provide a method
to return an updated category list.

(HeapSnapshot.prototype.serializeNode):
Include a &quot;dead&quot; 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).

LayoutTests:

* inspector/unit-tests/heap-snapshot-collection-event-expected.txt: Added.
* inspector/unit-tests/heap-snapshot-collection-event.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProxiesHeapSnapshotDiffProxyjs">trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotDiffProxy.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProxiesHeapSnapshotNodeProxyjs">trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotNodeProxy.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProxiesHeapSnapshotProxyjs">trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProxiesHeapSnapshotWorkerProxyjs">trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsHeapAllocationsTimelineViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsHeapSnapshotClassDataGridNodejs">trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotClassDataGridNode.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsHeapSnapshotContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsHeapSnapshotDataGridTreejs">trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotDataGridTree.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceWorkersHeapSnapshotHeapSnapshotjs">trunk/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceWorkersHeapSnapshotHeapSnapshotWorkerjs">trunk/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsinspectorunittestsheapsnapshotcollectioneventexpectedtxt">trunk/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectorunittestsheapsnapshotcollectioneventhtml">trunk/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/LayoutTests/ChangeLog        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2016-05-19  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
+
+        Web Inspector: HeapSnapshot Instances view should remove dead objects
+        https://bugs.webkit.org/show_bug.cgi?id=157920
+        &lt;rdar://problem/26375866&gt;
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/unit-tests/heap-snapshot-collection-event-expected.txt: Added.
+        * inspector/unit-tests/heap-snapshot-collection-event.html: Added.
+
</ins><span class="cx"> 2016-05-18  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         DFG::LICMPhase shouldn't hoist type checks unless it knows that the check will succeed at the loop pre-header
</span></span></pre></div>
<a id="trunkLayoutTestsinspectorunittestsheapsnapshotcollectioneventexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event-expected.txt (0 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event-expected.txt                                (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event-expected.txt        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+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.
+
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectorunittestsheapsnapshotcollectioneventhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event.html (0 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event.html                                (rev 0)
+++ trunk/LayoutTests/inspector/unit-tests/heap-snapshot-collection-event.html        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../http/tests/inspector/resources/inspector-test.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+function triggerCreateObjects() {
+    window.list = [];
+    for (let i = 0; i &lt; 100; ++i)
+        window.list.push({key: &quot;value&quot; + i});
+}
+
+function triggerRemoveObjects() {
+    window.list = null;
+}
+
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite(&quot;HeapSnapshot.CollectionEvent&quot;);
+
+    let snapshot = null;
+
+    suite.addTestCase({
+        name: &quot;HeapSnapshot&quot;,
+        test: (resolve, reject) =&gt; {
+            InspectorTest.evaluateInPage(&quot;triggerCreateObjects()&quot;);
+            HeapAgent.snapshot((error, timestamp, snapshotStringData) =&gt; {
+                InspectorTest.expectThat(!error, &quot;Should not have an error creating a snapshot.&quot;);
+                let workerProxy = WebInspector.HeapSnapshotWorkerProxy.singleton();
+                workerProxy.createSnapshot(snapshotStringData, ({objectId, snapshot: serializedSnapshot}) =&gt; {
+                    snapshot = WebInspector.HeapSnapshotProxy.deserialize(objectId, serializedSnapshot);
+                    InspectorTest.expectThat(snapshot, &quot;Should create HeapSnapshotProxy snapshot.&quot;);
+                    resolve();
+                });
+            });
+        }
+    });
+
+    suite.addTestCase({
+        name: &quot;HeapSnapshotCollectionEvent&quot;,
+        test: (resolve, reject) =&gt; {
+            InspectorTest.evaluateInPage(&quot;triggerRemoveObjects()&quot;);
+
+            let workerProxy = WebInspector.HeapSnapshotWorkerProxy.singleton();
+            HeapAgent.snapshot((error, timestamp, snapshotStringData) =&gt; {
+                InspectorTest.expectThat(!error, &quot;Should not have an error creating a snapshot.&quot;);
+                workerProxy.createSnapshot(snapshotStringData, ({objectId, snapshot: serializedSnapshot}) =&gt; {
+                    // Ignore result. This should trigger the collection event.
+                });
+            });
+
+            workerProxy.addEventListener(&quot;HeapSnapshot.CollectionEvent&quot;, (event) =&gt; {
+                InspectorTest.pass(&quot;Received HeapSnapshot.CollectionEvent.&quot;);
+                InspectorTest.expectThat(Object.keys(event.data.collectedNodes).length &gt;= 200, &quot;Collection should include at least 200 nodes (100 objects and 100 strings).&quot;);
+                InspectorTest.expectThat(event.data.affectedSnapshots.includes(snapshot.identifier), &quot;Collection should affect the first snapshot.&quot;);
+                resolve();
+            });
+        }
+    });
+
+    suite.addTestCase({
+        name: &quot;HeapSnapshot.prototype.updateCategories&quot;,
+        test: (resolve, reject) =&gt; {
+            let categoriesBefore = snapshot.categories;
+            snapshot.updateCategories(() =&gt; {
+                let categoriesAfter = snapshot.categories;
+                InspectorTest.expectThat(categoriesBefore.get(&quot;Object&quot;).deadCount === 0, &quot;0 Objects were dead before.&quot;);
+                InspectorTest.expectThat(categoriesAfter.get(&quot;Object&quot;).deadCount &gt;= 100, &quot;At least 100 Objects are dead after.&quot;);
+                InspectorTest.expectThat(categoriesBefore.get(&quot;string&quot;).deadCount === 0, &quot;0 strings were dead before.&quot;);
+                InspectorTest.expectThat(categoriesAfter.get(&quot;string&quot;).deadCount &gt;= 100, &quot;At least 100 strings are dead after.&quot;);
+                resolve();
+            });
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+&lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=&quot;runTest()&quot;&gt;
+    &lt;p&gt;Testing HeapSnapshot CollectionEvent between snapshots.&lt;/p&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/ChangeLog        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -1,3 +1,91 @@
</span><ins>+2016-05-19  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
+
+        Web Inspector: HeapSnapshot Instances view should remove dead objects
+        https://bugs.webkit.org/show_bug.cgi?id=157920
+        &lt;rdar://problem/26375866&gt;
+
+        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 &quot;deadCount&quot; in category data. And provide a method
+        to return an updated category list.
+
+        (HeapSnapshot.prototype.serializeNode):
+        Include a &quot;dead&quot; 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).
+
</ins><span class="cx"> 2016-05-19  Timothy Hatcher  &lt;timothy@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: REGRESSION: Search magnifying glass shifted in Search tab input field
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProxiesHeapSnapshotDiffProxyjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotDiffProxy.js (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotDiffProxy.js        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotDiffProxy.js        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -62,6 +62,16 @@
</span><span class="cx">     get totalObjectCount() { return this._totalObjectCount; }
</span><span class="cx">     get categories() { return this._categories; }
</span><span class="cx"> 
</span><ins>+    updateForCollectionEvent(event)
+    {
+        if (!event.data.affectedSnapshots.includes(this._snapshot2._identifier))
+            return;
+
+        this.updateCategories(() =&gt; {
+            this.dispatchEventToListeners(WebInspector.HeapSnapshotProxy.Event.CollectedNodes, event.data);
+        });
+    }
+
</ins><span class="cx">     allocationBucketCounts(bucketSizes, callback)
</span><span class="cx">     {
</span><span class="cx">         WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, &quot;allocationBucketCounts&quot;, bucketSizes, callback);
</span><span class="lines">@@ -74,6 +84,14 @@
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    updateCategories(callback)
+    {
+        WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, &quot;updateCategories&quot;, (categories) =&gt; {
+            this._categories = Map.fromObject(categories);
+            callback();
+        });
+    }
+
</ins><span class="cx">     nodeWithIdentifier(nodeIdentifier, callback)
</span><span class="cx">     {
</span><span class="cx">         WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, &quot;nodeWithIdentifier&quot;, nodeIdentifier, (serializedNode) =&gt; {
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProxiesHeapSnapshotNodeProxyjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotNodeProxy.js (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotNodeProxy.js        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotNodeProxy.js        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -25,7 +25,7 @@
</span><span class="cx"> 
</span><span class="cx"> WebInspector.HeapSnapshotNodeProxy = class HeapSnapshotNodeProxy
</span><span class="cx"> {
</span><del>-    constructor(snapshotObjectId, identifier, className, size, retainedSize, internal, gcRoot, dominatorNodeIdentifier, hasChildren)
</del><ins>+    constructor(snapshotObjectId, identifier, className, size, retainedSize, internal, gcRoot, dead, dominatorNodeIdentifier, hasChildren)
</ins><span class="cx">     {
</span><span class="cx">         this._proxyObjectId = snapshotObjectId;
</span><span class="cx"> 
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx">         this.retainedSize = retainedSize;
</span><span class="cx">         this.internal = internal;
</span><span class="cx">         this.gcRoot = gcRoot;
</span><ins>+        this.dead = dead;
</ins><span class="cx">         this.dominatorNodeIdentifier = dominatorNodeIdentifier;
</span><span class="cx">         this.hasChildren = hasChildren;
</span><span class="cx">     }
</span><span class="lines">@@ -43,8 +44,8 @@
</span><span class="cx"> 
</span><span class="cx">     static deserialize(objectId, serializedNode)
</span><span class="cx">     {
</span><del>-        let {id, className, size, retainedSize, internal, gcRoot, dominatorNodeIdentifier, hasChildren} = serializedNode;
-        return new WebInspector.HeapSnapshotNodeProxy(objectId, id, className, size, retainedSize, internal, gcRoot, dominatorNodeIdentifier, hasChildren);
</del><ins>+        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);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Proxied
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProxiesHeapSnapshotProxyjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -55,6 +55,16 @@
</span><span class="cx">     get totalObjectCount() { return this._totalObjectCount; }
</span><span class="cx">     get categories() { return this._categories; }
</span><span class="cx"> 
</span><ins>+    updateForCollectionEvent(event)
+    {
+        if (!event.data.affectedSnapshots.includes(this._identifier))
+            return;
+
+        this.updateCategories(() =&gt; {
+            this.dispatchEventToListeners(WebInspector.HeapSnapshotProxy.Event.CollectedNodes, event.data);
+        });
+    }
+
</ins><span class="cx">     allocationBucketCounts(bucketSizes, callback)
</span><span class="cx">     {
</span><span class="cx">         WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, &quot;allocationBucketCounts&quot;, bucketSizes, callback);
</span><span class="lines">@@ -67,6 +77,14 @@
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    updateCategories(callback)
+    {
+        WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, &quot;updateCategories&quot;, (categories) =&gt; {
+            this._categories = Map.fromObject(categories);
+            callback();
+        });
+    }
+
</ins><span class="cx">     nodeWithIdentifier(nodeIdentifier, callback)
</span><span class="cx">     {
</span><span class="cx">         WebInspector.HeapSnapshotWorkerProxy.singleton().callMethod(this._proxyObjectId, &quot;nodeWithIdentifier&quot;, nodeIdentifier, (serializedNode) =&gt; {
</span><span class="lines">@@ -74,3 +92,7 @@
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> };
</span><ins>+
+WebInspector.HeapSnapshotProxy.Event = {
+    CollectedNodes: &quot;heap-snapshot-proxy-did-collect-nodes&quot;
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProxiesHeapSnapshotWorkerProxyjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -34,6 +34,8 @@
</span><span class="cx"> 
</span><span class="cx">         this._nextCallId = 1;
</span><span class="cx">         this._callbacks = new Map;
</span><ins>+
+        WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Static
</span><span class="lines">@@ -47,6 +49,11 @@
</span><span class="cx"> 
</span><span class="cx">     // Actions
</span><span class="cx"> 
</span><ins>+    clearSnapshots(callback)
+    {
+        this.performAction(&quot;clearSnapshots&quot;, callback);
+    }
+
</ins><span class="cx">     createSnapshot(snapshotStringData, callback)
</span><span class="cx">     {
</span><span class="cx">         this.performAction(&quot;createSnapshot&quot;, ...arguments);
</span><span class="lines">@@ -88,6 +95,14 @@
</span><span class="cx"> 
</span><span class="cx">     // Private
</span><span class="cx"> 
</span><ins>+    _mainResourceDidChange(event)
+    {
+        if (!event.target.isMainFrame())
+            return;
+
+        this.clearSnapshots(function(){});
+    }
+
</ins><span class="cx">     _postMessage()
</span><span class="cx">     {
</span><span class="cx">         this._heapSnapshotWorker.postMessage(...arguments);
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsHeapAllocationsTimelineViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -89,6 +89,8 @@
</span><span class="cx">         this._pendingRecords = [];
</span><span class="cx"> 
</span><span class="cx">         timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._heapAllocationsTimelineRecordAdded, this);
</span><ins>+
+        WebInspector.HeapSnapshotWorkerProxy.singleton().addEventListener(&quot;HeapSnapshot.CollectionEvent&quot;, this._heapSnapshotCollectionEvent, this);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Public
</span><span class="lines">@@ -227,6 +229,8 @@
</span><span class="cx">         this._dataGrid.closed();
</span><span class="cx"> 
</span><span class="cx">         this._contentViewContainer.closeAllContentViews();
</span><ins>+
+        WebInspector.HeapSnapshotWorkerProxy.singleton().removeEventListener(&quot;HeapSnapshot.CollectionEvent&quot;, this._heapSnapshotCollectionEvent, this);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     layout()
</span><span class="lines">@@ -269,6 +273,22 @@
</span><span class="cx">         this.needsLayout();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _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: &lt;https://webkit.org/b/157904&gt; Web Inspector: Snapshot List should show the total size and the total live size
+    }
+
</ins><span class="cx">     _snapshotListPathComponentClicked(event)
</span><span class="cx">     {
</span><span class="cx">         this.showHeapSnapshotList();
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsHeapSnapshotClassDataGridNodejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotClassDataGridNode.js (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotClassDataGridNode.js        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotClassDataGridNode.js        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -92,6 +92,43 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    removeCollectedNodes(collectedNodes)
+    {
+        let nodesToRemove = [];
+
+        this.forEachImmediateChild((dataGridNode) =&gt; {
+            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) =&gt; !(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();
+    }
+
</ins><span class="cx">     // Private
</span><span class="cx"> 
</span><span class="cx">     _populate()
</span><span class="lines">@@ -99,7 +136,8 @@
</span><span class="cx">         this.removeEventListener(&quot;populate&quot;, this._populate, this);
</span><span class="cx"> 
</span><span class="cx">         this._tree.heapSnapshot.instancesWithClassName(this._data.className, (instances) =&gt; {
</span><del>-            this._instances = instances;
</del><ins>+            // FIXME: &lt;https://webkit.org/b/157905&gt; Web Inspector: Provide a way to toggle between showing only live objects and live+dead objects
+            this._instances = instances.filter((instance) =&gt; !instance.dead);
</ins><span class="cx">             this._sortInstances();
</span><span class="cx"> 
</span><span class="cx">             // Batch.
</span><span class="lines">@@ -128,9 +166,11 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         let count = newCount - oldCount;
</span><del>-        for (let i = 0; i &lt;= count; ++i) {
-            let instance = this._instances[oldCount + i];
-            this.appendChild(new WebInspector.HeapSnapshotInstanceDataGridNode(instance, this._tree));
</del><ins>+        if (count) {
+            for (let i = 0; i &lt;= count; ++i) {
+                let instance = this._instances[oldCount + i];
+                this.appendChild(new WebInspector.HeapSnapshotInstanceDataGridNode(instance, this._tree));
+            }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (this._batched)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsHeapSnapshotContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -86,6 +86,7 @@
</span><span class="cx"> 
</span><span class="cx">     _heapSnapshotDataGridTreeDidPopulate()
</span><span class="cx">     {
</span><ins>+        this._dataGrid.removeChildren();
</ins><span class="cx">         for (let child of this._heapSnapshotDataGridTree.children)
</span><span class="cx">             this._dataGrid.appendChild(child);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsHeapSnapshotDataGridTreejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotDataGridTree.js (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotDataGridTree.js        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotDataGridTree.js        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx">         console.assert(heapSnapshot instanceof WebInspector.HeapSnapshotProxy || heapSnapshot instanceof WebInspector.HeapSnapshotDiffProxy);
</span><span class="cx"> 
</span><span class="cx">         this._heapSnapshot = heapSnapshot;
</span><ins>+        this._heapSnapshot.addEventListener(WebInspector.HeapSnapshotProxy.Event.CollectedNodes, this._heapSnapshotCollectedNodes, this);
</ins><span class="cx"> 
</span><span class="cx">         this._children = [];
</span><span class="cx">         this._sortComparator = sortComparator;
</span><span class="lines">@@ -106,6 +107,11 @@
</span><span class="cx">         this._children.splice(index, 0, node);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    removeChild(node)
+    {
+        this._children.remove(node, true);
+    }
+
</ins><span class="cx">     removeChildren()
</span><span class="cx">     {
</span><span class="cx">         this._children = [];
</span><span class="lines">@@ -160,12 +166,24 @@
</span><span class="cx">         // Implemented by subclasses.
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    removeCollectedNodes(collectedNodes)
+    {
+        // Implemented by subclasses.
+    }
+
</ins><span class="cx">     didPopulate()
</span><span class="cx">     {
</span><span class="cx">         this.sort();
</span><span class="cx"> 
</span><span class="cx">         this.dispatchEventToListeners(WebInspector.HeapSnapshotDataGridTree.Event.DidPopulate);
</span><span class="cx">     }
</span><ins>+
+    // Private
+
+    _heapSnapshotCollectedNodes(event)
+    {
+        this.removeCollectedNodes(event.data.collectedNodes);
+    }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WebInspector.HeapSnapshotDataGridTree.Event = {
</span><span class="lines">@@ -182,14 +200,33 @@
</span><span class="cx">     populateTopLevel()
</span><span class="cx">     {
</span><span class="cx">         // Populate the first level with the different non-internal classes.
</span><del>-        for (let [className, {size, retainedSize, count, internalCount}] of this.heapSnapshot.categories) {
</del><ins>+        for (let [className, {size, retainedSize, count, internalCount, deadCount}] of this.heapSnapshot.categories) {
</ins><span class="cx">             if (count === internalCount)
</span><span class="cx">                 continue;
</span><del>-            this.appendChild(new WebInspector.HeapSnapshotClassDataGridNode({className, size, retainedSize, count}, this));
</del><ins>+
+            // FIXME: &lt;https://webkit.org/b/157905&gt; 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));
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         this.didPopulate()
</span><span class="cx">     }
</span><ins>+
+    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();
+    }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WebInspector.HeapSnapshotObjectGraphDataGridTree = class HeapSnapshotInstancesDataGridTree extends WebInspector.HeapSnapshotDataGridTree
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceWorkersHeapSnapshotHeapSnapshotjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -52,7 +52,7 @@
</span><span class="cx"> 
</span><span class="cx"> // Terminology:
</span><span class="cx"> //   - `nodeIndex` is an index into the `nodes` list.
</span><del>-//   - `nodeOrdinal` is the order of the node in the `nodes` list. (nodeIndex / nodeFieldCount)
</del><ins>+//   - `nodeOrdinal` is the order of the node in the `nodes` list. (nodeIndex / nodeFieldCount).
</ins><span class="cx"> //   - `nodeIdentifier` is the node's id value. (nodes[nodeIndex + nodeIdOffset]).
</span><span class="cx"> //   - `edgeIndex` is an index into the `edges` list.
</span><span class="cx"> //
</span><span class="lines">@@ -61,8 +61,9 @@
</span><span class="cx"> //     Iterate edges by walking `edges` (edgeFieldCount) and checking if fromIdentifier is current.
</span><span class="cx"> //   - _nodeOrdinalToFirstIncomingEdge - `nodeOrdinal` to `incomingEdgeIndex` in `incomingEdges`.
</span><span class="cx"> //     Iterate edges by walking `incomingEdges` until `nodeOrdinal+1`'s first incoming edge index.
</span><del>-//   - _nodeOrdinalToDominatorNodeOrdinal - `nodeOrdinal` to `nodeOrdinal` of dominator
-//   - _nodeOrdinalToRetainedSizes - `nodeOrdinal` to retain size value
</del><ins>+//   - _nodeOrdinalToDominatorNodeOrdinal - `nodeOrdinal` to `nodeOrdinal` of dominator.
+//   - _nodeOrdinalToRetainedSizes - `nodeOrdinal` to retain size value.
+//   - _nodeOrdinalIsDead - `nodeOrdinal` is dead or alive.
</ins><span class="cx"> //
</span><span class="cx"> // Temporary Lists:
</span><span class="cx"> //   - nodeOrdinalToPostOrderIndex - `nodeOrdinal` to a `postOrderIndex`.
</span><span class="lines">@@ -96,10 +97,14 @@
</span><span class="cx"> 
</span><span class="cx">         this._totalSize = 0;
</span><span class="cx">         this._nodeIdentifierToOrdinal = new Map; // &lt;node identifier&gt; =&gt; nodeOrdinal
</span><ins>+        this._lastNodeIdentifier = 0;
</ins><span class="cx">         for (let nodeIndex = 0; nodeIndex &lt; nodes.length; nodeIndex += nodeFieldCount) {
</span><span class="cx">             let nodeOrdinal = nodeIndex / nodeFieldCount;
</span><del>-            this._nodeIdentifierToOrdinal.set(nodes[nodeIndex + nodeIdOffset], nodeOrdinal);
</del><ins>+            let nodeIdentifier = nodes[nodeIndex + nodeIdOffset];
+            this._nodeIdentifierToOrdinal.set(nodeIdentifier, nodeOrdinal);
</ins><span class="cx">             this._totalSize += nodes[nodeIndex + nodeSizeOffset];
</span><ins>+            if (nodeIdentifier &gt; this._lastNodeIdentifier)
+                this._lastNodeIdentifier = nodeIdentifier;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // FIXME: Replace toIdentifier and fromIdentifier in edges with nodeIndex to reduce hash lookups?
</span><span class="lines">@@ -125,6 +130,8 @@
</span><span class="cx"> 
</span><span class="cx">         postOrderIndexToNodeOrdinal = null;
</span><span class="cx"> 
</span><ins>+        this._nodeOrdinalIsDead = new Uint8Array(this._nodeCount);
+
</ins><span class="cx">         this._categories = HeapSnapshot.buildCategories(this);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -137,6 +144,7 @@
</span><span class="cx">         let nodes = snapshot._nodes;
</span><span class="cx">         let nodeClassNamesTable = snapshot._nodeClassNamesTable;
</span><span class="cx">         let nodeOrdinalToRetainedSizes = snapshot._nodeOrdinalToRetainedSizes;
</span><ins>+        let nodeOrdinalIsDead = snapshot._nodeOrdinalIsDead;
</ins><span class="cx"> 
</span><span class="cx">         // Skip the &lt;root&gt; node.
</span><span class="cx">         let firstNodeIndex = nodeFieldCount;
</span><span class="lines">@@ -150,16 +158,19 @@
</span><span class="cx">             let size = nodes[nodeIndex + nodeSizeOffset];
</span><span class="cx">             let retainedSize = nodeOrdinalToRetainedSizes[nodeOrdinal];
</span><span class="cx">             let internal = nodes[nodeIndex + nodeInternalOffset] ? true : false;
</span><ins>+            let dead = nodeOrdinalIsDead[nodeOrdinal] ? true : false;
</ins><span class="cx"> 
</span><span class="cx">             let category = categories[className];
</span><span class="cx">             if (!category)
</span><del>-                category = categories[className] = {className, size: 0, retainedSize: 0, count: 0, internalCount: 0};
</del><ins>+                category = categories[className] = {className, size: 0, retainedSize: 0, count: 0, internalCount: 0, deadCount: 0};
</ins><span class="cx"> 
</span><span class="cx">             category.size += size;
</span><span class="cx">             category.retainedSize += retainedSize;
</span><span class="cx">             category.count += 1;
</span><span class="cx">             if (internal)
</span><span class="cx">                 category.internalCount += 1;
</span><ins>+            if (dead)
+                category.deadCount += 1;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         return categories;
</span><span class="lines">@@ -228,6 +239,11 @@
</span><span class="cx">         return HeapSnapshot.instancesWithClassName(this, className);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    updateCategories()
+    {
+        return HeapSnapshot.buildCategories(this);
+    }
+
</ins><span class="cx">     nodeWithIdentifier(nodeIdentifier)
</span><span class="cx">     {
</span><span class="cx">         let nodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier);
</span><span class="lines">@@ -323,10 +339,60 @@
</span><span class="cx">         };
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    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 &lt; this._nodes.length; nodeIndex += nodeFieldCount) {
+            let nodeIdentifier = this._nodes[nodeIndex + nodeIdOffset];
+            if (nodeIdentifier &gt; lastNodeIdentifier)
+                continue;
+            known.set(nodeIdentifier, nodeIndex);
+        }
+
+        // Determine which node identifiers have since been deleted.
+        let collectedNodesList = [];
+        for (let nodeIndex = 0; nodeIndex &lt; 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 &lt; collectedNodesList.length; ++i)
+            collectedNodes[collectedNodesList[i]] = true;
+
+        return {
+            collectedNodes,
+            affectedSnapshots,
+        };
+    }
+
</ins><span class="cx">     // Public
</span><span class="cx"> 
</span><span class="cx">     serialize()
</span><span class="cx">     {
</span><ins>+        // FIXME: &lt;https://webkit.org/b/157904&gt; Web Inspector: Snapshot List should show the total size and the total live size
+
</ins><span class="cx">         return {
</span><span class="cx">             identifier: this._identifier,
</span><span class="cx">             title: this._title,
</span><span class="lines">@@ -356,6 +422,7 @@
</span><span class="cx">             retainedSize: this._nodeOrdinalToRetainedSizes[nodeOrdinal],
</span><span class="cx">             internal: this._nodes[nodeIndex + nodeInternalOffset] ? true : false,
</span><span class="cx">             gcRoot: this._nodeOrdinalIsGCRoot[nodeOrdinal] ? true : false,
</span><ins>+            dead: this._nodeOrdinalIsDead[nodeOrdinal] ? true : false,
</ins><span class="cx">             dominatorNodeIdentifier,
</span><span class="cx">             hasChildren,
</span><span class="cx">         };
</span><span class="lines">@@ -619,6 +686,22 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _markDeadNodes(collectedNodesList)
+    {
+        let affected = false;
+
+        for (let i = 0; i &lt; collectedNodesList.length; ++i) {
+            let nodeIdentifier = collectedNodesList[i];
+            if (nodeIdentifier &gt; this._lastNodeIdentifier)
+                continue;
+            let nodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier);
+            this._nodeOrdinalIsDead[nodeOrdinal] = 1;
+            affected = true;
+        }
+
+        return affected;
+    }
+
</ins><span class="cx">     _isNodeGlobalObject(nodeIndex)
</span><span class="cx">     {
</span><span class="cx">         let className = this._nodeClassNamesTable[this._nodes[nodeIndex + nodeClassNameOffset]];
</span><span class="lines">@@ -725,6 +808,11 @@
</span><span class="cx">         return HeapSnapshot.instancesWithClassName(this._snapshot2, className, (nodeIdentifier) =&gt; this._addedNodeIdentifiers.has(nodeIdentifier));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    updateCategories()
+    {
+        return HeapSnapshot.buildCategories(this._snapshot2, (nodeIdentifier) =&gt; this._addedNodeIdentifiers.has(nodeIdentifier));
+    }
+
</ins><span class="cx">     nodeWithIdentifier(nodeIdentifier) { return this._snapshot2.nodeWithIdentifier(nodeIdentifier); }
</span><span class="cx">     shortestGCRootPath(nodeIdentifier) { return this._snapshot2.shortestGCRootPath(nodeIdentifier); }
</span><span class="cx">     dominatedNodes(nodeIdentifier) { return this._snapshot2.dominatedNodes(nodeIdentifier); }
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceWorkersHeapSnapshotHeapSnapshotWorkerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js (201182 => 201183)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js        2016-05-19 21:25:29 UTC (rev 201182)
+++ trunk/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js        2016-05-19 21:30:55 UTC (rev 201183)
</span><span class="lines">@@ -33,17 +33,37 @@
</span><span class="cx">     {
</span><span class="cx">         this._nextObjectId = 1;
</span><span class="cx">         this._objects = new Map;
</span><ins>+        this._snapshots = [];
</ins><span class="cx"> 
</span><span class="cx">         self.addEventListener(&quot;message&quot;, this._handleMessage.bind(this));
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Actions
</span><span class="cx"> 
</span><ins>+    clearSnapshots()
+    {
+        // FIXME: &lt;https://webkit.org/b/157907&gt; Web Inspector: Snapshots should be cleared at some point
+        // this._objects.clear();
+
+        this._snapshots = [];
+    }
+
</ins><span class="cx">     createSnapshot(snapshotString, title)
</span><span class="cx">     {
</span><span class="cx">         let objectId = this._nextObjectId++;
</span><span class="cx">         let snapshot = new HeapSnapshot(objectId, snapshotString, title);
</span><ins>+        this._snapshots.push(snapshot);
</ins><span class="cx">         this._objects.set(objectId, snapshot);
</span><ins>+
+        if (this._snapshots.length &gt; 1) {
+            setTimeout(() =&gt; {
+                let collectionData = snapshot.updateDeadNodesAndGatherCollectionData(this._snapshots);
+                if (!collectionData.affectedSnapshots.length)
+                    return;
+                this.sendEvent(&quot;HeapSnapshot.CollectionEvent&quot;, collectionData);
+            }, 0);
+        }
+
</ins><span class="cx">         return {objectId, snapshot: snapshot.serialize()};
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>