<!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>[196193] 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/196193">196193</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2016-02-05 15:25:23 -0800 (Fri, 05 Feb 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: Include SamplingProfiler's expression-level data for stack frames in the protocol
https://bugs.webkit.org/show_bug.cgi?id=153455
&lt;rdar://problem/24335884&gt;

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

We now send the sampling profiler's expression-level
line/column info in the inspector protocol.

* inspector/agents/InspectorScriptProfilerAgent.cpp:
(Inspector::buildSamples):
* inspector/protocol/ScriptProfiler.json:
* runtime/SamplingProfiler.h:
(JSC::SamplingProfiler::StackFrame::hasExpressionInfo):

Source/WebInspectorUI:

JSC has been collecting expression-level data in the sampling
profiler, and with this patch, we now get that information
in the inspector. With this information, we probably have
all the data we need to make real heat maps.

* UserInterface/Models/CallingContextTree.js:
(WebInspector.CallingContextTree.prototype.updateTreeWithStackTrace):
(WebInspector.CCTNode):
(WebInspector.CCTNode.prototype.findOrMakeChild):
(WebInspector.CCTNode.prototype.addTimestampAndExpressionLocation):
(WebInspector.CCTNode.prototype.addTimestamp): Deleted.

LayoutTests:

* inspector/sampling-profiler/expression-location-info-expected.txt: Added.
* inspector/sampling-profiler/expression-location-info.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectoragentsInspectorScriptProfilerAgentcpp">trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectorprotocolScriptProfilerjson">trunk/Source/JavaScriptCore/inspector/protocol/ScriptProfiler.json</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeSamplingProfilerh">trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h</a></li>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsCallingContextTreejs">trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsinspectorsamplingprofilerexpressionlocationinfoexpectedtxt">trunk/LayoutTests/inspector/sampling-profiler/expression-location-info-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectorsamplingprofilerexpressionlocationinfohtml">trunk/LayoutTests/inspector/sampling-profiler/expression-location-info.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (196192 => 196193)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-02-05 23:16:42 UTC (rev 196192)
+++ trunk/LayoutTests/ChangeLog        2016-02-05 23:25:23 UTC (rev 196193)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2016-02-05  Saam barati  &lt;sbarati@apple.com&gt;
+
+        Web Inspector: Include SamplingProfiler's expression-level data for stack frames in the protocol
+        https://bugs.webkit.org/show_bug.cgi?id=153455
+        &lt;rdar://problem/24335884&gt;
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/sampling-profiler/expression-location-info-expected.txt: Added.
+        * inspector/sampling-profiler/expression-location-info.html: Added.
+
</ins><span class="cx"> 2016-02-05  Nan Wang  &lt;n_wang@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         AX: WebKit hanging when VoiceOver attempts to focus in on page
</span></span></pre></div>
<a id="trunkLayoutTestsinspectorsamplingprofilerexpressionlocationinfoexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/sampling-profiler/expression-location-info-expected.txt (0 => 196193)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/sampling-profiler/expression-location-info-expected.txt                                (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/expression-location-info-expected.txt        2016-02-05 23:25:23 UTC (rev 196193)
</span><span class="lines">@@ -0,0 +1,6 @@
</span><ins>+
+== Running test suite: ScriptProfiler.Samples.ExpressionLocation
+-- Running test case: Sampling Profiler Expression Location
+PASS: Should have seen line 19, column 14.
+PASS: Should have seen line 25, column 14.
+
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectorsamplingprofilerexpressionlocationinfohtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector/sampling-profiler/expression-location-info.html (0 => 196193)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/sampling-profiler/expression-location-info.html                                (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/expression-location-info.html        2016-02-05 23:25:23 UTC (rev 196193)
</span><span class="lines">@@ -0,0 +1,73 @@
</span><ins>+&lt;!doctype html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../http/tests/inspector/resources/protocol-test.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+function runFor(func, millis) {
+    let start = Date.now();
+    do {
+        func();
+    } while (Date.now() - start &lt; millis);
+}
+
+function foo() {
+    {
+        let o = {};
+        for (let i = 0; i &lt; 10000; i++) {
+            o[&quot;s&quot; + i] = i; // line 19, column 14(&quot;[&quot;)
+        }
+    }
+    {
+        let o = {};
+        for (let i = 0; i &lt; 10000; i++) {
+            o[&quot;s&quot; + i] = i; // line 25, column 14(&quot;[&quot;)
+        }
+    }
+}
+noInline(foo);
+
+function test()
+{
+    let suite = ProtocolTest.createAsyncSuite(&quot;ScriptProfiler.Samples.ExpressionLocation&quot;);
+
+    suite.addTestCase({
+        name: &quot;Sampling Profiler Expression Location&quot;,
+        description: &quot;Make sure we properly collect location information.&quot;,
+        test: (resolve, reject) =&gt; {
+            InspectorProtocol.awaitEvent({event: &quot;ScriptProfiler.trackingComplete&quot;}).then((messageObject) =&gt; {
+                let tree = WebInspector.CallingContextTree.__test_makeTreeFromProtocolMessageObject(messageObject);
+                let foundLine19Column14 = false;
+                let foundLine25Column14 = false;
+                tree.forEachNode((node) =&gt; {
+                    if (node.name !== &quot;foo&quot;)
+                        return;
+
+                    for (let lineColumnHashedString of Object.getOwnPropertyNames(node._expressionLocations)) {
+                        let [lineNumber, columnNumber] = lineColumnHashedString.split(&quot;:&quot;).map(Number);
+                        if (lineNumber === 19 &amp;&amp; columnNumber === 14)
+                            foundLine19Column14 = true;
+                        if (lineNumber === 25 &amp;&amp; columnNumber === 14)
+                            foundLine25Column14 = true;
+                    }
+                });
+
+                ProtocolTest.expectThat(foundLine19Column14, &quot;Should have seen line 19, column 14.&quot;);
+                ProtocolTest.expectThat(foundLine25Column14, &quot;Should have seen line 25, column 14.&quot;);
+                resolve();
+            });
+
+            InspectorProtocol.sendCommand(&quot;ScriptProfiler.startTracking&quot;, {includeSamples: true});
+            ProtocolTest.evaluateInPage(&quot;runFor(foo, 100)&quot;);
+            InspectorProtocol.sendCommand('ScriptProfiler.stopTracking', {});
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+&lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=&quot;runTest()&quot;&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (196192 => 196193)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-02-05 23:16:42 UTC (rev 196192)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-02-05 23:25:23 UTC (rev 196193)
</span><span class="lines">@@ -1,5 +1,22 @@
</span><span class="cx"> 2016-02-05  Saam barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Web Inspector: Include SamplingProfiler's expression-level data for stack frames in the protocol
+        https://bugs.webkit.org/show_bug.cgi?id=153455
+        &lt;rdar://problem/24335884&gt;
+
+        Reviewed by Joseph Pecoraro.
+
+        We now send the sampling profiler's expression-level
+        line/column info in the inspector protocol.
+
+        * inspector/agents/InspectorScriptProfilerAgent.cpp:
+        (Inspector::buildSamples):
+        * inspector/protocol/ScriptProfiler.json:
+        * runtime/SamplingProfiler.h:
+        (JSC::SamplingProfiler::StackFrame::hasExpressionInfo):
+
+2016-02-05  Saam barati  &lt;sbarati@apple.com&gt;
+
</ins><span class="cx">         follow-up to: JSC Sampling Profiler: (host) is confusing in cases where I would expect to see JS name
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=153663
</span><span class="cx">         &lt;rdar://problem/24415092&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectoragentsInspectorScriptProfilerAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp (196192 => 196193)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp        2016-02-05 23:16:42 UTC (rev 196192)
+++ trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp        2016-02-05 23:25:23 UTC (rev 196193)
</span><span class="lines">@@ -170,6 +170,15 @@
</span><span class="cx">                 .setColumn(stackFrame.functionStartColumn())
</span><span class="cx">                 .setUrl(stackFrame.url())
</span><span class="cx">                 .release();
</span><ins>+
+            if (stackFrame.hasExpressionInfo()) {
+                Ref&lt;Protocol::ScriptProfiler::ExpressionLocation&gt; expressionLocation = Protocol::ScriptProfiler::ExpressionLocation::create()
+                    .setLine(stackFrame.lineNumber)
+                    .setColumn(stackFrame.columnNumber)
+                    .release();
+                frame-&gt;setExpressionLocation(WTFMove(expressionLocation));
+            }
+
</ins><span class="cx">             frames-&gt;addItem(WTFMove(frame));
</span><span class="cx">         }
</span><span class="cx">         Ref&lt;Protocol::ScriptProfiler::StackTrace&gt; inspectorStackTrace = Protocol::ScriptProfiler::StackTrace::create()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectorprotocolScriptProfilerjson"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/protocol/ScriptProfiler.json (196192 => 196193)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/protocol/ScriptProfiler.json        2016-02-05 23:16:42 UTC (rev 196192)
+++ trunk/Source/JavaScriptCore/inspector/protocol/ScriptProfiler.json        2016-02-05 23:25:23 UTC (rev 196193)
</span><span class="lines">@@ -17,6 +17,14 @@
</span><span class="cx">             ]
</span><span class="cx">         },
</span><span class="cx">         {
</span><ins>+            &quot;id&quot;: &quot;ExpressionLocation&quot;,
+            &quot;type&quot;: &quot;object&quot;,
+            &quot;properties&quot;: [
+                { &quot;name&quot;: &quot;line&quot;, &quot;type&quot;: &quot;integer&quot; },
+                { &quot;name&quot;: &quot;column&quot;, &quot;type&quot;: &quot;integer&quot; }
+            ]
+        },
+        {
</ins><span class="cx">             &quot;id&quot;: &quot;StackFrame&quot;,
</span><span class="cx">             &quot;type&quot;: &quot;object&quot;,
</span><span class="cx">             &quot;properties&quot;: [
</span><span class="lines">@@ -24,7 +32,8 @@
</span><span class="cx">                 { &quot;name&quot;: &quot;name&quot;, &quot;type&quot;: &quot;string&quot;, &quot;description&quot;: &quot;A displayable name for the stack frame. i.e function name, (program), etc.&quot; },
</span><span class="cx">                 { &quot;name&quot;: &quot;line&quot;, &quot;type&quot;: &quot;integer&quot; },
</span><span class="cx">                 { &quot;name&quot;: &quot;column&quot;, &quot;type&quot;: &quot;integer&quot; },
</span><del>-                { &quot;name&quot;: &quot;url&quot;, &quot;type&quot;: &quot;string&quot; }
</del><ins>+                { &quot;name&quot;: &quot;url&quot;, &quot;type&quot;: &quot;string&quot; },
+                { &quot;name&quot;: &quot;expressionLocation&quot;, &quot;$ref&quot;: &quot;ExpressionLocation&quot;, &quot;optional&quot;: true }
</ins><span class="cx">             ]
</span><span class="cx">         },
</span><span class="cx">         {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeSamplingProfilerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h (196192 => 196193)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h        2016-02-05 23:16:42 UTC (rev 196192)
+++ trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h        2016-02-05 23:25:23 UTC (rev 196193)
</span><span class="lines">@@ -84,6 +84,12 @@
</span><span class="cx">         unsigned lineNumber { std::numeric_limits&lt;unsigned&gt;::max() };
</span><span class="cx">         unsigned columnNumber { std::numeric_limits&lt;unsigned&gt;::max() };
</span><span class="cx"> 
</span><ins>+        bool hasExpressionInfo() const
+        {
+            return lineNumber != std::numeric_limits&lt;unsigned&gt;::max()
+                &amp;&amp; columnNumber != std::numeric_limits&lt;unsigned&gt;::max();
+        }
+
</ins><span class="cx">         // These are function-level data.
</span><span class="cx">         String nameFromCallee(VM&amp;);
</span><span class="cx">         String displayName(VM&amp;);
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (196192 => 196193)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2016-02-05 23:16:42 UTC (rev 196192)
+++ trunk/Source/WebInspectorUI/ChangeLog        2016-02-05 23:25:23 UTC (rev 196193)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2016-02-05  Saam barati  &lt;sbarati@apple.com&gt;
+
+        Web Inspector: Include SamplingProfiler's expression-level data for stack frames in the protocol
+        https://bugs.webkit.org/show_bug.cgi?id=153455
+        &lt;rdar://problem/24335884&gt;
+
+        Reviewed by Joseph Pecoraro.
+
+        JSC has been collecting expression-level data in the sampling
+        profiler, and with this patch, we now get that information
+        in the inspector. With this information, we probably have
+        all the data we need to make real heat maps.
+
+        * UserInterface/Models/CallingContextTree.js:
+        (WebInspector.CallingContextTree.prototype.updateTreeWithStackTrace):
+        (WebInspector.CCTNode):
+        (WebInspector.CCTNode.prototype.findOrMakeChild):
+        (WebInspector.CCTNode.prototype.addTimestampAndExpressionLocation):
+        (WebInspector.CCTNode.prototype.addTimestamp): Deleted.
+
</ins><span class="cx"> 2016-02-05  Devin Rousso  &lt;dcrousso+webkit@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Navigation bar in sidebars should always fit on a single line
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsCallingContextTreejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js (196192 => 196193)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js        2016-02-05 23:16:42 UTC (rev 196192)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js        2016-02-05 23:25:23 UTC (rev 196193)
</span><span class="lines">@@ -41,11 +41,11 @@
</span><span class="cx">     {
</span><span class="cx">         this._totalNumberOfSamples++;
</span><span class="cx">         let node = this._root;
</span><del>-        node.addTimestamp(timestamp);
</del><ins>+        node.addTimestampAndExpressionLocation(timestamp, null);
</ins><span class="cx">         for (let i = stackFrames.length; i--; ) {
</span><span class="cx">             let stackFrame = stackFrames[i];
</span><span class="cx">             node = node.findOrMakeChild(stackFrame);
</span><del>-            node.addTimestamp(timestamp);
</del><ins>+            node.addTimestampAndExpressionLocation(timestamp, stackFrame.expressionLocation || null);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -126,8 +126,10 @@
</span><span class="cx">         this._column = column;
</span><span class="cx">         this._name = name;
</span><span class="cx">         this._url = url;
</span><ins>+        this._uid = WebInspector.CCTNode.__uid++;
+
</ins><span class="cx">         this._timestamps = [];
</span><del>-        this._uid = WebInspector.CCTNode.__uid++;
</del><ins>+        this._expressionLocations = {}; // Keys are &quot;line:column&quot; strings. Values are arrays of timestamps in sorted order.
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Static and Private
</span><span class="lines">@@ -196,10 +198,23 @@
</span><span class="cx">         return node;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    addTimestamp(timestamp)
</del><ins>+    addTimestampAndExpressionLocation(timestamp, expressionLocation)
</ins><span class="cx">     {
</span><span class="cx">         console.assert(!this._timestamps.length || this._timestamps.lastValue &lt;= timestamp, &quot;Expected timestamps to be added in sorted, increasing, order.&quot;);
</span><span class="cx">         this._timestamps.push(timestamp);
</span><ins>+
+        if (!expressionLocation)
+            return;
+
+        let {line, column} = expressionLocation;    
+        let hashCons = line + &quot;:&quot; + column;
+        let timestamps = this._expressionLocations[hashCons];
+        if (!timestamps) {
+            timestamps = [];
+            this._expressionLocations[hashCons] = timestamps;
+        }
+        console.assert(!timestamps.length || timestamps.lastValue &lt;= timestamp, &quot;Expected timestamps to be added in sorted, increasing, order.&quot;);
+        timestamps.push(timestamp);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     forEachChild(callback)
</span></span></pre>
</div>
</div>

</body>
</html>